/// <summary> /// Генерує сітку /// </summary> public static List <double[]> generateGrid( double cellSize, out int outColumns, out int outRows, double coLatitudeBound = 0, double coLatitudeBound2 = 180, double LongitudeBoundW = 0, double LongitudeBoundE = 360, AngleType resType = AngleType.Radians ) { if (coLatitudeBound > 90 || coLatitudeBound < 0) { throw new Exception("coLatitudeBound повинна бути: 0 <= coLatitude <= 90"); } if (LongitudeBoundW >= 360 || LongitudeBoundW < 0 || LongitudeBoundE > 360 || LongitudeBoundE <= 0) { throw new Exception("LongitudeBounds must be 0<=LongitudeBound<360"); } if (LongitudeBoundW > LongitudeBoundE) { throw new Exception("West longituge bound повинна бути менша за East longituge"); } double gridRows = (180 - coLatitudeBound - (180 - coLatitudeBound2)) / cellSize; double gridColumns = (360 - LongitudeBoundW - (360 - LongitudeBoundE)) / cellSize; int addRow = 0, addCol = 0; if ((Math.Round(gridRows) - gridRows) < 0) { addRow = 1; } if ((Math.Round(gridColumns) - gridColumns) < 0) { addCol = 1; } gridColumns = (int)gridColumns + addCol; outColumns = (int)gridColumns; gridRows = (int)gridRows + addRow; outRows = (int)gridRows; int gridCells = (int)(gridColumns * gridRows); List <double[]> greed = new List <double[]>(gridCells); double coLatitudeStart = coLatitudeBound + (cellSize / 2D); double LongStart = deg2rad(LongitudeBoundW); #region ifRadians if (resType == AngleType.Radians) { MathFunc.deg2rad(ref cellSize); MathFunc.deg2rad(ref coLatitudeStart); } #endregion for (int r = 0; r < gridRows; r++) { for (int c = 0; c < gridColumns; c++) { greed.Add(new double[] { coLatitudeStart + r * cellSize, LongStart + cellSize * (0.5 + c) }); } } return(greed); }
//Зчитування даних з файлу .SGG public static double[][] read_SGG_data(string folder, MainForm.setProgressDel d) { System.IO.FileInfo fi = new FileInfo(folder); folder = fi.DirectoryName; List <string> files = new List <string>(); foreach (var file in System.IO.Directory.GetFiles(folder)) { var f = new FileInfo(file); if (f.Extension.Equals(".SGG", System.StringComparison.CurrentCultureIgnoreCase)) { files.Add(file); } ; } List <double[]> myList = new List <double[]>(getLines(files[0])); if (files.Count > 0) { foreach (string filename in files) { string[] lines = System.IO.File.ReadAllLines(filename); var x = Parallel.For(0, lines.Length, (i) => { double[] temp = null; double lat = 0; int l = 0; string[] line = null; lock (lines) { line = lines[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); } if (line.Length > 20) { lat = double.Parse(line[3]); //if (lat < 0) lat += 360; lat = MathFunc.deg2rad(lat); temp = new double[] { double.Parse(line[1]), MathFunc.deg2rad(90 - double.Parse(line[2])), lat, double.Parse(line[6]) }; if (Math.Abs(temp[1]) < Math.PI && Math.Abs(temp[2]) < 2D * Math.PI) { lock (myList) { myList.Add(temp); } } else { System.Windows.Forms.MessageBox.Show("Помилка в лінії номер " + i.ToString()); } l++; if (Math.Round(l / 20000D) == (double)l / 20000D) { d.Invoke(l / lines.Length, 1, "Обробка файлу вимірюваннь"); } ; } }); } } ; return(myList.ToArray()); }
//Запис висот геоїда і аномалій для сітки в текстовий файл public static void writeGeoidHeightsAndAnomalysToTxt(List <double[]> greed, double[] heights, double[] anomalies, ReferenceSystem rs, string file) { System.IO.TextWriter w = new System.IO.StreamWriter(file, false); for (int i = 0; i < greed.Count; i++) { w.WriteLine(string.Format("{0} {1} {2,10:0.0000} {3,10:0.0000}", MathFunc.rad2deg(MathFunc.convertThethaToB(greed[i][0], rs)), MathFunc.rad2deg(greed[i][1]), heights[i], anomalies[i])); } w.Close(); }
//Записує усереднені градієнти для кожної клітинки сітки public static void writeGreedToCsvFileWithMeasureS(List <double[]> greed, double[] data, string file) { System.IO.TextWriter tw = new System.IO.StreamWriter(file, false); int i = 0; foreach (var item in greed) { tw.WriteLine("{2:0.000};{1:0.000};{0}", data[i], MathFunc.rad2deg((Math.PI / 2D) - item[0]), MathFunc.rad2deg(item[1] - Math.PI)); i++; } tw.Flush(); tw.Close(); }
/// <summary> /// Визначає, до якої клітинки сітки відноситься кожен результат. Кожен елемент List() відповідає елементу Greed, і є масивом номерів точок з pointsData /// </summary> /// <param name="rs">Референсна система</param> /// <param name="pointsData">Масив точок типу: {radius,coLatitude,Longitude,Gradient}</param> /// <param name="greed">Масив з клітинками сітки типу: {{colat,long},{colat,long},{colat,long}...}</param> /// <param name="rowCount">Кількість рядків сітки</param> /// <param name="colsCount">Кількість стовпчиків сітки</param> /// <returns>Повертає масив з номерами точок з масиву pointsData</returns> public static List <int>[] getMappingOfPoints(ReferenceSystem rs, double[][] pointsData, double[][] greed, int rowCount, int colsCount, double avgRadius) { List <int>[] map = new List <int> [greed.Length]; for (int i = 0; i < map.Length; i++) { map[i] = new List <int>(); } double cellSize = MathFunc.deg2rad(rs.gridParameters.cellSize); double zero = greed[0][0] - cellSize / 2D; double l_zero = greed[0][1] - cellSize / 2d; Parallel.For(0, pointsData.Length, (i) => { double fi, lambda, r; lock (pointsData) { fi = pointsData[i][1]; lambda = pointsData[i][2]; r = pointsData[i][0]; } if (fi >= greed[0][0] && fi <= greed[greed.Length - 1][0] && lambda >= greed[0][1] && lambda <= greed[greed.Length - 1][1] && Math.Abs(r - avgRadius) < 10000d) { fi = fi - (zero); lambda = lambda - l_zero; int n = (int)Math.Floor(fi / cellSize); int m = (int)Math.Floor(lambda / cellSize); int index = (colsCount * n) + m; lock (map) { var x1 = cellSize / 2D - Math.Abs(greed[index][0] - zero - fi); var x2 = cellSize / 2D - Math.Abs(greed[index][1] - l_zero - lambda); if (x1 < 0 || x2 < 0) { System.Windows.Forms.MessageBox.Show("getMappingOfPoints: неправильна визначена клітинка точки " + i.ToString()); } else { map[index].Add(i); } } } ; }); return(map); }
//Записує кількість вимірів для кожної клітинки сітки public static void writeGreedToCsvFileWithMeasureCount(List <double[]> greed, List <int>[] map, string file) { System.IO.TextWriter tw = new System.IO.StreamWriter(file, false); int i = 0; int ii = 0; foreach (var item in greed) { if (item[1] > Math.PI) { ii++; } ; tw.WriteLine("{2:0.000};{1:0.000};{0}", map[i].Count, MathFunc.rad2deg((Math.PI / 2D) - item[0]), MathFunc.rad2deg(item[1] - Math.PI)); i++; } tw.Flush(); tw.Close(); }
/// <summary> /// Обчислення градієнту V_zz для заданих координат по моделі "in_model" /// </summary> public static double getGradient(ReferenceSystem rs, GravityModel in_model, double coLat, double longit, MathFunc.AngleType angType = MathFunc.AngleType.Radians) { GravityModel gm; if (in_model.model_a != rs.a || in_model.model_GM != rs.GM) { gm = in_model.rescaleModel(rs); } else { gm = new GravityModel(in_model); }; if (angType == MathFunc.AngleType.Degrees) { MathFunc.deg2rad(ref longit); } double grad = 0; double tmp = 0, sum_tmp = 0, sum_tmp_2 = 0; double[] legendrePolynoms = null; MathFunc.getLegendre(rs.maxDegree, coLat, out legendrePolynoms, angType); for (int i = 0; i <= rs.maxDegree; i++) { int n = MathFunc.getArraySize(i - 1) - 1; sum_tmp_2 = 0; sum_tmp = (i + 1) * (i + 2) * Math.Pow(rs.a / rs.satelliteSphere, i + 3); for (int m = 0; m < gm.c_coef[i].Length; m++) { double a1 = legendrePolynoms[n + m + 1], a2 = gm.c_coef[i][m] * Math.Cos(m * longit), a3 = gm.s_coef[i][m] * Math.Sin(m * longit); double x = a1 * (a2 + a3); sum_tmp_2 += x; } tmp += sum_tmp * sum_tmp_2; } grad = rs.GM / Math.Pow(rs.a, 3D) * tmp; return(grad); }
public static double[][] getGeoidHeightAndAnomalys(ReferenceSystem rs, GravityModel model, List <double[]> grid, System.Threading.CancellationToken ct, System.Threading.CancellationToken ct2, NormalGammaFormula gamma_0_formula = NormalGammaFormula.Somigliana, MainForm.setProgressDel d = null) { GravityModel gm; if (model.model_a != rs.a || model.model_GM != rs.GM) { gm = new GravityModel(model.rescaleModel(rs), rs.a, rs.GM); } else { gm = new GravityModel(model, model.model_a, model.model_GM); }; gm = getDisturbingModel(rs, gm); double[] heights = new double[grid.Count]; double[] anomaly = new double[grid.Count]; int[][] t_nm = MathFunc.get_nm(gm.maxDegree); double[] legendrePolys_old = null; double point_old = double.MinValue; object locker = new object(), locker2 = new object(); int position = 0; int count = grid.Count, position_p = (rs.maxDegree < 150)?(int)Math.Round(0.01d * count):5; ParallelOptions po = new ParallelOptions(); po.MaxDegreeOfParallelism = Environment.ProcessorCount; po.CancellationToken = ct; try { Parallel.For(0, grid.Count, po, (pointIndex) => { Label1: if (ct2.IsCancellationRequested) { System.Threading.Thread.Sleep(1000); } else { goto label2; } goto Label1; label2: double gamma_0 = 0, B = 0, r = 0; double[] legendrePolys = null; double[] point = grid[pointIndex]; lock (locker2) { if (point_old != double.MinValue) { if (point[0] == point_old) { legendrePolys = new double[legendrePolys_old.Length]; legendrePolys_old.CopyTo(legendrePolys, 0); } MathFunc.getLegendre(rs.maxDegree, point[0], out legendrePolys); legendrePolys_old = new double[legendrePolys.Length]; legendrePolys.CopyTo(legendrePolys_old, 0); point_old = point[0]; } else { MathFunc.getLegendre(rs.maxDegree, point[0], out legendrePolys); legendrePolys_old = new double[legendrePolys.Length]; legendrePolys.CopyTo(legendrePolys_old, 0); point_old = point[0]; } } B = MathFunc.convertThethaToB(point[0], rs); r = MathFunc.getGeocentrDistanceToPointOnElips(rs, B); if (gamma_0_formula == NormalGammaFormula.Somigliana) { gamma_0 = rs.gamma_a * (1d + rs.k * Math.Pow(Math.Sin(B), 2d)) / Math.Sqrt(1d - rs.firstExcentricity_2 * Math.Pow(Math.Sin(B), 2d)); } else { gamma_0 = 9.78030d * (1d + 0.005302 * Math.Pow(Math.Sin(B), 2d) - 0.000007 * Math.Pow(Math.Sin(2d * B), 2d)); } double a1, a2_x = rs.a / r, a2_t, a3, cosMlambda, sinMlambda, a1_a, a2_a = 0, a2 = 0, a2_x_m = a2_x; a1 = rs.GM / (r * gamma_0); a1_a = rs.GM / (r * r); int az = 0; for (int n = 0; n < rs.maxDegree; n++) { int x = (n == 0) ? 0 : -1; a3 = 0; az += (n - 1) + 1; for (int m = 0; m <= n; m++) { cosMlambda = Math.Cos(m * point[1]); sinMlambda = Math.Sin(m * point[1]); a3 += (gm.c_coef[n][m] * cosMlambda + gm.s_coef[n][m] * sinMlambda) * legendrePolys[az + (n - m)]; } if (n > 1) { a2_x *= a2_x_m; a2_t = a2_x; } else { a2_t = Math.Pow(a2_x, n); }; a2 += a2_t * a3; a2_a += a2_t * (n - 1) * a3; } double tmp_h = a1 * a2, tmp_a = a1_a * a2_a * 1e5; lock (heights) { heights[pointIndex] = tmp_h; } lock (anomaly) { anomaly[pointIndex] = tmp_a; } if (d != null) { position++; if (position > position_p) { lock (locker) { position_p += position_p; }; d.Invoke(position, count, "Обчислено висоти для точок: "); } ; if (position >= count) { d.Invoke(0, 1, ""); } ; } }); } catch (OperationCanceledException) { return(new double[2][]); } return(new double[][] { heights, anomaly }); }
//Обчислення аномалій сили ваги для сітки (в мГал) public static double[] getAnomaly(ReferenceSystem rs, GravityModel model, List <double[]> grid, MainForm.setProgressDel d = null) { GravityModel gm; if (model.model_a != rs.a || model.model_GM != rs.GM) { gm = new GravityModel(model.rescaleModel(rs), rs.a, rs.GM); } else { gm = new GravityModel(model, model.model_a, model.model_GM); }; gm = getDisturbingModel(rs, gm); double[] heights = new double[grid.Count]; int[][] t_nm = MathFunc.get_nm(gm.maxDegree); double[] legendrePolys_old = null; double point_old = double.MinValue; object locker = new object(), locker2 = new object(); int position = 0; int count = grid.Count, position_p = (int)Math.Round(0.01d * count); Parallel.For(0, grid.Count, (pointIndex) => { double B = 0, r = 0; double[] legendrePolys = null; double[] point = grid[pointIndex]; lock (locker2) { if (point_old != double.MinValue) { if (point[0] == point_old) { legendrePolys = new double[legendrePolys_old.Length]; legendrePolys_old.CopyTo(legendrePolys, 0); } MathFunc.getLegendre(gm.maxDegree, point[0], out legendrePolys); legendrePolys_old = new double[legendrePolys.Length]; legendrePolys.CopyTo(legendrePolys_old, 0); point_old = point[0]; } else { MathFunc.getLegendre(gm.maxDegree, point[0], out legendrePolys); legendrePolys_old = new double[legendrePolys.Length]; legendrePolys.CopyTo(legendrePolys_old, 0); point_old = point[0]; } } B = MathFunc.convertThethaToB(point[0], rs); r = MathFunc.getGeocentrDistanceToPointOnElips(rs, B); double a1, a2 = 0, a3, cosMlambda, sinMlambda; a1 = rs.GM / (r * r); for (int n = 0; n < gm.maxDegree; n++) { a3 = 0; for (int m = 0; m <= n; m++) { cosMlambda = Math.Cos(m * point[1]); sinMlambda = Math.Sin(m * point[1]); lock (gm) { a3 += (gm.c_coef[n][m] * cosMlambda + gm.s_coef[n][m] * sinMlambda) * legendrePolys[MathFunc.getArraySize(n - 1) + (n - m)]; } } a2 += Math.Pow(rs.a / r, n) * (n - 1) * a3; } lock (heights) { heights[pointIndex] = a1 * a2; } if (d != null) { position++; if (position > position_p) { lock (locker) { position_p += position_p; }; d.Invoke(position, count, "Обчислено висоти для точок: "); } ; if (position >= count) { d.Invoke(0, 1, ""); } ; } }); return(heights); }
public static double convertThethaToB(double thetha, ReferenceSystem rs, MathFunc.AngleType angType = MathFunc.AngleType.Radians) { double phi = 0; if (angType == MathFunc.AngleType.Degrees) { phi = deg2rad(90d - thetha); } else { phi = Math.PI / 2d - thetha; }; return (Math.Atan(Math.Tan(phi) / (1d - rs.firstExcentricity_2))); }
/// <summary> /// Генерує повністю нормовані приєднані поліномами Лежандра для ступеня n і порядку від 0 до n, і полярної відстані coLat /// </summary> /// <param name="n">Максимальний порядок</param> /// <param name="coLat">Полярна відстань theta=90deg-phi</param> /// <param name="resType">Одиниці, в яких задана полярна відстань</param> /// <returns>масив double[] з поліномами від нуля до n ({P_00,P_10,P_11,P_20,P_21,P_22,P_30,...,P_nn})</returns> public static double[] getLegendrePolynomialsMy(int maxDegree, double coLat, MathFunc.AngleType resType = AngleType.Radians) { func_l f1 = (l) => { return Math.Sqrt((2D*l+1)/(2D*l)); }; func_l f2 = (l) => { return Math.Sqrt(2D * (double)l + 1D); }; func_lm W3 = (l, m) => { return Math.Sqrt((4D * Math.Pow((double)l,2D) - 1D) / (double)(l*l-m*m)); }; #region перевірка if (resType == MathFunc.AngleType.Degrees) { deg2rad(ref coLat); } #endregion List<double> res = new List<double> (getArraySize(maxDegree)); double[][]tmp = new double[maxDegree+1][]; int[][] indexes = get_nm(maxDegree); double sinColat = Math.Sin(coLat), cosColat = Math.Cos(coLat); tmp[0] = new double[] {1}; tmp[1] = new double[2]; tmp[1][1] = Math.Sqrt(3D) * sinColat; for (int i = 2; i < tmp.Length; i++) { tmp[i] = new double[i+1]; tmp[i][i] = f1(i) * sinColat * tmp[i-1][i-1]; } int mm = 0; for (int i = 1; i < tmp.Length; i++) { tmp[i][i-1] = f2(i) * cosColat * tmp[i-1][i-1]; if (i > 1) { for (int j = 2; j <=i; j++) { mm=i-j; tmp[i][mm] = W3(i,mm)*(cosColat*tmp[i-1][mm]-1D/W3(i-1,mm)*tmp[i-2][mm]); } } } for (int i = 0; i < tmp.Length; i++) { foreach (var item in tmp[i]) { res.Add(item); } } return res.ToArray(); }
/// <summary> /// Генерує повністю нормовані приєднані поліномами Лежандра для ступеня n і порядку від 0 до n, і полярної відстані coLat /// </summary> /// <param name="i">Максимальний порядок</param> /// <param name="d">Полярна відстань d=90deg-phi</param> /// <param name="ad">Масив в який буде записано результат, він буде перезаписаний</param> /// <param name="angType">Одиниці, в яких задана полярна відстань</param> /// <returns>масив double[] з поліномами від нуля до n ({P_00,P_10,P_11,P_20,P_21,P_22,P_30,...,P_nn})</returns> public static void getLegendre(int i, double d, out double[] res, MathFunc.AngleType angType = AngleType.Radians) { #region proverka if (angType == MathFunc.AngleType.Degrees) { deg2rad(ref d); } #endregion int k_ = ((i + 1) * (i + 2)) / 2; double[] ad = new double[k_]; ad[0] = 1.0D; //00 double d1 = Math.Sin(d); double d2 = Math.Cos(d); ad[1] = Math.Sqrt(3D) * d1; //11 ad[2] = Math.Sqrt(3D) * d2; //10 if (i <= 1) { res = ad; return; } int j = 3; int k = 1; int l = 2; for (int i1 = 2; i1 <= i; i1++) { int j1 = 2 * i1 + 1; int k1 = j1 - 2; int l1 = k1 - 2; j++; ad[j - 1] = (Math.Sqrt((double)j1) / (double)i1) * (Math.Sqrt((double)k1) * d1 * ad[l - 1] - ((double)(i1 - 1) * ad[k - 1]) / Math.Sqrt((double)l1)); double d3 = Math.Sqrt(k1) * d2; double d4 = Math.Sqrt(2D) * d3 * ad[l - 1]; double d6 = Math.Sqrt(k1) * d1; j++; if (i1 >= 3) d4 += (Math.Sqrt((i1 - 1) * (i1 - 2)) * ad[k]) / Math.Sqrt(l1); ad[j - 1] = (Math.Sqrt(j1) * d4) / Math.Sqrt(i1 * (i1 + 1)); for (int i2 = 2; i2 <= i1; i2++) { int j2 = i1 + i2; int k2 = j2 - 1; j++; double d5 = d3 * ad[(l + i2) - 2]; double d7 = d6 * ad[(l + i2) - 1]; if (i2 + 2 > i1) { ad[j - 1] = (Math.Sqrt(j1) * d5) / Math.Sqrt(j2 * k2); } else { d7 -= (Math.Sqrt(k2 * (i1 - i2 - 1)) * ad[(k + i2) - 1]) / Math.Sqrt(l1); ad[j - 1] = (Math.Sqrt(j1) * d7) / Math.Sqrt(j2 * (i1 - i2)); } } k += i1 - 1; l += i1; } res = ad; }
//Формування рядка матриці коефіцієнтів рівнянь поправок public static double[] getCoefMatrixLineKoop(ReferenceSystem rs, int n, int[][] t_nm, double r, double coLatitude, double longitude, MathFunc.AngleType angType = AngleType.Radians) { if (angType == AngleType.Degrees) { deg2rad(ref longitude); } List<double> line = new List<double>((getArraySize(n) - 3) * 2 - (rs.maxDegree - 1)); double[][] legPol = getLegendreP_lm_cos_phi(n, Math.PI / 2d - coLatitude); double u_1 = rs.GM / Math.Pow(rs.a, 3d), u_2 = rs.a / rs.satelliteSphere; for (int l = 2; l <= rs.maxDegree; l++) { double u_3 = u_1 * Math.Pow(u_2, l + 3)*(l+1)*(l+2); for (int m = 0; m <= l; m++) { line.Add(u_3 * legPol[l][m] * Math.Cos((double)m * longitude)); if (m != 0) { line.Add(u_3 * legPol[l][m] * Math.Sin((double)m * longitude)); } } } return line.ToArray(); }
/// <summary> /// Обчислює масив з коефіцієнтами рядка в матриці /// </summary> /// <param name="rs">Еліпсоїд</param> /// <param name="n">Порядок розвинення</param> /// <param name="r">Радіус сфери, до якої віднесені виміри</param> /// <param name="coLatitude">Полярний кут tetha = 90deg-phi</param> /// <param name="longitude">Довгота</param> /// <param name="angType">Одиниці, в яких задано попередні кути</param> /// <returns></returns> public static double[] getCoefMatrixLine(ReferenceSystem rs, int n, int[][] t_nm, double r, double coLatitude, double longitude, MathFunc.AngleType angType = AngleType.Radians) { if (angType == AngleType.Degrees) { deg2rad(ref longitude); } double[] line = new double[(getArraySize(n) - 3) * 2-(rs.maxDegree-1)]; double u_1 = rs.GM / (Math.Pow(rs.a, 3d)); double[] legPol = null; getLegendre(n, coLatitude, out legPol, angType); double tmp_n = 0; double tmp_m = 0; int lineIndex = 0; for (int i = 0; i <= legPol.Length; i++) { if (i < 4) { continue; } tmp_n = t_nm[i-1][0]; tmp_m = t_nm[i-1][1]; double b = legPol[getArraySize(t_nm[i - 1][0] - 1) + t_nm[i - 1][0] - t_nm[i - 1][1]]; double a = (tmp_n + 1D) * (tmp_n + 2D) * Math.Pow(rs.a / rs.satelliteSphere, (double)tmp_n + 3d)*u_1; double a1 = a * Math.Cos(tmp_m * longitude); line[lineIndex] = a1 * b; if (tmp_m > 0) { double a2 = a * Math.Sin(tmp_m * longitude); line[lineIndex + 1] = a2 * b; lineIndex += 2; } else { lineIndex++; } } return line; }
/// <summary> /// Обчислення градієнту V_zz для заданих координат по моделі "in_model" /// </summary> public static double getGradient(ReferenceSystem rs,GravityModel in_model, double coLat, double longit, MathFunc.AngleType angType = MathFunc.AngleType.Radians) { GravityModel gm; if (in_model.model_a != rs.a || in_model.model_GM != rs.GM) { gm = in_model.rescaleModel(rs); } else { gm = new GravityModel(in_model); }; if (angType == MathFunc.AngleType.Degrees) { MathFunc.deg2rad(ref longit); } double grad = 0; double tmp = 0, sum_tmp = 0, sum_tmp_2 = 0; double[] legendrePolynoms = null; MathFunc.getLegendre(rs.maxDegree, coLat, out legendrePolynoms, angType); for (int i = 0; i <= rs.maxDegree; i++) { int n = MathFunc.getArraySize(i - 1) - 1; sum_tmp_2 = 0; sum_tmp = (i + 1) * (i + 2) * Math.Pow(rs.a / rs.satelliteSphere, i + 3); for (int m = 0; m < gm.c_coef[i].Length; m++) { double a1 = legendrePolynoms[n + m + 1], a2 = gm.c_coef[i][m] * Math.Cos(m * longit), a3 = gm.s_coef[i][m] * Math.Sin(m * longit); double x = a1 * (a2 + a3); sum_tmp_2 += x; } tmp += sum_tmp * sum_tmp_2; } grad = rs.GM / Math.Pow(rs.a, 3D) * tmp; return grad; }