private static int SortSolutions( CircularSurface cs1 , CircularSurface cs2 )
        {
            // If cs1 is null...
            if ( cs1 == null )
            {
                // ...and cs2 is also null...
                if ( cs2 == null )
                {
                    // ...cs1 == cs2
                    return 0;
                }

                // ...and cs2 is not null...
                else
                {
                    // ...cs2 > cs1
                    return -1;
                }
            }

            // If cs1 is not null...
            else
            {
                // ...and cs2 is null...
                if ( cs2 == null )
                {
                    // ...cs1 > cs2
                    return 1;
                }

                // ...and cs2 is also not null...
                else
                {
                    // ...compare SF of surfaces
                    if ( cs1.SF > cs2.SF ) return 1;
                    else if ( cs1.SF < cs2.SF ) return -1;
                    else return 0;
                }
            }
        }
        // ------------------------------------------------------------------
        // Bishop's Method
        // ------------------------------------------------------------------
        private static double Bishop( CircularSurface slipcircle , List<Point> surface , List<List<AnalysisMeshPoint>> mesh )
        {
            double toler = 1e-5 ,
                    x0 , y0 , x1 , y1 , m , c ,
                    xc , xcSq , yc , ycSq , r , rSq ,
                    A , B , C , disc , sqrtDisc ,
                    v , w ,
                    yTop0 , yBot0 , yTop1 , yBot1 ,
                    xEnter , yEnter , xExit , yExit ,
                    meanWeight0 , meanWeight1 ,
                    bishFactor , resist , applied , prevSF , currSF , errSF;

            List<double> xEnterExit = new List<double>();
            List<double> yEnterExit = new List<double>();

            List<double> alpha = new List<double>();
            List<double> width = new List<double>();
            List<double> weight = new List<double>();
            List<double> phi = new List<double>();
            List<double> coh = new List<double>();

            // Initialize SF
            double result = 1000.0;
            int iter = 0;

            // Get circular surface parameters
            xc = slipcircle.X;
            yc = slipcircle.Y;
            r = slipcircle.R;

            xcSq = Math.Pow( xc , 2 );
            ycSq = Math.Pow( yc , 2 );
            rSq = Math.Pow( r , 2 );

            double direction = slipcircle.SoilDirection == SoilMovement.LtoR ? -1.0 : 1.0;

            // Get entry and exit points for failure surface
            for ( int i = 0 ; i < surface.Count - 1 ; i++ )
            {
                // Get coords of current surface line segment
                x0 = surface[i].X;
                y0 = surface[i].Y;
                x1 = surface[i + 1].X;
                y1 = surface[i + 1].Y;

                // If line is vertical
                if ( Math.Abs( x0 - x1 ) < toler )
                {
                    v = x0;

                    A = 1.0;
                    B = -2 * yc;
                    C = Math.Pow( v - xc , 2 ) + ycSq - rSq;

                    disc = Math.Pow( B , 2 ) - 4 * A * C;
                    if ( disc < 0 ) continue;
                    sqrtDisc = Math.Sqrt( disc );

                    w = (-B - sqrtDisc) / (2 * A);

                    if ( w >= Math.Min( y0 , y1 ) && w <= Math.Max( y0 , y1 ) )
                    {
                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }

                    w = (-B + sqrtDisc) / (2 * A);

                    if ( w >= Math.Min( y0 , y1 ) && w <= Math.Max( y0 , y1 ) )
                    {
                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }
                }
                // If line is horizontal
                else if ( Math.Abs( y0 - y1 ) < toler )
                {
                    w = y0;

                    A = 1.0;
                    B = -2 * xc;
                    C = Math.Pow( w - yc , 2 ) + xcSq - rSq;

                    disc = Math.Pow( B , 2 ) - 4 * A * C;
                    if ( disc < 0 ) continue;
                    sqrtDisc = Math.Sqrt( disc );

                    v = (-B - sqrtDisc) / (2 * A);

                    if ( v >= Math.Min( x0 , x1 ) && v <= Math.Max( x0 , x1 ) )
                    {
                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }

                    v = (-B + sqrtDisc) / (2 * A);

                    if ( v >= Math.Min( x0 , x1 ) && v <= Math.Max( x0 , x1 ) )
                    {
                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }
                }
                // Otherwise, compute slope and y-intercept
                else
                {
                    m = (y1 - y0) / (x1 - x0);
                    c = y0 - m * x0;

                    A = 1 + Math.Pow( m , 2 );
                    B = 2 * (m * (c - yc) - xc);
                    C = Math.Pow( c - yc , 2 ) + xcSq - rSq;

                    disc = Math.Pow( B , 2 ) - 4 * A * C;
                    if ( disc < 0 ) continue;
                    sqrtDisc = Math.Sqrt( disc );

                    v = (-B - sqrtDisc) / (2 * A);

                    if ( v >= Math.Min( x0 , x1 ) && v <= Math.Max( x0 , x1 ) )
                    {
                        w = m * v + c;

                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }

                    v = (-B + sqrtDisc) / (2 * A);

                    if ( v >= Math.Min( x0 , x1 ) && v <= Math.Max( x0 , x1 ) )
                    {
                        w = m * v + c;

                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }
                }
            }

            while ( xEnterExit.Count >= 2 )
            {
                // Clear entries for previous potential surface
                alpha.Clear();
                width.Clear();
                weight.Clear();
                phi.Clear();
                coh.Clear();

                // Get entry and exit coords of slip surface
                xEnter = xEnterExit[0];
                yEnter = yEnterExit[0];
                xEnterExit.RemoveAt( 0 );
                yEnterExit.RemoveAt( 0 );

                xExit = xEnterExit[0];
                yExit = yEnterExit[0];
                xEnterExit.RemoveAt( 0 );
                yEnterExit.RemoveAt( 0 );

                if ( Math.Abs( xExit - xEnter ) < mesh[1][0].X - mesh[0][0].X ) continue;

                // Advance to mesh in region of interest
                int imesh = 0;
                while ( mesh[imesh][0].X < xEnter ) imesh++;

                // Initialize x and y coords and moments
                x0 = xEnter;
                yTop0 = yEnter;
                yBot0 = yEnter;
                meanWeight0 = 0;
                applied = 0;

                // Step through mesh, getting geometry and applied moments
                double yUpper , yLower , yHeight;
                int ibase;
                while ( mesh[imesh][0].X < xExit )
                {
                    x1 = mesh[imesh][0].X;
                    yTop1 = mesh[imesh][mesh[imesh].Count - 1].Y;

                    // Compute y coord of bottom of right side of slice
                    A = 1.0;
                    B = -2 * yc;
                    C = Math.Pow( x1 - xc , 2 ) + ycSq - rSq;

                    sqrtDisc = Math.Sqrt( Math.Pow( B , 2 ) - 4 * A * C );

                    yBot1 = (-B - sqrtDisc) / (2 * A);

                    // Compute slice properties
                    alpha.Add( Math.Atan( (yBot1 - yBot0) / (x1 - x0) ) );
                    width.Add( x1 - x0 );

                    // Initialize base parameters to zero
                    phi.Add( 0 ); coh.Add( 0 );

                    ibase = phi.Count - 1;

                    meanWeight1 = 0;
                    bool begin = false;
                    for ( int imeshpt = 0 ; imeshpt < mesh[imesh].Count ; imeshpt += 2 )
                    {
                        if ( mesh[imesh][imeshpt + 1].Y < yBot1 ) continue;

                        if ( !begin )
                        {
                            /* NOTE:
                             * The angle of friction and cohesion are taken as a simple average between
                             * the current and previous slice. If the previous slice had the same as the current
                             * then the material has not changed and the result will be the same. If the previous
                             * slice had a different material, the values are taken as midway between the two
                             * slices' values. This does not account for proportion of the base of the slice
                             * occupied by each material type. For relatively thin slices, this should be
                             * accurate enough; for very wide slices it is not very accurate, but if the slices
                             * are too wide then other errors will dominate regardless.
                             */
                            if ( ibase == 0 )
                            {
                                phi[ibase] = mesh[imesh][imeshpt].Material.Phi;
                                coh[ibase] = mesh[imesh][imeshpt].Material.Cohesion;
                            }
                            else
                            {
                                phi[ibase] = 0.5 * (mesh[imesh][imeshpt].Material.Phi + phi[ibase - 1]);
                                coh[ibase] = 0.5 * (mesh[imesh][imeshpt].Material.Cohesion + coh[ibase - 1]);
                            }

                            yLower = yBot1;

                            begin = true;
                        }
                        else
                        {
                            yLower = mesh[imesh][imeshpt].Y;
                        }

                        yUpper = mesh[imesh][imeshpt + 1].Y;

                        yHeight = yUpper - yLower;

                        meanWeight1 += mesh[imesh][imeshpt].Material.Gamma * yHeight;
                    }
                    meanWeight1 /= (yTop1 - yBot1);

                    weight.Add( 0.5 * width[ibase] * (meanWeight0 * (yTop0 - yBot0) + meanWeight1 * (yTop1 - yBot1)) );

                    applied += weight[ibase] * Math.Sin( alpha[ibase] );

                    // Update right side info to new left side
                    x0 = x1;
                    yTop0 = yTop1;
                    yBot0 = yBot1;
                    meanWeight0 = meanWeight1;
                    imesh++;
                }

                // Set right side of slice to exit coords
                x1 = xExit;
                yTop1 = yBot1 = yExit;

                // Compute slice properties
                alpha.Add( Math.Atan( (yBot1 - yBot0) / (x1 - x0) ) );
                width.Add( x1 - x0 );

                // error catch for surfaces with "zero slices"
                if ( phi.Count == 0 ) continue;

                ibase = phi.Count - 1;

                phi.Add( phi[ibase] );
                coh.Add( coh[ibase] );

                weight.Add( 0.5 * width[ibase + 1] * meanWeight0 * (yTop0 - yBot0) );

                applied += weight[ibase] * Math.Sin( alpha[ibase] );

                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // TESTING PROPERTY LIST COUNTS
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                //MessageBox.Show(string.Format(
                //    "alpha count = {0}\n" +
                //    "width count = {1}\n" +
                //    "phi count = {2}\n" +
                //    "coh count = {3}\n" +
                //    "weight count = {4}\n",
                //    alpha.Count,
                //    width.Count,
                //    phi.Count,
                //    coh.Count,
                //    weight.Count), "Count Tester");

                if ( Math.Abs( applied ) > toler )
                {
                    // Compute resisting moments and safety factor
                    errSF = 1.0;
                    currSF = 1.0;
                    iter = 0;

                    while ( errSF > toler && iter++ < 100 )
                    {
                        prevSF = currSF;
                        resist = 0;

                        for ( int islice = 0 ; islice < alpha.Count ; islice++ )
                        {
                            bishFactor = Math.Cos( alpha[islice] ) + Math.Sin( alpha[islice] ) * Math.Tan( phi[islice] ) / prevSF;

                            resist += direction * (Math.Tan( phi[islice] ) * weight[islice] + coh[islice] * width[islice]) / bishFactor;
                        }

                        currSF = resist / applied;
                        errSF = Math.Abs( currSF - prevSF ) / prevSF;
                    }
                }
                else currSF = 1000.0;

                if ( iter == 100 ) currSF = 1000.0;

                // If safety factor is lowest computed for this surface
                if ( currSF > 0 && currSF < result )
                {
                    result = currSF;
                    slipcircle.XEnter = xEnter;
                    slipcircle.YEnter = yEnter;
                    slipcircle.XExit = xExit;
                    slipcircle.YExit = yExit;
                }
            }

            return result;
        }
        // ------------------------------------------------------------------
        // RFEM Analysis
        // ------------------------------------------------------------------
        private static double RFEM( CircularSurface slipcircle , List<Point> surface , List<List<AnalysisMeshPoint>> mesh )
        {
            int nnodel = 2 ,             // nodes / element
                nvar = 2 ,               // dofs / node
                nvel = nnodel * nvar ,   // dofs / element
                n ,                      // number of slices
                nnet ,                   // total system dofs
                nel ,                    // total system elements
                npts;                   // number of mapping nodes

            double soildir = slipcircle.SoilDirection == SoilMovement.RtoL ? 1.0 : -1.0;

            /*List<List<int>> ico;                            // for connectivity
            List<int> index = new List<int>(nvel);          // for mapping element to global
            List<int> nd = new List<int>(nnodel);  */
            // for element nodes

            double result , currSF , toler = 1e-5 ,
                xc , yc , r , xcSq , ycSq , rSq ,
                xEnter , yEnter , xExit , yExit ,
                direction ,
                x0 , y0 , h0 , x1 , y1 , h1 ,
                A , B , C , disc , sqrtDisc ,
                v , w , m , c;

            BandSymMatrix gstif /*, estif = new BandSymMatrix(nvel, 5)*/;    // global and element stiffness matrices
            BandSymMatrix[] gstif_chol;      // global stiffness matrix Cholesky decomposition
            DenseMatrix gload ,/* eload = new DenseMatrix(nvel, 1),*/        // global and element load vectors
                        iload , dload , dload0 ,                           // incremental and delta load vectors
                        gdisp , gdisp0 , idisp , ddisp;                    // global, incremental, delta displacement

            /*List<double> x = new List<double>(nnodel),      // slice coordinates
                         y = new List<double>(nnodel),
                         h = new List<double>(nnodel);*/

            int listcap = 200;

            List<double> xg = new List<double>( listcap ) ,           // mesh coordinates
                         yg = new List<double>( listcap ) ,
                         hg = new List<double>( listcap );

            List<double> alpha = new List<double>( listcap ) ,        // slice geometry and weight
                         width = new List<double>( listcap ) ,
                         blength = new List<double>( listcap ) ,
                         weight = new List<double>( listcap );

            List<double> K_trb = new List<double>( listcap ) ,        // wt avg base properties
                         K_nob = new List<double>( listcap ) ,
                         K_nrb = new List<double>( listcap ) ,
                         A_coefb = new List<double>( listcap ) ,
                         Phi_b = new List<double>( listcap ) ,
                         Coh_b = new List<double>( listcap );

            List<double> K_trs = new List<double>( listcap ) ,        // wt avg interslice properties
                         K_nos = new List<double>( listcap ) ,
                         K_nrs = new List<double>( listcap ) ,
                         A_coefs = new List<double>( listcap ) ,
                         Phi_s = new List<double>( listcap ) ,
                         Coh_s = new List<double>( listcap ) ,
                         Gamma_s = new List<double>( listcap );

            double acoef = 1e-5;    // RFEM constant

            List<double> xEnterExit = new List<double>( 6 );
            List<double> yEnterExit = new List<double>( 6 );

            // Initialize SF
            result = currSF = 1000.0;

            // Get circular surface parameters
            xc = slipcircle.X;
            yc = slipcircle.Y;
            r = slipcircle.R;

            xcSq = Math.Pow( xc , 2 );
            ycSq = Math.Pow( yc , 2 );
            rSq = Math.Pow( r , 2 );

            direction = slipcircle.SoilDirection == SoilMovement.LtoR ? -1.0 : 1.0;

            // Get entry and exit points for failure surface
            for ( int i = 0 ; i < surface.Count - 1 ; i++ )
            {
                // Get coords of current surface line segment
                x0 = surface[i].X;
                y0 = surface[i].Y;
                x1 = surface[i + 1].X;
                y1 = surface[i + 1].Y;

                // If line is vertical
                if ( Math.Abs( x0 - x1 ) < toler )
                {
                    v = x0;

                    A = 1.0;
                    B = -2 * yc;
                    C = Math.Pow( v - xc , 2 ) + ycSq - rSq;

                    disc = Math.Pow( B , 2 ) - 4 * A * C;
                    if ( disc < 0 ) continue;
                    sqrtDisc = Math.Sqrt( disc );

                    w = (-B - sqrtDisc) / (2 * A);

                    if ( w >= Math.Min( y0 , y1 ) && w <= Math.Max( y0 , y1 ) )
                    {
                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }

                    w = (-B + sqrtDisc) / (2 * A);

                    if ( w >= Math.Min( y0 , y1 ) && w <= Math.Max( y0 , y1 ) )
                    {
                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }
                }
                // If line is horizontal
                else if ( Math.Abs( y0 - y1 ) < toler )
                {
                    w = y0;

                    A = 1.0;
                    B = -2 * xc;
                    C = Math.Pow( w - yc , 2 ) + xcSq - rSq;

                    disc = Math.Pow( B , 2 ) - 4 * A * C;
                    if ( disc < 0 ) continue;
                    sqrtDisc = Math.Sqrt( disc );

                    v = (-B - sqrtDisc) / (2 * A);

                    if ( v >= Math.Min( x0 , x1 ) && v <= Math.Max( x0 , x1 ) )
                    {
                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }

                    v = (-B + sqrtDisc) / (2 * A);

                    if ( v >= Math.Min( x0 , x1 ) && v <= Math.Max( x0 , x1 ) )
                    {
                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }
                }
                // Otherwise, compute slope and y-intercept
                else
                {
                    m = (y1 - y0) / (x1 - x0);
                    c = y0 - m * x0;

                    A = 1 + Math.Pow( m , 2 );
                    B = 2 * (m * (c - yc) - xc);
                    C = Math.Pow( c - yc , 2 ) + xcSq - rSq;

                    disc = Math.Pow( B , 2 ) - 4 * A * C;
                    if ( disc < 0 ) continue;
                    sqrtDisc = Math.Sqrt( disc );

                    v = (-B - sqrtDisc) / (2 * A);

                    if ( v >= Math.Min( x0 , x1 ) && v <= Math.Max( x0 , x1 ) )
                    {
                        w = m * v + c;

                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }

                    v = (-B + sqrtDisc) / (2 * A);

                    if ( v >= Math.Min( x0 , x1 ) && v <= Math.Max( x0 , x1 ) )
                    {
                        w = m * v + c;

                        xEnterExit.Add( v );
                        yEnterExit.Add( w );
                    }
                }
            }

            while ( xEnterExit.Count >= 2 )
            {
                xg.Clear(); yg.Clear(); hg.Clear();

                alpha.Clear(); width.Clear(); blength.Clear(); weight.Clear();

                K_trb.Clear(); K_nob.Clear(); K_nrb.Clear(); A_coefb.Clear();
                Phi_b.Clear(); Coh_b.Clear();

                K_trs.Clear(); K_nos.Clear(); K_nrs.Clear(); A_coefs.Clear();
                Phi_s.Clear(); Coh_s.Clear(); Gamma_s.Clear();

                // Get entry and exit coords of slip surface
                xEnter = xEnterExit[0];
                yEnter = yEnterExit[0];
                xEnterExit.RemoveAt( 0 );
                yEnterExit.RemoveAt( 0 );

                xExit = xEnterExit[0];
                yExit = yEnterExit[0];
                xEnterExit.RemoveAt( 0 );
                yEnterExit.RemoveAt( 0 );

                if ( Math.Abs( xExit - xEnter ) < mesh[1][0].X - mesh[0][0].X ) continue;

                // Advance to mesh in region of interest
                int imesh = 0;
                while ( mesh[imesh][0].X < xEnter ) imesh++;

                // Initialize x and y coords of LHS
                x0 = xEnter; xg.Add( x0 );
                y0 = yEnter; yg.Add( y0 );
                h0 = yEnter; hg.Add( h0 );

                // Set first interslice parameters to zero (y0 == h0)
                K_trs.Add( 0 ); K_nos.Add( 0 ); K_nrs.Add( 0 ); A_coefs.Add( 0 );
                Phi_s.Add( 0 ); Coh_s.Add( 0 ); Gamma_s.Add( 0 );

                // Step through mesh, getting geometry
                int ibase , iface;
                while ( mesh[imesh][0].X < xExit )
                {
                    x1 = mesh[imesh][0].X;
                    h1 = mesh[imesh][mesh[imesh].Count - 1].Y;

                    // Compute y coord of bottom of right side of slice
                    A = 1.0;
                    B = -2 * yc;
                    C = Math.Pow( x1 - xc , 2 ) + ycSq - rSq;

                    sqrtDisc = Math.Sqrt( Math.Pow( B , 2 ) - 4 * A * C );

                    y1 = (-B - sqrtDisc) / (2 * A);

                    // Add slice coords to mesh coords
                    xg.Add( x1 ); yg.Add( y1 ); hg.Add( h1 );

                    // Compute slice properties
                    alpha.Add( Math.Atan( (y1 - y0) / (x1 - x0) ) );
                    width.Add( x1 - x0 );
                    blength.Add( Math.Sqrt( Math.Pow( x1 - x0 , 2 ) + Math.Pow( y1 - y0 , 2 ) ) );

                    // Initialize base parameters to zero
                    K_trb.Add( 0 ); K_nob.Add( 0 ); K_nrb.Add( 0 ); A_coefb.Add( 0 );
                    Phi_b.Add( 0 ); Coh_b.Add( 0 );

                    // Initialize interslice parameters to zero
                    K_trs.Add( 0 ); K_nos.Add( 0 ); K_nrs.Add( 0 ); A_coefs.Add( 0 );
                    Phi_s.Add( 0 ); Coh_s.Add( 0 ); Gamma_s.Add( 0 );

                    ibase = K_trb.Count - 1; iface = K_trs.Count - 1;

                    bool begin = false; double yUpper , yLower , yHeight;
                    for ( int imeshpt = 0 ; imeshpt < mesh[imesh].Count ; imeshpt += 2 )
                    {
                        if ( mesh[imesh][imeshpt + 1].Y < y1 ) continue;

                        if ( !begin )
                        {
                            /* NOTE:
                             * The angle of friction and cohesion are taken as a simple average between
                             * the current and previous slice. If the previous slice had the same as the current
                             * then the material has not changed and the result will be the same. If the previous
                             * slice had a different material, the values are taken as midway between the two
                             * slices' values. This does not account for proportion of the base of the slice
                             * occupied by each material type. For relatively thin slices, this should be
                             * accurate enough; for very wide slices it is not very accurate, but if the slices
                             * are too wide then other errors will dominate regardless.
                             */
                            if ( ibase == 0 )
                            {
                                K_trb[ibase] = mesh[imesh][imeshpt].Material.Ktrb;
                                K_nob[ibase] = mesh[imesh][imeshpt].Material.Kno;
                                K_nrb[ibase] = mesh[imesh][imeshpt].Material.Knr;
                                A_coefb[ibase] = mesh[imesh][imeshpt].Material.Acoef;

                                Phi_b[ibase] = mesh[imesh][imeshpt].Material.Phi;
                                Coh_b[ibase] = mesh[imesh][imeshpt].Material.Cohesion;
                            }
                            else
                            {
                                K_trb[ibase] = 0.5 * (mesh[imesh][imeshpt].Material.Ktrb + K_trb[ibase - 1]);
                                K_nob[ibase] = 0.5 * (mesh[imesh][imeshpt].Material.Kno + K_nob[ibase - 1]);
                                K_nrb[ibase] = 0.5 * (mesh[imesh][imeshpt].Material.Knr + K_nrb[ibase - 1]);
                                A_coefb[ibase] = 0.5 * (mesh[imesh][imeshpt].Material.Acoef + A_coefb[ibase - 1]);

                                Phi_b[ibase] = 0.5 * (mesh[imesh][imeshpt].Material.Phi + Phi_b[ibase - 1]);
                                Coh_b[ibase] = 0.5 * (mesh[imesh][imeshpt].Material.Cohesion + Coh_b[ibase - 1]);
                            }

                            yLower = y1;

                            begin = true;
                        }
                        else
                        {
                            yLower = mesh[imesh][imeshpt].Y;
                        }

                        yUpper = mesh[imesh][imeshpt + 1].Y;

                        yHeight = yUpper - yLower;

                        K_trs[iface] += mesh[imesh][imeshpt].Material.Ktrs * yHeight;
                        K_nos[iface] += mesh[imesh][imeshpt].Material.Kno * yHeight;
                        K_nrs[iface] += mesh[imesh][imeshpt].Material.Knr * yHeight;
                        A_coefs[iface] += mesh[imesh][imeshpt].Material.Acoef * yHeight;

                        Phi_s[iface] += mesh[imesh][imeshpt].Material.Phi * yHeight;
                        Coh_s[iface] += mesh[imesh][imeshpt].Material.Cohesion * yHeight;
                        Gamma_s[iface] += mesh[imesh][imeshpt].Material.Gamma * yHeight;
                    }
                    yHeight = h1 - y1;

                    K_trs[iface] /= yHeight;
                    K_nos[iface] /= yHeight;
                    K_nrs[iface] /= yHeight;
                    A_coefs[iface] /= yHeight;

                    Phi_s[iface] /= yHeight;
                    Coh_s[iface] /= yHeight;
                    Gamma_s[iface] /= yHeight;

                    weight.Add( 0.5 * width[ibase]
                        * (Gamma_s[iface] * (hg[iface] - yg[iface])
                        + Gamma_s[iface - 1] * (hg[iface - 1] - yg[iface - 1])) );

                    // Update right side info to new left side
                    x0 = x1;
                    y0 = y1;
                    h0 = h1;
                    imesh++;
                }

                // Add exit coords to mesh coords
                x1 = xExit; xg.Add( x1 );
                y1 = yExit; yg.Add( y1 );
                h1 = yExit; hg.Add( h1 );

                // Compute slice properties
                alpha.Add( Math.Atan( (y1 - y0) / (x1 - x0) ) );
                width.Add( x1 - x0 );
                blength.Add( Math.Sqrt( Math.Pow( x1 - x0 , 2 ) + Math.Pow( y1 - y0 , 2 ) ) );

                // error catch for surfaces with "zero slices"
                if ( K_trb.Count == 0 ) continue;

                ibase = K_trb.Count - 1;

                // Set base parameters to same as previous slice
                K_trb.Add( K_trb[ibase] );
                K_nob.Add( K_nob[ibase] );
                K_nrb.Add( K_nrb[ibase] );
                A_coefb.Add( A_coefb[ibase] );
                Phi_b.Add( Phi_b[ibase] );
                Coh_b.Add( Coh_b[ibase] );

                // Set final interslice parameters to zero (y0 == h0)
                K_trs.Add( 0 ); K_nos.Add( 0 ); K_nrs.Add( 0 ); A_coefs.Add( 0 );
                Phi_s.Add( 0 ); Coh_s.Add( 0 ); Gamma_s.Add( 0 );

                // Add weight of final slice
                weight.Add( 0.5 * width[ibase + 1] * Gamma_s[ibase] * (hg[ibase] - yg[ibase]) );

                // Item counts for RFEM
                n = K_trb.Count;    // # of slices
                nel = n - 1;        // # of elements
                nnet = n * nvar;    // # of system dofs
                npts = n + 1;       // # of mapping nodes

                /*
                // Create connectivity list
                ico = new List<List<int>>(nel);
                for (int i = 0; i < nel; i++)
                {
                    ico.Add(new List<int>(2));
                    ico[i].Add(i);
                    ico[i].Add(i + 1);
                }
                */

                // Initialize global stiffness matrix
                gstif = new BandSymMatrix( nnet , 5 );

                // Initialize global load vectors
                gload = new DenseMatrix( nnet );
                iload = new DenseMatrix( nnet );
                dload = new DenseMatrix( nnet );
                dload0 = new DenseMatrix( nnet );

                // Initialize global displacement vectors
                gdisp = new DenseMatrix( nnet );
                gdisp0 = new DenseMatrix( nnet );
                ddisp = new DenseMatrix( nnet );
                idisp = new DenseMatrix( nnet );

                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // TESTING PROPERTY LIST COUNTS
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                //MessageBox.Show(string.Format(
                //    "Number of slices, n = {0}\n" +
                //    "K_trb count = {1}\n" +
                //    "K_nob count = {2}\n" +
                //    "K_nrb_count = {3}\n" +
                //    "A_coefb count = {4}\n" +
                //    "Phi_b count = {5}\n" +
                //    "Coh_b count = {6}\n" +
                //    "alpha count = {7}\n" +
                //    "width count = {8}\n" +
                //    "blength count = {9}\n" +
                //    "weight count = {10}\n\n" +
                //    "Number of mesh points, npts = {11}\n" +
                //    "K_trs count = {12}\n" +
                //    "K_nos count = {13}\n" +
                //    "K_nrs count = {14}\n" +
                //    "A_coefs count = {15}\n" +
                //    "Phi_s count = {16}\n" +
                //    "Coh_s count = {17}\n" +
                //    "xg count = {18}\n" +
                //    "yg count = {19}\n" +
                //    "hg count = {20}\n\n" +
                //    "Number of elements, nel = {21}\n" +
                //    "Number of system dofs, nnet = {22}",
                //    n,
                //    K_trb.Count,
                //    K_nob.Count,
                //    K_nrb.Count,
                //    A_coefb.Count,
                //    Phi_b.Count,
                //    Coh_b.Count,
                //    alpha.Count,
                //    width.Count,
                //    blength.Count,
                //    weight.Count,
                //    npts,
                //    K_trs.Count,
                //    K_nos.Count,
                //    K_nrs.Count,
                //    A_coefs.Count,
                //    Phi_s.Count,
                //    Coh_s.Count,
                //    xg.Count,
                //    yg.Count,
                //    hg.Count,
                //    nel,
                //    nnet), "Count Tester");

                /*eload[3, 0] = 0;    // Clear values from any previous analysis
                estif[2, 3] = 0;*/

                // build up initial stiffness matrix and initial load vector
                double cos , cos2 , sin , sin2 , A1 , Ab , Kx , Ky , Kn , Kt , F;
                int gel0 , gel1 , gel2 , gel3;
                for ( int iel = 0 ; iel < nel ; iel++ )
                {
                    gel0 = iel * nvar;
                    gel1 = gel0 + 1;
                    gel2 = gel0 + 2;
                    gel3 = gel0 + 3;

                    // Compute geometry parameters (for efficiency)
                    cos = Math.Cos( alpha[iel] );
                    cos2 = Math.Pow( cos , 2 );
                    sin = Math.Sin( alpha[iel] );
                    sin2 = Math.Pow( sin , 2 );
                    A1 = hg[iel + 1] - yg[iel + 1];
                    Ab = blength[iel];

                    // Create element load vector
                    /*eload[1, 0] = -weight[iel];*/
                    gload[gel1 , 0] += -weight[iel];

                    // Compute stiffness parameters
                    Kx = A1 * K_nos[iel + 1];
                    Ky = A1 * (K_trs[iel + 1] + Coh_s[iel + 1] / acoef);

                    Kn = Ab * K_nob[iel];
                    F = Math.Max( Coh_b[iel] - (weight[iel] * cos / Ab) * Math.Tan( Phi_b[iel] ) , 0 );
                    Kt = Ab * (K_trb[iel] + F / acoef);

                    // Create element stiffness matrix
                    // (Note:   null and symmetric entries can be omitted for efficiency
                    //          due to the nature of the BandSymMatrix object)
                    //estif[0, 0] = Kx + (Kt * cos2 + Kn * sin2);
                    //estif[0, 1] = (Kt - Kn) * cos * sin;
                    //estif[0, 2] = -Kx;
                    ///* estif[0, 3] = 0; */
                    ///* estif[1, 0] = (Kt - Kn) * cos * sin; */
                    //estif[1, 1] = Ky + (Kn * cos2 + Kt * sin2);
                    ///* estif[1, 2] = 0; */
                    //estif[1, 3] = -Ky;
                    ///* estif[2, 0] = -Kx; */
                    ///* estif[2, 1] = 0; */
                    //estif[2, 2] = Kx;
                    ///* estif[2, 3] = 0; */
                    ///* estif[3, 0] = 0; */
                    ///* estif[3, 1] = -Ky; */
                    ///* estif[3, 2] = 0; */
                    //estif[3, 3] = Ky;

                    gstif[gel0 , gel0] += Kx + (Kt * cos2 + Kn * sin2);
                    gstif[gel0 , gel1] += (Kt - Kn) * cos * sin;
                    gstif[gel0 , gel2] += -Kx;
                    /* gstif[gel0, gel3] += 0; */
                    /* gstif[gel1, gel0] += (Kt - Kn) * cos * sin; */
                    gstif[gel1 , gel1] += Ky + (Kn * cos2 + Kt * sin2);
                    /* gstif[gel1, gel2] += 0; */
                    gstif[gel1 , gel3] += -Ky;
                    /* gstif[gel2, gel0] += -Kx; */
                    /* gstif[gel2, gel1] += 0; */
                    gstif[gel2 , gel2] += Kx;
                    /* gstif[gel2, gel3] += 0; */
                    /* gstif[gel3, gel0] += 0; */
                    /* gstif[gel3, gel1] += -Ky; */
                    /* gstif[gel3, gel2] += 0; */
                    gstif[gel3 , gel3] += Ky;
                }

                // Compute geometry for last slice
                cos = Math.Cos( alpha[nel] );
                cos2 = Math.Pow( cos , 2 );
                sin = Math.Sin( alpha[nel] );
                sin2 = Math.Pow( sin , 2 );
                Ab = blength[nel];

                // Add to global load vector
                gload[nnet - 1 , 0] = -weight[nel];

                // Compute stiffness properties for last slice
                Kn = Ab * K_nob[nel];
                F = Math.Max( Coh_b[nel] - (weight[nel] * cos / Ab) * Math.Tan( Phi_b[nel] ) , 0 );
                Kt = Ab * (K_trb[nel] + F / acoef);

                // Add to global stiffness matrix
                gstif[nnet - 2 , nnet - 2] += Kt * cos2 + Kn * sin2;
                gstif[nnet - 2 , nnet - 1] += (Kt - Kn) * cos * sin;
                /* gstif[nnet - 1, nnet - 2] += (Kt - Kn) * cos * sin; */
                gstif[nnet - 1 , nnet - 1] += Kn * cos2 + Kt * sin2;

                // obtain Cholesky decomposition of the (initial) global stiffness matrix
                gstif_chol = gstif.Cholesky;

                if ( gstif_chol == null ) continue;

                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                /* TESTING MATRIX SOLVER */

                //BandSymMatrix.SolveInPlaceCholesky(gstif_chol, gload, ref gdisp);

                //gstif.PrintFullToFile("C:\\Users\\Brandon\\Documents\\School\\Slope 2011\\gstif.txt");
                //gstif_chol[0].PrintFullToFile("C:\\Users\\Brandon\\Documents\\School\\Slope 2011\\gstif_chol[0].txt");
                //gstif_chol[1].PrintFullToFile("C:\\Users\\Brandon\\Documents\\School\\Slope 2011\\gstif_chol[1].txt");
                //gload.PrintToFile("C:\\Users\\Brandon\\Documents\\School\\Slope 2011\\gload.txt");
                //gdisp.PrintToFile("C:\\Users\\Brandon\\Documents\\School\\Slope 2011\\gdisp.txt");

                /* MATRIX SOLVER TESTING COMPLETE */
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                // NON-LINEAR SOLVER FOR RFEM (MODIFIED NEWTON-RAPHSON)
                double eps_s = 1e-5 , eps_a , iresid , gresid;
                int niter = 5000 , iter;
                int nstep = (int) Math.Ceiling( Math.Log( 1 / eps_s ) / Math.Log( 2 ) + 1 );
                double relax = 0.25;
                double dfact = 1.0 , fact0 = 0.0 , factor = 0.0;
                /*bool converge;*/

                for ( int istep = 0 ; istep < nstep ; istep++ )
                {
                    factor = fact0 + dfact;             // Set load scaling factor for current step
                    gdisp0.CopyInPlace( ref gdisp );      // Put current displacements and loads into
                    dload0.CopyInPlace( ref dload );      //      solver matrices

                    eps_a = 1; iter = 0; /* converge = false;*/

                    while ( eps_a > eps_s && iter < niter && factor <= 1 )
                    {
                        iter++;

                        // Determine global load vector for this iteration
                        DenseMatrix.MultiplyInPlace( factor , gload , ref iload );
                        DenseMatrix.AddInPlace( iload , dload , ref iload );

                        // --------------------------------------
                        // SOLVE THE STIFFNESS EQUATION
                        // --------------------------------------

                        // solve gstif*idisp = iload
                        BandSymMatrix.SolveInPlaceCholesky( gstif_chol , iload , ref idisp );

                        // compute update global displacements, ddisp = gdisp + idisp
                        DenseMatrix.AddInPlace( gdisp , idisp , ref ddisp );

                        // apply relaxation factor, gdisp = (1-relax)*gdisp + relax*ddisp
                        DenseMatrix.MultiplyInPlace( 1 - relax , gdisp , ref gdisp );
                        DenseMatrix.MultiplyInPlace( relax , ddisp , ref ddisp );
                        DenseMatrix.AddInPlace( gdisp , ddisp , ref gdisp );

                        // compute actual load (non-linear load-displacement curve)
                        ComputeDLoadRFEM( ref dload , gdisp ,
                                            n , /* kappa = */ 1.0 , /*acoef = */ 1e-5 ,
                                            yg , hg ,
                                            alpha , blength ,
                                            K_nob , K_nos ,
                                            K_nrb , K_nrs ,
                                            K_trb , K_trs ,
                                            A_coefb , A_coefs ,
                                            Phi_b , Phi_s ,
                                            Coh_b , Coh_s );

                        // compute approximation error
                        iresid = 0; gresid = 0;
                        for ( int i = 0 ; i < nnet ; i++ )
                        {
                            iresid += idisp[i , 0] * idisp[i , 0];
                            gresid += gdisp[i , 0] * gdisp[i , 0];
                        }
                        eps_a = Math.Sqrt( iresid / gresid );
                    }

                    /*converge = iter < niter;*/

                    // If NewtonRaphson solver converged, step forward
                    if ( iter < niter )
                    {
                        fact0 = factor;
                        gdisp.CopyInPlace( ref gdisp0 );
                        dload.CopyInPlace( ref dload0 );
                        dfact /= 2;
                        niter /= 2;
                    }
                    else        // otherwise, proceed with load reduction
                    {
                        dfact /= 2;
                    }

                    // ensure lower bound for maximum iterations
                    niter = Math.Max( niter , 200 );

                    // if converged on first run (i.e. Fs > 1), exit load stepping loop
                    if ( Math.Abs( 1 - factor ) < toler ) break;
                }

                currSF = ComputeSafetyFactorRFEM( gdisp ,
                                                    n , /* kappa = */ 1.0 , /*acoef = */ 1e-5 ,
                                                    alpha , blength ,
                                                    K_nob , K_nrb ,
                                                    K_trb , A_coefb ,
                                                    Phi_b , Coh_b );
                currSF *= soildir * factor;

                // If safety factor is lowest computed for this surface
                if ( currSF > 0 && currSF < result )
                {
                    result = currSF;
                    slipcircle.XEnter = xEnter;
                    slipcircle.YEnter = yEnter;
                    slipcircle.XExit = xExit;
                    slipcircle.YExit = yExit;
                }
            }

            //Random rand = new Random();
            //result = rand.NextDouble();

            return result;
        }