From 246ac47d2b07a8f72d86d066fece46c2f5972d04 Mon Sep 17 00:00:00 2001 From: Don Cross Date: Fri, 18 Dec 2020 14:29:41 -0500 Subject: [PATCH] Fixed a failure to find a full moon using certain start dates. In all four versions of Astronomy Engine (C, C#, JavaScript, and Python), starting a search for a full moon near December 19, 2020 would fail. I added a unit test to all four languages and it failed consistently across them all. The root cause: I was too optimistic about how narrow I could make the window around the approximate moon phase time in the SearchMoonPhase functions. Finding the exact moon phase time failed because it was outside this excessively small window around the approximate time. I increased the window from 1.8 days to 3.0 days. This should handle all cases with minimal impact on performance. Now all four of the new unit tests pass. --- demo/browser/astronomy.js | 6 ++--- demo/c/test/moonphase_correct.txt | 2 +- demo/csharp/test/moonphase_correct.txt | 6 ++--- demo/nodejs/astronomy.js | 6 ++--- demo/nodejs/test/moonphase_correct.txt | 2 +- demo/python/astronomy.py | 6 ++--- demo/python/test/moonphase_correct.txt | 6 ++--- generate/ctest.c | 28 +++++++++++++++++++++- generate/dotnet/csharp_test/csharp_test.cs | 20 ++++++++++++++++ generate/template/astronomy.c | 6 ++--- generate/template/astronomy.cs | 6 ++--- generate/template/astronomy.js | 6 ++--- generate/template/astronomy.py | 6 ++--- generate/test.js | 16 +++++++++++++ generate/test.py | 18 ++++++++++++++ source/c/astronomy.c | 6 ++--- source/csharp/astronomy.cs | 6 ++--- source/js/astronomy.js | 6 ++--- source/js/astronomy.min.js | 2 +- source/python/astronomy.py | 6 ++--- 20 files changed, 123 insertions(+), 43 deletions(-) diff --git a/demo/browser/astronomy.js b/demo/browser/astronomy.js index 74a71668..70249aa2 100644 --- a/demo/browser/astronomy.js +++ b/demo/browser/astronomy.js @@ -3645,11 +3645,11 @@ Astronomy.SearchMoonPhase = function(targetLon, dateStart, limitDays) { // that every lunar phase repeats roughly every 29.5 days. // There is a surprising uncertainty in the quarter timing, // due to the eccentricity of the moon's orbit. - // I have seen up to 0.826 days away from the simple prediction. + // I have seen more than 0.9 days away from the simple prediction. // To be safe, we take the predicted time of the event and search - // +/-0.9 days around it (a 1.8-day wide window). + // +/-1.5 days around it (a 3.0-day wide window). // But we must return null if the final result goes beyond limitDays after dateStart. - const uncertainty = 0.9; + const uncertainty = 1.5; let ta = Astronomy.MakeTime(dateStart); let ya = moon_offset(ta); diff --git a/demo/c/test/moonphase_correct.txt b/demo/c/test/moonphase_correct.txt index b4b812d6..5b044970 100644 --- a/demo/c/test/moonphase_correct.txt +++ b/demo/c/test/moonphase_correct.txt @@ -4,7 +4,7 @@ The next 10 lunar quarters are: 2019-06-17T08:31:18Z : Full Moon 2019-06-25T09:47:08Z : Third Quarter 2019-07-02T19:16:47Z : New Moon -2019-07-09T10:55:28Z : First Quarter +2019-07-09T10:55:29Z : First Quarter 2019-07-16T21:38:54Z : Full Moon 2019-07-25T01:18:43Z : Third Quarter 2019-08-01T03:12:26Z : New Moon diff --git a/demo/csharp/test/moonphase_correct.txt b/demo/csharp/test/moonphase_correct.txt index 9b6da72d..7d37366d 100644 --- a/demo/csharp/test/moonphase_correct.txt +++ b/demo/csharp/test/moonphase_correct.txt @@ -1,13 +1,13 @@ 2019-06-15T09:15:32.987Z : Moon's phase angle = 156.100612 degrees. The next 10 lunar quarters are: -2019-06-17T08:31:17.978Z : Full Moon +2019-06-17T08:31:17.934Z : Full Moon 2019-06-25T09:47:07.624Z : Third Quarter 2019-07-02T19:16:46.550Z : New Moon -2019-07-09T10:55:28.132Z : First Quarter +2019-07-09T10:55:28.849Z : First Quarter 2019-07-16T21:38:53.691Z : Full Moon 2019-07-25T01:18:42.697Z : Third Quarter 2019-08-01T03:12:26.152Z : New Moon -2019-08-07T17:31:36.307Z : First Quarter +2019-08-07T17:31:35.717Z : First Quarter 2019-08-15T12:29:57.164Z : Full Moon 2019-08-23T14:56:46.202Z : Third Quarter diff --git a/demo/nodejs/astronomy.js b/demo/nodejs/astronomy.js index 74a71668..70249aa2 100644 --- a/demo/nodejs/astronomy.js +++ b/demo/nodejs/astronomy.js @@ -3645,11 +3645,11 @@ Astronomy.SearchMoonPhase = function(targetLon, dateStart, limitDays) { // that every lunar phase repeats roughly every 29.5 days. // There is a surprising uncertainty in the quarter timing, // due to the eccentricity of the moon's orbit. - // I have seen up to 0.826 days away from the simple prediction. + // I have seen more than 0.9 days away from the simple prediction. // To be safe, we take the predicted time of the event and search - // +/-0.9 days around it (a 1.8-day wide window). + // +/-1.5 days around it (a 3.0-day wide window). // But we must return null if the final result goes beyond limitDays after dateStart. - const uncertainty = 0.9; + const uncertainty = 1.5; let ta = Astronomy.MakeTime(dateStart); let ya = moon_offset(ta); diff --git a/demo/nodejs/test/moonphase_correct.txt b/demo/nodejs/test/moonphase_correct.txt index cb87d037..46124366 100644 --- a/demo/nodejs/test/moonphase_correct.txt +++ b/demo/nodejs/test/moonphase_correct.txt @@ -4,7 +4,7 @@ The next 10 lunar quarters are: 2019-06-17 08:31:18 UTC : Full Moon 2019-06-25 09:47:08 UTC : Third Quarter 2019-07-02 19:16:47 UTC : New Moon -2019-07-09 10:55:28 UTC : First Quarter +2019-07-09 10:55:29 UTC : First Quarter 2019-07-16 21:38:54 UTC : Full Moon 2019-07-25 01:18:43 UTC : Third Quarter 2019-08-01 03:12:26 UTC : New Moon diff --git a/demo/python/astronomy.py b/demo/python/astronomy.py index 30a7b1f5..4da13de9 100644 --- a/demo/python/astronomy.py +++ b/demo/python/astronomy.py @@ -4620,11 +4620,11 @@ def SearchMoonPhase(targetLon, startTime, limitDays): # that every lunar phase repeats roughly every 29.5 days. # There is a surprising uncertainty in the quarter timing, # due to the eccentricity of the moon's orbit. - # I have seen up to 0.826 days away from the simple prediction. + # I have seen more than 0.9 days away from the simple prediction. # To be safe, we take the predicted time of the event and search - # +/-0.9 days around it (a 1.8-day wide window). + # +/-1.5 days around it (a 3-day wide window). # But we must return None if the final result goes beyond limitDays after startTime. - uncertainty = 0.9 + uncertainty = 1.5 ya = _moon_offset(targetLon, startTime) if ya > 0.0: ya -= 360.0 # force searching forward in time, not backward diff --git a/demo/python/test/moonphase_correct.txt b/demo/python/test/moonphase_correct.txt index 9b6da72d..7d37366d 100644 --- a/demo/python/test/moonphase_correct.txt +++ b/demo/python/test/moonphase_correct.txt @@ -1,13 +1,13 @@ 2019-06-15T09:15:32.987Z : Moon's phase angle = 156.100612 degrees. The next 10 lunar quarters are: -2019-06-17T08:31:17.978Z : Full Moon +2019-06-17T08:31:17.934Z : Full Moon 2019-06-25T09:47:07.624Z : Third Quarter 2019-07-02T19:16:46.550Z : New Moon -2019-07-09T10:55:28.132Z : First Quarter +2019-07-09T10:55:28.849Z : First Quarter 2019-07-16T21:38:53.691Z : Full Moon 2019-07-25T01:18:42.697Z : Third Quarter 2019-08-01T03:12:26.152Z : New Moon -2019-08-07T17:31:36.307Z : First Quarter +2019-08-07T17:31:35.717Z : First Quarter 2019-08-15T12:29:57.164Z : Full Moon 2019-08-23T14:56:46.202Z : Third Quarter diff --git a/generate/ctest.c b/generate/ctest.c index 979e1d49..563ce511 100644 --- a/generate/ctest.c +++ b/generate/ctest.c @@ -81,6 +81,7 @@ static const char *ParseJplHorizonsDateTime(const char *text, astro_time_t *time static int VectorDiff(astro_vector_t a, astro_vector_t b, double *diff); static int RefractionTest(void); static int ConstellationTest(void); +static int LunarEclipseIssue78(void); static int LunarEclipseTest(void); static int GlobalSolarEclipseTest(void); static int PlotDeltaT(const char *outFileName); @@ -109,6 +110,7 @@ static unit_test_t UnitTests[] = {"global_solar_eclipse", GlobalSolarEclipseTest}, {"local_solar_eclipse", LocalSolarEclipseTest}, {"lunar_eclipse", LunarEclipseTest}, + {"lunar_eclipse_78", LunarEclipseIssue78}, {"magnitude", MagnitudeTest}, {"moon", MoonTest}, {"moon_apsis", LunarApsis}, @@ -1871,7 +1873,7 @@ static int Rotation_MatrixInverse(void) b = Astronomy_InverseRotation(a); CHECK(CompareMatrices("Rotation_MatrixInverse", b, v, 0.0)); - printf("Rotation_MatrixInverse: PASS\n"); + printf("C Rotation_MatrixInverse: PASS\n"); error = 0; fail: @@ -2546,6 +2548,30 @@ static void PrintTime(astro_time_t time) printf("%04d-%02d-%02dT%02d:%02d:%06.3lfZ", utc.year, utc.month, utc.day, utc.hour, utc.minute, utc.second); } +static int LunarEclipseIssue78(void) +{ + int error; + astro_lunar_eclipse_t eclipse; + astro_time_t search_time = Astronomy_MakeTime(2020, 12, 19, 0, 0, 0.0); + astro_time_t expected_peak = Astronomy_MakeTime(2021, 5, 26, 11, 18, 42); /* https://www.timeanddate.com/eclipse/lunar/2021-may-26 */ + double dt_seconds; + + eclipse = Astronomy_SearchLunarEclipse(search_time); + CHECK_STATUS(eclipse); + + dt_seconds = (24.0 * 3600.0) * ABS(eclipse.peak.tt - expected_peak.tt); + if (dt_seconds > 40.0) + FAIL("C LunarEclipseIssue78: Excessive prediction error = %lf seconds.\n", dt_seconds); + + if (eclipse.kind != ECLIPSE_TOTAL) + FAIL("C LunarEclipseIssue78: Expected total eclipse; found %d\n", eclipse.kind); + + printf("C LunarEclipseIssue78: PASS\n"); + error = 0; +fail: + return error; +} + static int LunarEclipseTest(void) { const char *filename = "eclipse/lunar_eclipse.txt"; diff --git a/generate/dotnet/csharp_test/csharp_test.cs b/generate/dotnet/csharp_test/csharp_test.cs index 36349768..b783bfbc 100644 --- a/generate/dotnet/csharp_test/csharp_test.cs +++ b/generate/dotnet/csharp_test/csharp_test.cs @@ -40,6 +40,7 @@ namespace csharp_test new Test("local_solar_eclipse", LocalSolarEclipseTest), new Test("lunar_apsis", LunarApsisTest), new Test("lunar_eclipse", LunarEclipseTest), + new Test("lunar_eclipse_78", LunarEclipseIssue78), new Test("magnitude", MagnitudeTest), new Test("moonphase", MoonPhaseTest), new Test("planet_apsis", PlanetApsisTest), @@ -1676,6 +1677,25 @@ namespace csharp_test return 0; } + static int LunarEclipseIssue78() + { + LunarEclipseInfo eclipse = Astronomy.SearchLunarEclipse(new AstroTime(2020, 12, 19, 0, 0, 0)); + var expected_peak = new AstroTime(2021, 5, 26, 11, 18, 42); // https://www.timeanddate.com/eclipse/lunar/2021-may-26 + double dt_seconds = (24.0 * 3600.0) * abs(expected_peak.tt - eclipse.peak.tt); + if (dt_seconds > 40.0) + { + Console.WriteLine("C# LunarEclipseIssue78: Excessive prediction error = {0} seconds.", dt_seconds); + return 1; + } + if (eclipse.kind != EclipseKind.Total) + { + Console.WriteLine("C# LunarEclipseIssue78: Expected total eclipse; found {0}", eclipse.kind); + return 1; + } + Console.WriteLine("C# LunarEclipseIssue78: PASS"); + return 0; + } + static int LunarEclipseTest() { const string filename = "../../eclipse/lunar_eclipse.txt"; diff --git a/generate/template/astronomy.c b/generate/template/astronomy.c index f5e5e9d7..cf8f7948 100644 --- a/generate/template/astronomy.c +++ b/generate/template/astronomy.c @@ -3709,12 +3709,12 @@ astro_search_result_t Astronomy_SearchMoonPhase(double targetLon, astro_time_t s that every lunar phase repeats roughly every 29.5 days. There is a surprising uncertainty in the quarter timing, due to the eccentricity of the moon's orbit. - I have seen up to 0.826 days away from the simple prediction. + I have seen more than 0.9 days away from the simple prediction. To be safe, we take the predicted time of the event and search - +/-0.9 days around it (a 1.8-day wide window). + +/-1.5 days around it (a 3-day wide window). Return ASTRO_NO_MOON_QUARTER if the final result goes beyond limitDays after startTime. */ - const double uncertainty = 0.9; + const double uncertainty = 1.5; astro_func_result_t funcres; double ya, est_dt, dt1, dt2; astro_time_t t1, t2; diff --git a/generate/template/astronomy.cs b/generate/template/astronomy.cs index 0d893415..31c2016f 100644 --- a/generate/template/astronomy.cs +++ b/generate/template/astronomy.cs @@ -3758,13 +3758,13 @@ $ASTRO_IAU_DATA() that every lunar phase repeats roughly every 29.5 days. There is a surprising uncertainty in the quarter timing, due to the eccentricity of the moon's orbit. - I have seen up to 0.826 days away from the simple prediction. + I have seen more than 0.9 days away from the simple prediction. To be safe, we take the predicted time of the event and search - +/-0.9 days around it (a 1.8-day wide window). + +/-1.5 days around it (a 3-day wide window). Return null if the final result goes beyond limitDays after startTime. */ - const double uncertainty = 0.9; + const double uncertainty = 1.5; var moon_offset = new SearchContext_MoonOffset(targetLon); double ya = moon_offset.Eval(startTime); diff --git a/generate/template/astronomy.js b/generate/template/astronomy.js index 42d60279..03bf8295 100644 --- a/generate/template/astronomy.js +++ b/generate/template/astronomy.js @@ -2788,11 +2788,11 @@ Astronomy.SearchMoonPhase = function(targetLon, dateStart, limitDays) { // that every lunar phase repeats roughly every 29.5 days. // There is a surprising uncertainty in the quarter timing, // due to the eccentricity of the moon's orbit. - // I have seen up to 0.826 days away from the simple prediction. + // I have seen more than 0.9 days away from the simple prediction. // To be safe, we take the predicted time of the event and search - // +/-0.9 days around it (a 1.8-day wide window). + // +/-1.5 days around it (a 3.0-day wide window). // But we must return null if the final result goes beyond limitDays after dateStart. - const uncertainty = 0.9; + const uncertainty = 1.5; let ta = Astronomy.MakeTime(dateStart); let ya = moon_offset(ta); diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py index fc8f11b4..bf726892 100644 --- a/generate/template/astronomy.py +++ b/generate/template/astronomy.py @@ -2723,11 +2723,11 @@ def SearchMoonPhase(targetLon, startTime, limitDays): # that every lunar phase repeats roughly every 29.5 days. # There is a surprising uncertainty in the quarter timing, # due to the eccentricity of the moon's orbit. - # I have seen up to 0.826 days away from the simple prediction. + # I have seen more than 0.9 days away from the simple prediction. # To be safe, we take the predicted time of the event and search - # +/-0.9 days around it (a 1.8-day wide window). + # +/-1.5 days around it (a 3-day wide window). # But we must return None if the final result goes beyond limitDays after startTime. - uncertainty = 0.9 + uncertainty = 1.5 ya = _moon_offset(targetLon, startTime) if ya > 0.0: ya -= 360.0 # force searching forward in time, not backward diff --git a/generate/test.js b/generate/test.js index ef9d6685..cef17b9b 100644 --- a/generate/test.js +++ b/generate/test.js @@ -279,6 +279,21 @@ function LunarApsis() { } +function LunarEclipseIssue78() { + // https://github.com/cosinekitty/astronomy/issues/78 + + let eclipse = Astronomy.SearchLunarEclipse(new Date(Date.UTC(2020, 11, 19))); + const expected_peak = new Date('2021-05-26T11:18:42Z'); // https://www.timeanddate.com/eclipse/lunar/2021-may-26 + const dt = (expected_peak - eclipse.peak.date) / 1000; + if (abs(dt) > 40.0) + throw `LunarEclipseIssue78: Excessive prediction error = ${dt} seconds.`; + if (eclipse.kind !== 'total') + throw `Expected total eclipse; found: ${eclipse.kind}`; + console.log(`JS LunarEclipseIssue78: PASS`); + return 0; +} + + function LunarEclipse() { Astronomy.CalcMoonCount = 0; const filename = 'eclipse/lunar_eclipse.txt'; @@ -1737,6 +1752,7 @@ const UnitTests = { local_solar_eclipse: LocalSolarEclipse, lunar_apsis: LunarApsis, lunar_eclipse: LunarEclipse, + lunar_eclipse_78: LunarEclipseIssue78, planet_apsis: PlanetApsis, pluto: PlutoCheck, magnitude: Magnitude, diff --git a/generate/test.py b/generate/test.py index ac3da15f..53aa6da9 100755 --- a/generate/test.py +++ b/generate/test.py @@ -1140,6 +1140,23 @@ def Constellation(): #----------------------------------------------------------------------------------------------------------- +def LunarEclipseIssue78(): + # https://github.com/cosinekitty/astronomy/issues/78 + + eclipse = astronomy.SearchLunarEclipse(astronomy.Time.Make(2020, 12, 19, 0, 0, 0)) + expected_peak = astronomy.Time.Make(2021, 5, 26, 11, 18, 42) # https://www.timeanddate.com/eclipse/lunar/2021-may-26 + dt = (expected_peak.tt - eclipse.peak.tt) * (24.0 * 3600.0) + if vabs(dt) > 40.0: + print('LunarEclipseIssue78: Excessive prediction error = {} seconds.'.format(dt)) + return 1 + if eclipse.kind != astronomy.EclipseKind.Total: + print('Expected total eclipse; found: {}'.format(eclipse.kind)) + return 1 + print('PY LunarEclipseIssue78: PASS') + return 0 + +#----------------------------------------------------------------------------------------------------------- + def LunarEclipse(): astronomy._CalcMoonCount = 0 filename = 'eclipse/lunar_eclipse.txt' @@ -1575,6 +1592,7 @@ UnitTests = { 'local_solar_eclipse': LocalSolarEclipse, 'lunar_apsis': LunarApsis, 'lunar_eclipse': LunarEclipse, + 'lunar_eclipse_78': LunarEclipseIssue78, 'magnitude': Magnitude, 'moon': GeoMoon, 'moonphase': MoonPhase, diff --git a/source/c/astronomy.c b/source/c/astronomy.c index bd0a7e1d..dc43d517 100644 --- a/source/c/astronomy.c +++ b/source/c/astronomy.c @@ -4761,12 +4761,12 @@ astro_search_result_t Astronomy_SearchMoonPhase(double targetLon, astro_time_t s that every lunar phase repeats roughly every 29.5 days. There is a surprising uncertainty in the quarter timing, due to the eccentricity of the moon's orbit. - I have seen up to 0.826 days away from the simple prediction. + I have seen more than 0.9 days away from the simple prediction. To be safe, we take the predicted time of the event and search - +/-0.9 days around it (a 1.8-day wide window). + +/-1.5 days around it (a 3-day wide window). Return ASTRO_NO_MOON_QUARTER if the final result goes beyond limitDays after startTime. */ - const double uncertainty = 0.9; + const double uncertainty = 1.5; astro_func_result_t funcres; double ya, est_dt, dt1, dt2; astro_time_t t1, t2; diff --git a/source/csharp/astronomy.cs b/source/csharp/astronomy.cs index 3abbb217..ce8aa8fa 100644 --- a/source/csharp/astronomy.cs +++ b/source/csharp/astronomy.cs @@ -4814,13 +4814,13 @@ namespace CosineKitty that every lunar phase repeats roughly every 29.5 days. There is a surprising uncertainty in the quarter timing, due to the eccentricity of the moon's orbit. - I have seen up to 0.826 days away from the simple prediction. + I have seen more than 0.9 days away from the simple prediction. To be safe, we take the predicted time of the event and search - +/-0.9 days around it (a 1.8-day wide window). + +/-1.5 days around it (a 3-day wide window). Return null if the final result goes beyond limitDays after startTime. */ - const double uncertainty = 0.9; + const double uncertainty = 1.5; var moon_offset = new SearchContext_MoonOffset(targetLon); double ya = moon_offset.Eval(startTime); diff --git a/source/js/astronomy.js b/source/js/astronomy.js index 74a71668..70249aa2 100644 --- a/source/js/astronomy.js +++ b/source/js/astronomy.js @@ -3645,11 +3645,11 @@ Astronomy.SearchMoonPhase = function(targetLon, dateStart, limitDays) { // that every lunar phase repeats roughly every 29.5 days. // There is a surprising uncertainty in the quarter timing, // due to the eccentricity of the moon's orbit. - // I have seen up to 0.826 days away from the simple prediction. + // I have seen more than 0.9 days away from the simple prediction. // To be safe, we take the predicted time of the event and search - // +/-0.9 days around it (a 1.8-day wide window). + // +/-1.5 days around it (a 3.0-day wide window). // But we must return null if the final result goes beyond limitDays after dateStart. - const uncertainty = 0.9; + const uncertainty = 1.5; let ta = Astronomy.MakeTime(dateStart); let ya = moon_offset(ta); diff --git a/source/js/astronomy.min.js b/source/js/astronomy.min.js index 23011114..ea3d83d3 100644 --- a/source/js/astronomy.min.js +++ b/source/js/astronomy.min.js @@ -145,7 +145,7 @@ b.y,b.z);for(b=a.elon-b.elon;0>b;)b+=360;for(;360<=b;)b-=360;return b};e.AngleFr else if("Moon"===a){a=.017453292519943295*d;var m=a*a;a=-12.717+1.49*Math.abs(a)+.0431*m*m;a+=5*Math.log10(f/.002573570052980638*l)}else if("Saturn"===a)a=d,h=e.Ecliptic(k.x,k.y,k.z),m=.017453292519943295*h.elat,h=Math.asin(Math.sin(m)*Math.cos(.4897393881096089)-Math.cos(m)*Math.sin(.4897393881096089)*Math.sin(.017453292519943295*h.elon-.017453292519943295*(169.51+3.82E-5*c.tt))),m=Math.sin(Math.abs(h)),a=-9+.044*a+m*(-2.6+1.2*m)+5*Math.log10(l*f),h*=57.29577951308232;else{var g=m=0,n=0;switch(a){case "Mercury":a= -.6;m=4.98;g=-4.88;n=3.02;break;case "Venus":163.6>d?(a=-4.47,m=1.03,g=.57,n=.13):(a=.98,m=-1.02);break;case "Mars":a=-1.52;m=1.6;break;case "Jupiter":a=-9.4;m=.5;break;case "Uranus":a=-7.19;m=.25;break;case "Neptune":a=-6.87;break;case "Pluto":a=-1;m=4;break;default:throw"VisualMagnitude: unsupported body "+a;}var p=d/100;a=a+p*(m+p*(g+p*n))+5*Math.log10(l*f)}return new cb(c,a,d,l,f,k,b,h)};e.SearchRelativeLongitude=function(a,b,c){function d(c){var d=e.EclipticLongitude(a,c);c=e.EclipticLongitude("Earth", c);return I(f*(c-d)-b)}q(b);var k=y[a];if(!k)throw"Cannot search relative longitude because body is not a planet: "+a;if("Earth"===a)throw"Cannot search relative longitude for the Earth (it is always 0)";var f=k.OrbitalPeriod>y.Earth.OrbitalPeriod?1:-1;k=O(a);c=e.MakeTime(c);var l=d(c);0h;++h){var m=-l/360*k;c=c.AddDays(m);if(1>86400*Math.abs(m))return c;m=l;l=d(c);30>Math.abs(m)&&m!==l&&(m/=m-l,.5m&&(k*=m))}throw"Relative longitude search failed to converge for "+ -a+" near "+c.toString()+" (error_angle = "+l+").";};e.MoonPhase=function(a){return e.LongitudeFromSun("Moon",a)};e.SearchMoonPhase=function(a,b,c){function d(b){b=e.MoonPhase(b);return I(b-a)}q(a);q(c);b=e.MakeTime(b);var k=d(b);0c)return null;c=Math.min(c,f+.9);k=b.AddDays(k);b=b.AddDays(c);return e.Search(d,k,b)};var db=function(a,b){this.quarter=a;this.time=b};e.SearchMoonQuarter=function(a){var b=e.MoonPhase(a);b=(Math.floor(b/90)+1)%4;return(a= +a+" near "+c.toString()+" (error_angle = "+l+").";};e.MoonPhase=function(a){return e.LongitudeFromSun("Moon",a)};e.SearchMoonPhase=function(a,b,c){function d(b){b=e.MoonPhase(b);return I(b-a)}q(a);q(c);b=e.MakeTime(b);var k=d(b);0c)return null;c=Math.min(c,f+1.5);k=b.AddDays(k);b=b.AddDays(c);return e.Search(d,k,b)};var db=function(a,b){this.quarter=a;this.time=b};e.SearchMoonQuarter=function(a){var b=e.MoonPhase(a);b=(Math.floor(b/90)+1)%4;return(a= e.SearchMoonPhase(90*b,a,10))&&new db(b,a)};e.NextMoonQuarter=function(a){a=new Date(a.time.date.getTime()+5184E5);return e.SearchMoonQuarter(a)};e.SearchRiseSet=function(a,b,c,d,k){function f(d){var g=e.Equator(a,d,b,!0,!0);d=e.Horizon(d,b,g.ra,g.dec).altitude+l/g.dist*57.29577951308232+ab;return c*d}K(b);q(k);var l={Sun:.0046504672612422675,Moon:1.1618480877914597E-5}[a]||0;if("Earth"===a)throw"Cannot find rise or set time of the Earth.";if(1===c){var h=12;var m=0}else if(-1===c)h=0,m=12;else throw"Astronomy.SearchRiseSet: Invalid direction parameter "+ c+" -- must be +1 or -1";d=e.MakeTime(d);var g=f(d);var n;if(0=g&&0=d.ut+k)return null;p=g.time;g=f(g.time);n=f(r.time)}};var eb=function(a,b){this.time=a;this.hor=b};e.SearchHourAngle=function(a,b,c,d){K(b);d=e.MakeTime(d);var k=0;if("Earth"=== a)throw"Cannot search for hour angle of the Earth.";q(c);if(0>c||24<=c)throw"Invalid hour angle "+c;for(;;){++k;var f=J(d),l=e.Equator(a,d,b,!0,!0);f=(c+l.ra-b.longitude/15-f)%24;1===k?0>f&&(f+=24):-12>f?f+=24:123600*Math.abs(f))return a=e.Horizon(d,b,l.ra,l.dec,"normal"),new eb(d,a);d=d.AddDays(f/24*.9972695717592592)}};var fb=function(a,b,c,d){this.mar_equinox=a;this.jun_solstice=b;this.sep_equinox=c;this.dec_solstice=d};e.Seasons=function(a){function b(b,c,d){c=new Date(Date.UTC(a, diff --git a/source/python/astronomy.py b/source/python/astronomy.py index 30a7b1f5..4da13de9 100644 --- a/source/python/astronomy.py +++ b/source/python/astronomy.py @@ -4620,11 +4620,11 @@ def SearchMoonPhase(targetLon, startTime, limitDays): # that every lunar phase repeats roughly every 29.5 days. # There is a surprising uncertainty in the quarter timing, # due to the eccentricity of the moon's orbit. - # I have seen up to 0.826 days away from the simple prediction. + # I have seen more than 0.9 days away from the simple prediction. # To be safe, we take the predicted time of the event and search - # +/-0.9 days around it (a 1.8-day wide window). + # +/-1.5 days around it (a 3-day wide window). # But we must return None if the final result goes beyond limitDays after startTime. - uncertainty = 0.9 + uncertainty = 1.5 ya = _moon_offset(targetLon, startTime) if ya > 0.0: ya -= 360.0 # force searching forward in time, not backward