File indexing completed on 2024-04-21 14:47:05

0001 /*
0002     SPDX-FileCopyrightText: 2002-2005 Jason Harris <kstars@30doradus.org>
0003     SPDX-FileCopyrightText: 2004-2005 Pablo de Vicente <p.devicente@wanadoo.es>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "ksnumbers.h"
0009 
0010 #include "kstarsdatetime.h" //for J2000 define
0011 
0012 // 63 elements
0013 const int KSNumbers::arguments[NUTTERMS][5] = {
0014     { 0, 0, 0, 0, 1 },   { -2, 0, 0, 2, 2 },  { 0, 0, 0, 2, 2 },   { 0, 0, 0, 0, 2 },  { 0, 1, 0, 0, 0 },
0015     { 0, 0, 1, 0, 0 },   { -2, 1, 0, 2, 2 },  { 0, 0, 0, 2, 1 },   { 0, 0, 1, 2, 2 },  { -2, -1, 0, 2, 2 },
0016     { -2, 0, 1, 0, 0 },  { -2, 0, 0, 2, 1 },  { 0, 0, -1, 2, 2 },  { 2, 0, 0, 0, 0 },  { 0, 0, 1, 0, 1 },
0017     { 2, 0, -1, 2, 2 },  { 0, 0, -1, 0, 1 },  { 0, 0, 1, 2, 1 },   { -2, 0, 2, 0, 0 }, { 0, 0, -2, 2, 1 },
0018     { 2, 0, 0, 2, 2 },   { 0, 0, 2, 2, 2 },   { 0, 0, 2, 0, 0 },   { -2, 0, 1, 2, 2 }, { 0, 0, 0, 2, 0 },
0019     { -2, 0, 0, 2, 0 },  { 0, 0, -1, 2, 1 },  { 0, 2, 0, 0, 0 },   { 2, 0, -1, 0, 1 }, { -2, 2, 0, 2, 2 },
0020     { 0, 1, 0, 0, 1 },   { -2, 0, 1, 0, 1 },  { 0, -1, 0, 0, 1 },  { 0, 0, 2, -2, 0 }, { 2, 0, -1, 2, 1 },
0021     { 2, 0, 1, 2, 2 },   { 0, 1, 0, 2, 2 },   { -2, 1, 1, 0, 0 },  { 0, -1, 0, 2, 2 }, { 2, 0, 0, 2, 1 },
0022     { 2, 0, 1, 0, 0 },   { -2, 0, 2, 2, 2 },  { -2, 0, 1, 2, 1 },  { 2, 0, -2, 0, 1 }, { 2, 0, 0, 0, 1 },
0023     { 0, -1, 1, 0, 0 },  { -2, -1, 0, 2, 1 }, { -2, 0, 0, 0, 1 },  { 0, 0, 2, 2, 1 },  { -2, 0, 2, 0, 1 },
0024     { -2, 1, 0, 2, 1 },  { 0, 0, 1, -2, 0 },  { -1, 0, 1, 0, 0 },  { -2, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0 },
0025     { 0, 0, 1, 2, 0 },   { 0, 0, -2, 2, 2 },  { -1, -1, 1, 0, 0 }, { 0, 1, 1, 0, 0 },  { 0, -1, 1, 2, 2 },
0026     { 2, -1, -1, 2, 2 }, { 0, 0, 3, 2, 2 },   { 2, -1, 0, 2, 2 }
0027 };
0028 
0029 const int KSNumbers::amp[NUTTERMS][4] = { { -171996, -1742, 92025, 89 },
0030                                           { -13187, -16, 5736, -31 },
0031                                           { -2274, -2, 977, -5 },
0032                                           { 2062, 2, -895, 5 },
0033                                           { 1426, -34, 54, -1 },
0034                                           { 712, 1, -7, 0 },
0035                                           { -517, 12, 224, -6 },
0036                                           { -386, -4, 200, 0 },
0037                                           { -301, 0, 129, -1 },
0038                                           { 217, -5, -95, 3 },
0039                                           { -158, 0, 0, 0 },
0040                                           { 129, 1, -70, 0 },
0041                                           { 123, 0, -53, 0 },
0042                                           { 63, 0, 0, 0 },
0043                                           { 63, 1, -33, 0 },
0044                                           { -59, 0, 26, 0 },
0045                                           { -58, -1, 32, 0 },
0046                                           { -51, 0, 27, 0 },
0047                                           { 48, 0, 0, 0 },
0048                                           { 46, 0, -24, 0 },
0049                                           { -38, 0, 16, 0 },
0050                                           { -31, 0, 13, 0 },
0051                                           { 29, 0, 0, 0 },
0052                                           { 29, 0, -12, 0 },
0053                                           { 26, 0, 0, 0 },
0054                                           { -22, 0, 0, 0 },
0055                                           { 21, 0, -10, 0 },
0056                                           { 17, -1, 0, 0 },
0057                                           { 16, 0, -8, 0 },
0058                                           { -16, 1, 7, 0 },
0059                                           { -15, 0, 9, 0 },
0060                                           { -13, 0, 7, 0 },
0061                                           { -12, 0, 6, 0 },
0062                                           { 11, 0, 0, 0 },
0063                                           { -10, 0, 5, 0 },
0064                                           { -8, 0, 3, 0 },
0065                                           { 7, 0, -3, 0 },
0066                                           { -7, 0, 0, 0 },
0067                                           { -7, 0, 3, 0 },
0068                                           { -7, 0, 3, 0 },
0069                                           { 6, 0, 0, 0 },
0070                                           { 6, 0, -3, 0 },
0071                                           { 6, 0, -3, 0 },
0072                                           { -6, 0, 3, 0 },
0073                                           { -6, 0, 3, 0 },
0074                                           { 5, 0, 0, 0 },
0075                                           { -5, 0, 3, 0 },
0076                                           { -5, 0, 3, 0 },
0077                                           { -5, 0, 3, 0 },
0078                                           { 4, 0, 0, 0 },
0079                                           { 4, 0, 0, 0 },
0080                                           { 4, 0, 0, 0 },
0081                                           { -4, 0, 0, 0 },
0082                                           { -4, 0, 0, 0 },
0083                                           { -4, 0, 0, 0 },
0084                                           { 3, 0, 0, 0 },
0085                                           { -3, 0, 0, 0 },
0086                                           { -3, 0, 0, 0 },
0087                                           { -3, 0, 0, 0 },
0088                                           { -3, 0, 0, 0 },
0089                                           { -3, 0, 0, 0 },
0090                                           { -3, 0, 0, 0 },
0091                                           { -3, 0, 0, 0 } };
0092 
0093 KSNumbers::KSNumbers(long double jd)
0094 {
0095     K.setD(20.49552 / 3600.); //set the constant of aberration
0096 
0097     // ecliptic longitude of earth's perihelion, source: https://nssdc.gsfc.nasa.gov/planetary/factsheet/earthfact.html; FIXME: We should correct this, as it changes with time. See the commit log for an order of magnitude estimate of the error.
0098     // FIXME: FIXME above seems to have been addressed? What is deltaEcLong? -- asimha
0099     P.setD(102.94719);
0100 
0101     // JM 2017-09-04: Yes the longitude of the perihelion changes with time. The value below is the one for 04-09-2017 obtained from JPL Horizons system.
0102     // But some Earth orbital elements MUST be updated periodically like any other solar system body.
0103     // This is an important FIXME!
0104     // deltaEcLong is used in nutation calculations. Can P be obtained computationally?
0105     //P.setD(104.8089842092676);
0106 
0107     computeConstantValues();
0108     updateValues(jd);
0109 }
0110 
0111 void KSNumbers::computeConstantValues()
0112 {
0113     // Compute those numbers that need to be computed only
0114     // once.
0115     //
0116     // Ideally, these should be computed at compile-time. When we
0117     // upgrade to C++11, we can make this function static and
0118     // constexpr (maybe?) But even otherwise, the overhead is very
0119     // negligible.
0120 
0121     //Compute Precession Matrices from B1950 to 1984 using Newcomb formulae
0122     XB.setD(0.217697);
0123     YB.setD(0.189274);
0124     ZB.setD(0.217722);
0125 
0126     XB.SinCos(SXB, CXB);
0127     YB.SinCos(SYB, CYB);
0128     ZB.SinCos(SZB, CZB);
0129 
0130     //P1B is used to precess from 1984 to B1950:
0131 
0132     P1B(0, 0) = CXB * CYB * CZB - SXB * SZB;
0133     P1B(1, 0) = CXB * CYB * SZB + SXB * CZB;
0134     P1B(2, 0) = CXB * SYB;
0135     P1B(0, 1) = -1.0 * SXB * CYB * CZB - CXB * SZB;
0136     P1B(1, 1) = -1.0 * SXB * CYB * SZB + CXB * CZB;
0137     P1B(2, 1) = -1.0 * SXB * SYB;
0138     P1B(0, 2) = -1.0 * SYB * CZB;
0139     P1B(1, 2) = -1.0 * SYB * SZB;
0140     P1B(2, 2) = CYB;
0141 
0142     //P2 is used to precess from B1950 to 1984 (it is the transpose of P1)
0143     // FIXME: This can be optimized by taking the transpose of P1 instead of recomputing it from scratch
0144     P2B(0, 0) = CXB * CYB * CZB - SXB * SZB;
0145     P2B(1, 0) = -1.0 * SXB * CYB * CZB - CXB * SZB;
0146     P2B(2, 0) = -1.0 * SYB * CZB;
0147     P2B(0, 1) = CXB * CYB * SZB + SXB * CZB;
0148     P2B(1, 1) = -1.0 * SXB * CYB * SZB + CXB * CZB;
0149     P2B(2, 1) = -1.0 * SYB * SZB;
0150     P2B(0, 2) = CXB * SYB;
0151     P2B(1, 2) = -1.0 * SXB * SYB;
0152     P2B(2, 2) = CYB;
0153 }
0154 
0155 void KSNumbers::updateValues(long double jd)
0156 {
0157     dms arg;
0158     double args, argc;
0159 
0160     days = jd;
0161 
0162     // FIXME: What is the source for these algorithms / polynomials / numbers? -- asimha
0163 
0164     //Julian Centuries since J2000.0
0165     T = (jd - J2000) / 36525.;
0166 
0167     // Julian Millenia since J2000.0
0168     jm = T / 10.0;
0169 
0170     double T2 = T * T;
0171     double T3 = T2 * T;
0172 
0173     //Sun's Mean Longitude
0174     L.setD(280.46645 + 36000.76983 * T + 0.0003032 * T2);
0175 
0176     //Mean elongation of the Moon from the Sun
0177     D.setD(297.85036 + 445267.111480 * T - 0.0019142 * T2 + T3 / 189474.);
0178 
0179     //Sun's Mean Anomaly
0180     M.setD(357.52910 + 35999.05030 * T - 0.0001559 * T2 - 0.00000048 * T3);
0181 
0182     //Moon's Mean Anomaly
0183     MM.setD(134.96298 + 477198.867398 * T + 0.0086972 * T2 + T3 / 56250.0);
0184 
0185     //Moon's Mean Longitude
0186     LM.setD(218.3164591 + 481267.88134236 * T - 0.0013268 * T2 + T3 / 538841. - T * T * T * T / 6519400.);
0187 
0188     //Moon's argument of latitude
0189     F.setD(93.27191 + 483202.017538 * T - 0.0036825 * T2 + T3 / 327270.);
0190 
0191     //Longitude of Moon's Ascending Node
0192     O.setD(125.04452 - 1934.136261 * T + 0.0020708 * T2 + T3 / 450000.0);
0193 
0194     //Earth's orbital eccentricity
0195     e = 0.016708617 - 0.000042037 * T - 0.0000001236 * T2;
0196 
0197     double C = (1.914600 - 0.004817 * T - 0.000014 * T2) * sin(M.radians()) +
0198                (0.019993 - 0.000101 * T) * sin(2.0 * M.radians()) + 0.000290 * sin(3.0 * M.radians());
0199 
0200     //Sun's True Longitude
0201     L0.setD(L.Degrees() + C);
0202 
0203     //Sun's True Anomaly
0204     M0.setD(M.Degrees() + C);
0205 
0206     //Obliquity of the Ecliptic
0207     // FIXME: This can be optimized by using the fact that U^3 = U^2 * U, so we can reduce the number of multiplications
0208     double U      = T / 100.0;
0209     double dObliq = -4680.93 * U - 1.55 * U * U + 1999.25 * U * U * U - 51.38 * U * U * U * U -
0210                     249.67 * U * U * U * U * U - 39.05 * U * U * U * U * U * U + 7.12 * U * U * U * U * U * U * U +
0211                     27.87 * U * U * U * U * U * U * U * U + 5.79 * U * U * U * U * U * U * U * U * U +
0212                     2.45 * U * U * U * U * U * U * U * U * U * U;
0213     Obliquity.setD(23.43929111 + dObliq / 3600.0);
0214 
0215     //Nutation parameters
0216     dms L2, M2, O2;
0217     double sin2L, cos2L, sin2M, cos2M;
0218     double sinO, cosO, sin2O, cos2O;
0219 
0220     O2.setD(2.0 * O.Degrees());
0221     L2.setD(2.0 * L.Degrees());  //twice mean ecl. long. of Sun
0222     M2.setD(2.0 * LM.Degrees()); //twice mean ecl. long. of Moon
0223 
0224     O.SinCos(sinO, cosO);
0225     O2.SinCos(sin2O, cos2O);
0226     L2.SinCos(sin2L, cos2L);
0227     M2.SinCos(sin2M, cos2M);
0228 
0229     //  deltaEcLong = ( -17.2*sinO - 1.32*sin2L - 0.23*sin2M + 0.21*sin2O)/3600.0; //Ecl. long. correction
0230     //  deltaObliquity = ( 9.2*cosO + 0.57*cos2L + 0.10*cos2M - 0.09*cos2O)/3600.0; //Obliq. correction
0231 
0232     deltaEcLong    = 0.;
0233     deltaObliquity = 0.;
0234 
0235     for (unsigned int i = 0; i < NUTTERMS; i++)
0236     {
0237         arg.setD(arguments[i][0] * D.Degrees() + arguments[i][1] * M.Degrees() + arguments[i][2] * MM.Degrees() +
0238                  arguments[i][3] * F.Degrees() + arguments[i][4] * O.Degrees());
0239         arg.SinCos(args, argc);
0240 
0241         deltaEcLong += (amp[i][0] + amp[i][1] / 10. * T) * args * 1e-4;
0242         deltaObliquity += (amp[i][2] + amp[i][3] / 10. * T) * argc * 1e-4;
0243     }
0244 
0245     deltaEcLong /= 3600.0;
0246     deltaObliquity /= 3600.0;
0247 
0248     //Compute Precession Matrices:
0249     XP.setD(0.6406161 * T + 0.0000839 * T2 + 0.0000050 * T3);
0250     YP.setD(0.5567530 * T - 0.0001185 * T2 - 0.0000116 * T3);
0251     ZP.setD(0.6406161 * T + 0.0003041 * T2 + 0.0000051 * T3);
0252 
0253     XP.SinCos(SX, CX);
0254     YP.SinCos(SY, CY);
0255     ZP.SinCos(SZ, CZ);
0256 
0257     //P1 is used to precess from any epoch to J2000
0258     // Note: P1 is a rotation matrix, and P2 is its transpose = inverse (also a rotation matrix)
0259     P1(0, 0) = CX * CY * CZ - SX * SZ;
0260     P1(1, 0) = CX * CY * SZ + SX * CZ;
0261     P1(2, 0) = CX * SY;
0262     P1(0, 1) = -1.0 * SX * CY * CZ - CX * SZ;
0263     P1(1, 1) = -1.0 * SX * CY * SZ + CX * CZ;
0264     P1(2, 1) = -1.0 * SX * SY;
0265     P1(0, 2) = -1.0 * SY * CZ;
0266     P1(1, 2) = -1.0 * SY * SZ;
0267     P1(2, 2) = CY;
0268 
0269     //P2 is used to precess from J2000 to any other epoch (it is the transpose of P1)
0270     // FIXME: More optimization -- just use P1(j, i) instead of P2(i, j) in code
0271     P2(0, 0) = P1(0, 0);
0272     P2(1, 0) = P1(0, 1);
0273     P2(2, 0) = P1(0, 2);
0274     P2(0, 1) = P1(1, 0);
0275     P2(1, 1) = P1(1, 1);
0276     P2(2, 1) = P1(1, 2);
0277     P2(0, 2) = P1(2, 0);
0278     P2(1, 2) = P1(2, 1);
0279     P2(2, 2) = P1(2, 2);
0280 
0281     // Mean longitudes for the planets. radians
0282     //
0283 
0284     // TODO Pasar a grados [Google Translate says "Jump to Degrees". --asimha]
0285     double LVenus   = 3.1761467 + 1021.3285546 * T; // Venus
0286     double LMars    = 1.7534703 + 628.3075849 * T;  // Mars
0287     double LEarth   = 6.2034809 + 334.0612431 * T;  // Earth
0288     double LJupiter = 0.5995465 + 52.9690965 * T;   // Jupiter
0289     double LSaturn  = 0.8740168 + 21.3299095 * T;   // Saturn
0290     double LNeptune = 5.3118863 + 3.8133036 * T;    // Neptune
0291     double LUranus  = 5.4812939 + 7.4781599 * T;    // Uranus
0292 
0293     double LMRad = 3.8103444 + 8399.6847337 * T; // Moon
0294     double DRad  = 5.1984667 + 7771.3771486 * T;
0295     double MMRad = 2.3555559 + 8328.6914289 * T; // Moon
0296     double FRad  = 1.6279052 + 8433.4661601 * T;
0297 
0298     /** Contributions to the velocity of the Earth referred to the barycenter of the solar system
0299         in the J2000 equatorial system
0300         Velocities 10^{-8} AU/day
0301         Ron & Vondrak method
0302     **/
0303 
0304     double vondrak[36][7] = {
0305         { LMars, -1719914 - 2 * T, -25, 25 - 13 * T, 1578089 + 156 * T, 10 + 32 * T, 684185 - 358 * T },
0306         { 2 * LMars, 6434 + 141 * T, 28007 - 107 * T, 25697 - 95 * T, -5904 - 130 * T, 11141 - 48 * T, -2559 - 55 * T },
0307         { LJupiter, 715, 0, 6, -657, -15, -282 },
0308         { LMRad, 715, 0, 0, -656, 0, -285 },
0309         { 3 * LMars, 486 - 5 * T, -236 - 4 * T, -216 - 4 * T, -446 + 5 * T, -94, -193 },
0310         { LSaturn, 159, 0, 2, -147, -6, -61 },
0311         { FRad, 0, 0, 0, 26, 0, -59 },
0312         { LMRad + MMRad, 39, 0, 0, -36, 0, -16 },
0313         { 2 * LJupiter, 33, -10, -9, -30, -5, -13 },
0314         { 2 * LMars - LJupiter, 31, 1, 1, -28, 0, -12 },
0315         { 3 * LMars - 8 * LEarth + 3 * LJupiter, 8, -28, 25, 8, 11, 3 },
0316         { 5 * LMars - 8 * LEarth + 3 * LJupiter, 8, -28, -25, -8, -11, -3 },
0317         { 2 * LVenus - LMars, 21, 0, 0, -19, 0, -8 },
0318         { LVenus, -19, 0, 0, 17, 0, 8 },
0319         { LNeptune, 17, 0, 0, -16, 0, -7 },
0320         { LMars - 2 * LJupiter, 16, 0, 0, 15, 1, 7 },
0321         { LUranus, 16, 0, 1, -15, -3, -6 },
0322         { LMars + LJupiter, 11, -1, -1, -10, -1, -5 },
0323         { 2 * LVenus - 2 * LMars, 0, -11, -10, 0, -4, 0 },
0324         { LMars - LJupiter, -11, -2, -2, 9, -1, 4 },
0325         { 4 * LMars, -7, -8, -8, 6, -3, 3 },
0326         { 3 * LMars - 2 * LJupiter, -10, 0, 0, 9, 0, 4 },
0327         { LVenus - 2 * LMars, -9, 0, 0, -9, 0, -4 },
0328         { 2 * LVenus - 3 * LMars, -9, 0, 0, -8, 0, -4 },
0329         { 2 * LSaturn, 0, -9, -8, 0, -3, 0 },
0330         { 2 * LVenus - 4 * LMars, 0, -9, 8, 0, 3, 0 },
0331         { 3 * LMars - 2 * LEarth, 8, 0, 0, -8, 0, -3 },
0332         { LMRad + 2 * DRad - MMRad, 8, 0, 0, -7, 0, -3 },
0333         { 8 * LVenus - 12 * LMars, -4, -7, -6, 4, -3, 2 },
0334         { 8 * LVenus - 14 * LMars, -4, -7, 6, -4, 3, -2 },
0335         { 2 * LEarth, -6, -5, -4, 5, -2, 2 },
0336         { 3 * LVenus - 4 * LMars, -1, -1, -2, -7, 1, -4 },
0337         { 2 * LMars - 2 * LJupiter, 4, -6, -5, -4, -2, -2 },
0338         { 3 * LVenus - 3 * LMars, 0, -7, -6, 0, -3, 0 },
0339         { 2 * LMars - 2 * LEarth, 5, -5, -4, -5, -2, -2 },
0340         { LMRad - 2 * DRad, 5, 0, 0, -5, 0, -2 }
0341     };
0342 
0343     dms anglev;
0344     double sa, ca;
0345     // Vearth X component
0346     vearth[0] = 0.;
0347     // Vearth Y component
0348     vearth[1] = 0.;
0349     // Vearth Z component
0350     vearth[2] = 0.;
0351 
0352     for (auto &item : vondrak)
0353     {
0354         anglev.setRadians(item[0]);
0355         anglev.SinCos(sa, ca);
0356         for (unsigned int j = 0; j < 3; j++)
0357         {
0358             vearth[j] += item[2 * j + 1] * sa + item[2 * j + 2] * ca;
0359         }
0360     }
0361 
0362     const double UA2km = 1.49597870 / 86400.; // 10^{-8}*UA/dia -> km/s
0363 
0364     for (double &item : vearth)
0365     {
0366         item *= UA2km;
0367     }
0368 }