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