public static void spherical_harmonic_values_test() //****************************************************************************80 // // Purpose: // // SPHERICAL_HARMONIC_VALUES_TEST tests SPHERICAL_HARMONIC_VALUES. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 08 February 2007 // // Author: // // John Burkardt // { int l = 0; int m = 0; double phi = 0; double theta = 0; double yi = 0; double yr = 0; Console.WriteLine(""); Console.WriteLine("SPHERICAL_HARMONIC_VALUES_TEST:"); Console.WriteLine(" SPHERICAL_HARMONIC_VALUES stores values of"); Console.WriteLine(" the spherical harmonic function."); Console.WriteLine(""); Console.WriteLine(" L M THETA PHI Yr Yi"); Console.WriteLine(""); int n_data = 0; for (;;) { SphericalHarmonic.spherical_harmonic_values(ref n_data, ref l, ref m, ref theta, ref phi, ref yr, ref yi); if (n_data == 0) { break; } Console.WriteLine(" " + l.ToString().PadLeft(2) + " " + m.ToString().PadLeft(2) + " " + theta.ToString("0.####").PadLeft(8) + " " + phi.ToString("0.####").PadLeft(8) + " " + yr.ToString("0.################").PadLeft(24) + " " + yi.ToString("0.################").PadLeft(24) + ""); } }
public SphericalHarmonicsPanel() { InitializeComponent(); try { m_sh0 = new SphericalHarmonic(C, S, N, a, SphericalHarmonic.Normalization.SCHMIDT); m_sh1 = new SphericalHarmonic1(C, S, N, C1, S1, N1, a, SphericalHarmonic1.Normalization.FULL); m_sh2 = new SphericalHarmonic2(C, S, N, C1, S1, N1, C2, S2, N2, a, SphericalHarmonic2.Normalization.FULL); } catch (Exception xcpt) { MessageBox.Show(xcpt.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } m_classComboBox.SelectedIndex = 0; }
public SphericalHarmonicsPanel() { InitializeComponent(); try { m_sh0 = new SphericalHarmonic(C, S, N, a, SphericalHarmonic.Normalization.SCHMIDT); m_sh1 = new SphericalHarmonic1(C, S, N, C1, S1, N1, a, SphericalHarmonic1.Normalization.FULL); m_sh2 = new SphericalHarmonic2(C, S, N, C1, S1, N1, C2, S2, N2, a, SphericalHarmonic2.Normalization.FULL); } catch (Exception xcpt) { MessageBox.Show(xcpt.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } m_classComboBox.SelectedIndex = 0; }
static void Main(string[] args) { try { int N = 3; // The maximum degree double[] ca = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; // cosine coefficients double[] sa = { 6, 5, 4, 3, 2, 1 }; // sine coefficients double a = 1; SphericalHarmonic h = new SphericalHarmonic(ca, sa, N, a, SphericalHarmonic.Normalization.SCHMIDT); double x = 2, y = 3, z = 1; double v, vx, vy, vz; v = h.HarmonicSum(x, y, z, out vx, out vy, out vz); Console.WriteLine(String.Format("{0} {1} {2} {3}", v, vx, vy, vz)); } catch (GeographicErr e) { Console.WriteLine(String.Format("Caught exception: {0}", e.Message)); } }
static void Main(string[] args) { try { int N = 3; // The maximum degree double[] ca = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; // cosine coefficients double[] sa = {6, 5, 4, 3, 2, 1}; // sine coefficients double a = 1; SphericalHarmonic h = new SphericalHarmonic(ca, sa, N, a, SphericalHarmonic.Normalization.SCHMIDT); double x = 2, y = 3, z = 1; double v, vx, vy, vz; v = h.HarmonicSum(x, y, z, out vx, out vy, out vz); Console.WriteLine(String.Format("{0} {1} {2} {3}", v, vx, vy, vz)); } catch (GeographicErr e) { Console.WriteLine(String.Format("Caught exception: {0}", e.Message)); } }
static void Main(string[] args) { // This computes the same value as example-SphericalHarmonic.cpp using a // CircularEngine (which will be faster if many values on a circle of // latitude are to be found). try { int N = 3; // The maxium degree double[] ca = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; // cosine coefficients double[] sa = { 6, 5, 4, 3, 2, 1 }; // sine coefficients double a = 1; SphericalHarmonic h = new SphericalHarmonic(ca, sa, N, a, SphericalHarmonic.Normalization.SCHMIDT); double x = 2, y = 3, z = 1, p = Math.Sqrt(x * x + y * y); CircularEngine circ = h.Circle(p, z, true); double v, vx, vy, vz; v = circ.LongitudeSum(x / p, y / p, out vx, out vy, out vz); Console.WriteLine(String.Format("{0} {1} {2} {3}", v, vx, vy, vz)); } catch (GeographicErr e) { Console.WriteLine(String.Format("Caught exception: {0}", e.Message)); } }
static void Main(string[] args) { // This computes the same value as example-SphericalHarmonic.cpp using a // CircularEngine (which will be faster if many values on a circle of // latitude are to be found). try { int N = 3; // The maxium degree double[] ca = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; // cosine coefficients double[] sa = {6, 5, 4, 3, 2, 1}; // sine coefficients double a = 1; SphericalHarmonic h = new SphericalHarmonic(ca, sa, N, a, SphericalHarmonic.Normalization.SCHMIDT); double x = 2, y = 3, z = 1, p = Math.Sqrt(x*x+y*y); CircularEngine circ = h.Circle(p, z, true); double v, vx, vy, vz; v = circ.LongitudeSum(x/p, y/p, out vx, out vy, out vz); Console.WriteLine(String.Format("{0} {1} {2} {3}", v, vx, vy, vz)); } catch (GeographicErr e) { Console.WriteLine(String.Format("Caught exception: {0}", e.Message)); } }
/// <summary> /// Construct a magnetic model. /// </summary> /// <param name="name">the name of the model</param> /// <param name="path">(optional) directory for data file.</param> /// <param name="earth">(optional) <see cref="Geocentric"/> object for converting coordinates; default <see cref="Geocentric.WGS84"/>.</param> /// <param name="Nmax">(optional) if non-negative, truncate the degree of the model this value.</param> /// <param name="Mmax">(optional) if non-negative, truncate the order of the model this value.</param> /// <remarks> /// A filename is formed by appending ".wmm" (World Magnetic Model) to the name. /// If path is specified (and is non-empty), then the file is loaded from directory, <paramref name="path"/>. /// Otherwise the path is given by the <see cref="DefaultMagneticPath"/>. /// <para> /// This file contains the metadata which specifies the properties of the model. /// The coefficients for the spherical harmonic sums are obtained from a file obtained by appending ".cof" to metadata file (so the filename ends in ".wwm.cof"). /// </para> /// <para> /// The model is not tied to a particular ellipsoidal model of the earth. /// The final earth argument to the constructor specifies an ellipsoid to allow geodetic coordinates to the /// transformed into the spherical coordinates used in the spherical harmonic sum. /// </para> /// <para> /// If <paramref name="Nmax"/> ≥ 0 and <paramref name="Mmax"/> < 0, then <paramref name="Mmax"/> is set to <paramref name="Nmax"/>. /// After the model is loaded, the maximum degree and order of the model can be found by the <see cref="Degree"/> and <see cref="Order"/> methods. /// </para> /// </remarks> public MagneticModel(string name, string path = "", Geocentric earth = null, int Nmax = -1, int Mmax = -1) { earth = earth ?? Geocentric.WGS84; _name = name; _dir = path; _description = "NONE"; _t0 = double.NaN; _dt0 = 1; _tmin = double.NaN; _tmax = double.NaN; _a = double.NaN; _hmin = double.NaN; _hmax = double.NaN; _Nmodels = 1; _Nconstants = 0; _nmx = -1; _mmx = -1; _norm = Normalization.Schmidt; _earth = earth; if (string.IsNullOrEmpty(path)) { _dir = DefaultMagneticPath; } bool truncate = Nmax >= 0 || Mmax >= 0; if (truncate) { if (Nmax >= 0 && Mmax < 0) { Mmax = Nmax; } if (Nmax < 0) { Nmax = int.MaxValue; } if (Mmax < 0) { Mmax = int.MaxValue; } } ReadMetadata(_name, ref _filename, ref _id, ref _name, ref _description, ref _date, ref _a, ref _t0, ref _dt0, ref _tmin, ref _tmax, ref _hmin, ref _hmax, ref _Nmodels, ref _Nconstants, ref _norm); string coeff = _filename + ".cof"; using (var stream = File.OpenRead(coeff)) { Span <byte> id = stackalloc byte[idlength_]; if (stream.Read(id) != idlength_) { throw new GeographicException("No header in " + coeff); } if (MemoryMarshal.Cast <char, byte>(_id.AsSpan()).SequenceEqual(id)) { throw new GeographicException($"ID mismatch: {_id} vs {Encoding.ASCII.GetString(id.ToArray())}"); } for (int i = 0; i < _Nmodels + 1 + _Nconstants; ++i) { int N = 0, M = 0; if (truncate) { N = Nmax; M = Mmax; } var c = SphericalEngine.Coeff.FromStream(stream, ref N, ref M, truncate); if (!(M < 0 || c.Cv(0) == 0)) { throw new GeographicException("A degree 0 term is not permitted"); } var sh = new SphericalHarmonic(c, _a, _norm); _harm.Add(sh); _nmx = Max(_nmx, sh.Coefficients.Nmx); _mmx = Max(_mmx, sh.Coefficients.Mmx); } if (stream.Position != stream.Length) { throw new GeographicException("Extra data in " + coeff); } } }
private void OnValidate(object sender, EventArgs e) { try { const double DEG_TO_RAD = 3.1415926535897932384626433832795 / 180.0; double gradx, grady, gradz; SphericalHarmonic s0 = new SphericalHarmonic(C, S, N, N - 1, 0, a, SphericalHarmonic.Normalization.SCHMIDT); s0 = new SphericalHarmonic(C, S, N, a, SphericalHarmonic.Normalization.SCHMIDT); double sum = s0.HarmonicSum(1.0, 2.0, 3.0); double test = s0.HarmonicSum(1.0, 2.0, 3.0, out gradx, out grady, out grady); if (sum != test) { throw new Exception("Error in SphericalHarmonic.HarmonicSum"); } SphericalCoefficients sc = s0.Coefficients(); CircularEngine ce = s0.Circle(1.0, 0.5, true); sum = ce.LongitudeSum(60.0); test = ce.LongitudeSum(Math.Cos(60.0 * DEG_TO_RAD), Math.Sin(60.0 * DEG_TO_RAD)); if (sum != test) { throw new Exception("Error in CircularEngine.LongitudeSum 1"); } test = ce.LongitudeSum(60.0, out gradx, out grady, out gradz); if (sum != test) { throw new Exception("Error in CircularEngine.LongitudeSum 2"); } ce.LongitudeSum(Math.Cos(60.0 * DEG_TO_RAD), Math.Sin(60.0 * DEG_TO_RAD), out gradx, out grady, out gradz); if (sum != test) { throw new Exception("Error in CircularEngine.LongitudeSum 3"); } SphericalHarmonic1 s1 = new SphericalHarmonic1(C, S, N, N - 1, 1, C1, S1, N1, N1 - 1, 0, a, SphericalHarmonic1.Normalization.SCHMIDT); s1 = new SphericalHarmonic1(C, S, N, C1, S1, N1, a, SphericalHarmonic1.Normalization.SCHMIDT); sum = s1.HarmonicSum(0.95, 1.0, 2.0, 3.0); test = s1.HarmonicSum(0.95, 1.0, 2.0, 3.0, out gradx, out grady, out gradz); if (sum != test) { throw new Exception("Error in SphericalHarmonic1.HarmonicSum 3"); } ce = s1.Circle(0.95, 1.0, 0.5, true); sc = s1.Coefficients(); sc = s1.Coefficients1(); SphericalHarmonic2 s2 = new SphericalHarmonic2(C, S, N, N - 1, 2, C1, S1, N1, N1 - 1, 1, C2, S2, N2, N2 - 1, 0, a, SphericalHarmonic2.Normalization.SCHMIDT); s2 = new SphericalHarmonic2(C, S, N, C1, S1, N1, C2, S2, N2, a, SphericalHarmonic2.Normalization.SCHMIDT); sum = s2.HarmonicSum(0.95, 0.8, 1.0, 2.0, 3.0); test = s2.HarmonicSum(0.95, 0.8, 1.0, 2.0, 3.0, out gradx, out grady, out gradz); if (sum != test) { throw new Exception("Error in SphericalHarmonic2.HarmonicSum 3"); } ce = s2.Circle(0.95, 0.8, 1.0, 0.5, true); sc = s2.Coefficients(); sc = s2.Coefficients1(); sc = s2.Coefficients2(); } catch (Exception xcpt) { MessageBox.Show(xcpt.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } MessageBox.Show("No errors found", "OK", MessageBoxButtons.OK, MessageBoxIcon.Information); }
/// <summary> /// Construct a gravity model. /// </summary> /// <param name="name">the name of the model.</param> /// <param name="path">directory for data file.</param> /// <param name="Nmax">if non-negative, truncate the degree of the model this value.</param> /// <param name="Mmax">if non-negative, truncate the order of the model this value.</param> /// <remarks> /// A filename is formed by appending ".egm" (World Gravity Model) to the <paramref name="name"/>. /// If <paramref name="path"/> is specified (and is non-empty), then the file is loaded from directory, <paramref name="path"/>. /// Otherwise the <paramref name="path"/> is given by <see cref="DefaultGravityPath"/>. /// <para> /// This file contains the metadata which specifies the properties of the model. /// The coefficients for the spherical harmonic sums are obtained from a file obtained by appending ".cof" /// to metadata file (so the filename ends in ".egm.cof"). /// </para> /// <para> /// If <paramref name="Nmax"/> ≥ 0 and <paramref name="Mmax"/> < 0, then <paramref name="Mmax"/> is set to <paramref name="Nmax"/>. /// After the model is loaded, the maximum degree and order of the model can be found by the <see cref="Degree"/> and <see cref="Order"/> methods. /// </para> /// </remarks> public GravityModel(string name, string path = "", int Nmax = -1, int Mmax = -1) { _name = name; _dir = path; _description = "NONE"; _amodel = double.NaN; _GMmodel = double.NaN; _zeta0 = 0; _corrmult = 1; _nmx = -1; _mmx = -1; _norm = Normalization.Full; if (string.IsNullOrWhiteSpace(path)) { _dir = DefaultGravityPath; } bool truncate = Nmax >= 0 || Mmax >= 0; if (truncate) { if (Nmax >= 0 && Mmax < 0) { Mmax = Nmax; } if (Nmax < 0) { Nmax = int.MaxValue; } if (Mmax < 0) { Mmax = int.MaxValue; } } ReadMetadata(_name, ref _filename, ref _name, ref _description, ref _date, ref _amodel, ref _GMmodel, ref _zeta0, ref _corrmult, ref _norm, ref _id, ref _earth); double[] _Cx, _Sx; string coeff = _filename + ".cof"; using (var coeffstr = File.OpenRead(coeff)) { Span <byte> id = stackalloc byte[idlength_]; if (coeffstr.Read(id) != idlength_) { throw new GeographicException("No header in " + coeff); } if (MemoryMarshal.Cast <char, byte>(_id.AsSpan()).SequenceEqual(id)) { throw new GeographicException($"ID mismatch: {_id} vs {Encoding.ASCII.GetString(id.ToArray())}"); } int N = 0, M = 0; if (truncate) { N = Nmax; M = Mmax; } var scoeff = SphericalEngine.Coeff.FromStream(coeffstr, ref N, ref M, truncate); _Cx = new double[scoeff.Cnm.Length]; _Sx = new double[scoeff.Snm.Length]; scoeff.Cnm.CopyTo(_Cx); scoeff.Snm.CopyTo(_Sx); if (!(N >= 0 && M >= 0)) { throw new GeographicException("Degree and order must be at least 0"); } if (_Cx[0] != 0) { throw new GeographicException("The degree 0 term should be zero"); } _Cx[0] = 1; // Include the 1/r term in the sum _gravitational = new SphericalHarmonic(_Cx, _Sx, N, N, M, _amodel, _norm); if (truncate) { N = Nmax; M = Mmax; } scoeff = SphericalEngine.Coeff.FromStream(coeffstr, ref N, ref M, truncate); double[] _CC, _CS; if (N < 0) { N = M = 0; _CC = new[] { 0d }; } else { _CC = new double[scoeff.Cnm.Length]; scoeff.Cnm.CopyTo(_CC); } _CS = new double[scoeff.Snm.Length]; scoeff.Snm.CopyTo(_CS); _CC[0] += _zeta0 / _corrmult; _correction = new SphericalHarmonic(_CC, _CS, N, N, M, 1, _norm); var pos = (int)coeffstr.Position; coeffstr.Seek(0, SeekOrigin.End); if (pos != coeffstr.Position) { throw new GeographicException("Extra data in " + coeff); } } int nmx = _gravitational.Coefficients.Nmx; _nmx = Max(nmx, _correction.Coefficients.Nmx); _mmx = Max(_gravitational.Coefficients.Mmx, _correction.Coefficients.Mmx); // Adjust the normalization of the normal potential to match the model. var mult = _earth._GM / _GMmodel; var amult = Sq(_earth._a / _amodel); // The 0th term in _zonal should be is 1 + _dzonal0. Instead set it to 1 // to give exact cancellation with the (0,0) term in the model and account // for _dzonal0 separately. var _zonal = new List <double> { 1 }; _dzonal0 = (_earth.MassConstant - _GMmodel) / _GMmodel; for (int n = 2; n <= nmx; n += 2) { // Only include as many normal zonal terms as matter. Figuring the limit // in this way works because the coefficients of the normal potential // (which is smooth) decay much more rapidly that the corresponding // coefficient of the model potential (which is bumpy). Typically this // goes out to n = 18. mult *= amult; double r = _Cx[n], // the model term s = -mult *_earth.Jn(n) / Sqrt(2 * n + 1), // the normal term t = r - s; // the difference if (t == r) // the normal term is negligible { break; } _zonal.Add(0); // index = n - 1; the odd terms are 0 _zonal.Add(s); } int nmx1 = _zonal.Count - 1; var za = _zonal.ToArray(); _disturbing = new SphericalHarmonic1(_Cx, _Sx, _gravitational.Coefficients.N, nmx, _gravitational.Coefficients.Mmx, za, za, // This is not accessed! nmx1, nmx1, 0, _amodel, _norm); }
private void OnValidate(object sender, EventArgs e) { try { const double DEG_TO_RAD = 3.1415926535897932384626433832795 / 180.0; double gradx, grady, gradz; SphericalHarmonic s0 = new SphericalHarmonic(C, S, N, N - 1, 0, a, SphericalHarmonic.Normalization.SCHMIDT); s0 = new SphericalHarmonic(C, S, N, a, SphericalHarmonic.Normalization.SCHMIDT); double sum = s0.HarmonicSum(1.0, 2.0, 3.0); double test = s0.HarmonicSum(1.0, 2.0, 3.0, out gradx, out grady, out grady); if (sum != test) throw new Exception("Error in SphericalHarmonic.HarmonicSum"); SphericalCoefficients sc = s0.Coefficients(); CircularEngine ce = s0.Circle(1.0, 0.5, true); sum = ce.LongitudeSum(60.0); test = ce.LongitudeSum(Math.Cos(60.0 * DEG_TO_RAD), Math.Sin(60.0 * DEG_TO_RAD)); if ( sum != test ) throw new Exception("Error in CircularEngine.LongitudeSum 1"); test = ce.LongitudeSum(60.0, out gradx, out grady, out gradz); if ( sum != test ) throw new Exception("Error in CircularEngine.LongitudeSum 2"); ce.LongitudeSum(Math.Cos(60.0 * DEG_TO_RAD), Math.Sin(60.0 * DEG_TO_RAD), out gradx, out grady, out gradz); if (sum != test) throw new Exception("Error in CircularEngine.LongitudeSum 3"); SphericalHarmonic1 s1 = new SphericalHarmonic1(C, S, N, N - 1, 1, C1, S1, N1, N1 - 1, 0, a, SphericalHarmonic1.Normalization.SCHMIDT); s1 = new SphericalHarmonic1(C, S, N, C1, S1, N1, a, SphericalHarmonic1.Normalization.SCHMIDT); sum = s1.HarmonicSum(0.95, 1.0, 2.0, 3.0); test = s1.HarmonicSum(0.95, 1.0, 2.0, 3.0, out gradx, out grady, out gradz); if (sum != test) throw new Exception("Error in SphericalHarmonic1.HarmonicSum 3"); ce = s1.Circle(0.95, 1.0, 0.5, true); sc = s1.Coefficients(); sc = s1.Coefficients1(); SphericalHarmonic2 s2 = new SphericalHarmonic2(C, S, N, N - 1, 2, C1, S1, N1, N1 - 1, 1, C2, S2, N2, N2 - 1, 0, a, SphericalHarmonic2.Normalization.SCHMIDT); s2 = new SphericalHarmonic2(C, S, N, C1, S1, N1, C2, S2, N2, a, SphericalHarmonic2.Normalization.SCHMIDT); sum = s2.HarmonicSum(0.95, 0.8, 1.0, 2.0, 3.0); test = s2.HarmonicSum(0.95, 0.8, 1.0, 2.0, 3.0, out gradx, out grady, out gradz); if (sum != test) throw new Exception("Error in SphericalHarmonic2.HarmonicSum 3"); ce = s2.Circle(0.95, 0.8, 1.0, 0.5, true); sc = s2.Coefficients(); sc = s2.Coefficients1(); sc = s2.Coefficients2(); } catch (Exception xcpt) { MessageBox.Show(xcpt.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } MessageBox.Show("No errors found", "OK", MessageBoxButtons.OK, MessageBoxIcon.Information); }
public static void spherical_harmonic_test() //****************************************************************************80 // // Purpose: // // SPHERICAL_HARMONIC_TEST tests SPHERICAL_HARMONIC. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 02 June 2007 // // Author: // // John Burkardt // { const int N_MAX = 20; double[] c = new double[N_MAX + 1]; int l = 0; int m = 0; double phi = 0; double[] s = new double[N_MAX + 1]; double theta = 0; double yi = 0; double yr = 0; Console.WriteLine(""); Console.WriteLine("SPHERICAL_HARMONIC_TEST:"); Console.WriteLine(" SPHERICAL_HARMONIC evaluates spherical harmonic functions."); Console.WriteLine(""); Console.WriteLine( " N M THETA PHI YR YI"); Console.WriteLine(""); int n_data = 0; for (;;) { Burkardt.Values.SphericalHarmonic.spherical_harmonic_values(ref n_data, ref l, ref m, ref theta, ref phi, ref yr, ref yi); if (n_data == 0) { break; } SphericalHarmonic.spherical_harmonic(l, m, theta, phi, ref c, ref s); double yr2 = c[l]; double yi2 = s[l]; Console.WriteLine(" " + l.ToString(CultureInfo.InvariantCulture).PadLeft(8) + " " + m.ToString(CultureInfo.InvariantCulture).PadLeft(8) + " " + theta.ToString(CultureInfo.InvariantCulture).PadLeft(8) + " " + phi.ToString(CultureInfo.InvariantCulture).PadLeft(8) + " " + yr.ToString(CultureInfo.InvariantCulture).PadLeft(14) + " " + yi.ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); Console.WriteLine(" " + " " + " " + " " + " " + " " + " " + " " + " " + yr2.ToString(CultureInfo.InvariantCulture).PadLeft(14) + " " + yi2.ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); } }