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) + "");
        }
    }
Ejemplo n.º 2
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;
 }
Ejemplo n.º 3
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;
 }
Ejemplo n.º 4
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));
     }
 }
Ejemplo n.º 5
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));
     }
 }
Ejemplo n.º 6
0
 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));
     }
 }
Ejemplo n.º 7
0
 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));
     }
 }
Ejemplo n.º 8
0
        /// <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"/> &lt; 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);
                }
            }
        }
Ejemplo n.º 9
0
 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);
 }
Ejemplo n.º 10
0
        /// <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"/> &lt; 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);
        }
Ejemplo n.º 11
0
 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) + "");
        }
    }