Track the maximum recursion depth in FindAscent.
Count the number of times the altitude_diff function is called.
These are important performance statistics that I want to
measure, so I can try a few optimization ideas.
Current results:
don@spearmint:~/github/astronomy/generate $ ./generate source && ./ctbuild && ./ctest -v riseset
./ctbuild: C compiler = gcc
./ctbuild: Built 'ctest' program.
C RiseSet: Moon lat=-61.0 lon=103.0
C RiseSet: Moon lat=-45.0 lon=150.0
C RiseSet: Moon lat=29.0 lon=-81.0
C RiseSet: Moon lat=80.0 lon=130.0
C RiseSet: Moon lat=83.0 lon=105.0
C RiseSet: Moon lat=84.0 lon=125.0
C RiseSet: Moon lat=85.0 lon=135.0
C RiseSet: Moon lat=85.0 lon=140.0
C RiseSet: Sun lat=-90.0 lon=0.0
C RiseSet: Sun lat=-88.0 lon=45.0
C RiseSet: Sun lat=-60.0 lon=-150.0
C RiseSet: Sun lat=15.0 lon=75.0
C RiseSet: Sun lat=29.0 lon=-81.0
C RiseSet: Sun lat=60.0 lon=0.0
C RiseSet: Sun lat=89.0 lon=30.0
C RiseSet: Sun lat=90.0 lon=0.0
C RiseSet: passed 5909 lines: time errors in minutes: rms=0.2904, max=1.1541, recur=19, altcount=171438
This is a whole new algorithm that efficiently finds
all rise/set events, even near the poles.
It uses a recursive bisection search that limits
recursion depth by knowing the maximum possible
|da/dt| = change in altitude with respect to time.
Finding apparent angular radius by dividing body radius
by distance is not quite as accurate as taking the
arcsine of the same ratio. Changed this for a slightly
more accurate answer.
Refactored so there is a single altitude function/context pair
instead of separate ones for SearchAltitude and SearchRiseSet.
This allows InternalSearchAltitude to fully understand the
problem to be solved, and also makes the code smaller.
InternalSearchAltitude will need to perform min/max altitude
calculations, which means it needs to know all the parameters
of the altitude search directly. They are no longer hidden
inside an opaque function pointer and context.
So now SearchAltitude and SearchRiseSet no longer create
contexts, nor pass in a function pointer. They just
pass the correct numeric parameters to the generic solver
InternalSearchAltitude, which packs the parameters into
the context for Search().
Unified the two context types into a single context type,
and the two callback functions into a single callback function.
Updated the version number so I can create a new
npm package to test the pull request from @matheo
that should allow TypeScript types to be exported correctly.
Apparently you have to put CodeQL paths-ignore statements
in a separate yml file from the GitHub Actions workflow yml,
and point to it by name. Trying that here.
Updated CodeQL config to ignore source templates,
because they are not syntactically valid source code.
Ignore other stuff that is irrelevant to published
code quality.
Made various fixes based on helpful CodeQL analysis.
The rise/set search based on hour angles is complicated,
and doesn't handle oddities that happen close to the poles.
I'm starting to rework rise/set as a more brute force solution
that iterates through finite time steps.
I also added a series of Moon data for the arctic circle,
which includes some of the more painful special cases.
For example:
Moon 130 80 2034-05-16T13:21Z s
Moon 130 80 2034-05-16T13:51Z r
Here the Moon sets, then rises 30 minutes later.
So now I'm trying to figure out how to discover
arbitrarily brief intervals like this.
I want the time increments to scale intelligently
so that we don't waste time during long periods
of inactivity (body above or below the horizon continuously),
but without missing examples like the one above.
Added sunrise/sunset test data for locations
at or near the poles. This causes rise/set tests to fail.
I need to fix these cases!
Observations:
1. Sunrise/sunset at the poles has nothing to do with
the Earth's rotation. It is based only on the Sun's
declination. Therefore, it makes no sense to look
at hour angles there.
2. At the poles, there is no such thing as a meridian.
For example, at the north pole, no matter which way
you turn, you are facing south!
So the very notion of hour angles is meaningless.
3. At the poles, there is a single sunrise and a single sunset
per calendar year. The sun rises near the spring solstice
for that hemisphere, and sets near the autumn solstice.
4. Near the poles, sunrise/sunset behavior gets more complicated.
It is possible for there to be more than one sunset or sunrise
per 24-hour period, because of changes of Sun declination.
When parsing the rise/set data, the Linux
`sort` utility had weird behavior. Fixed it
by making parse_riseset.py do its own sorting
in an order that makes sense, before writing
to riseset.txt.
I use a variety of doxygen versions among the systems
that run the unit tests, including my personal development
systems and GitHub Actions.
Older versions of doxygen complain about options in Doxyfile
they don't know about.
Newer versions of doxygen complain about obsolete options in Doxyfile.
I'm trying to get rid of all these noisy warnings by pruning
all options in Doxyfile that are equivalent to their default
values. I only keep the options that I need to be different
from the default.
Hopefully this quiets down the warnings.
The Windows version of the GitHub Actions tests require
downloading Doxygen binaries. Every now and then this
step would break when Doxygen updates their version numbers.
Added a Python script to scrape the Doxygen website to
determine the correct URL to download.
commit_hook.bat calls the Python script to determine
the URL, so I don't have to keep manually updating it.
This is my second attempt to release eclipse obscuration.
I discovered there was a missing unit test for obscuration
for lunar eclipses in the Kotlin library. It has been added.
For consistency, I now calculate the Sun's apparent position
correcting for aberration, for lunar eclipses and transits.
This didn't make much difference for accuracy.
Before correcting for Sun aberration:
$ ./ctest transit
C TransitFile(eclipse/mercury.txt ): PASS - verified 94, max minutes = 10.709, max sep arcmin = 0.2120
C TransitFile(eclipse/venus.txt ): PASS - verified 30, max minutes = 9.108, max sep arcmin = 0.6772
$ ./ctest -v lunar_fraction
C LunarFractionCase(2010-06-26) fraction error = 0.00900991
C LunarFractionCase(2012-06-04) fraction error = 0.00491535
C LunarFractionCase(2013-04-25) fraction error = 0.00143039
C LunarFractionCase(2017-08-07) fraction error = 0.00682336
C LunarFractionCase(2019-07-16) fraction error = 0.00572727
C LunarFractionCase(2021-11-19) fraction error = 0.00350680
C LunarFractionCase(2023-10-28) fraction error = 0.00370518
C LunarFractionCase(2024-09-18) fraction error = 0.00429906
C LunarFractionCase(2026-08-28) fraction error = 0.00322697
C LunarFractionCase(2028-01-12) fraction error = 0.00405870
C LunarFractionCase(2028-07-06) fraction error = 0.00857840
C LunarFractionCase(2030-06-15) fraction error = 0.00557106
C LunarFractionTest: PASS
After correcting for Sun aberration:
$ ./ctest transit
C TransitFile(eclipse/mercury.txt ): PASS - verified 94, max minutes = 10.709, max sep arcmin = 0.2120
C TransitFile(eclipse/venus.txt ): PASS - verified 30, max minutes = 9.108, max sep arcmin = 0.6772
$ ./ctest -v lunar_fraction
C LunarFractionCase(2010-06-26) fraction error = 0.00762932
C LunarFractionCase(2012-06-04) fraction error = 0.00606322
C LunarFractionCase(2013-04-25) fraction error = 0.00111560
C LunarFractionCase(2017-08-07) fraction error = 0.00571542
C LunarFractionCase(2019-07-16) fraction error = 0.00713913
C LunarFractionCase(2021-11-19) fraction error = 0.00298979
C LunarFractionCase(2023-10-28) fraction error = 0.00448445
C LunarFractionCase(2024-09-18) fraction error = 0.00367044
C LunarFractionCase(2026-08-28) fraction error = 0.00405559
C LunarFractionCase(2028-01-12) fraction error = 0.00347340
C LunarFractionCase(2028-07-06) fraction error = 0.00729982
C LunarFractionCase(2030-06-15) fraction error = 0.00680776
C LunarFractionTest: PASS
C function Astronomy_SearchLocalSolarEclipse now reports
obscuration for the peak of a solar eclipse seen at a given location.
Some of the test data from aa.usno.navy.mil looks suspiciously inaccurate.
I am finding better agreement with Fred Espenak's eclipsewise.com and
Xavier M. Jubier's xjubier.free.fr online calculators.
The larger obscuration differences are from aa.usno.navy.mil:
don@spearmint:~/github/astronomy/generate $ ./ctest -v solar_fraction
C GlobalAnnularCase(2023-10-14) obscuration error = 0.00009036, expected = 0.90638000, calculated = 0.90647036
C GlobalAnnularCase(2024-10-02) obscuration error = 0.00005246, expected = 0.86975000, calculated = 0.86980246
C GlobalAnnularCase(2027-02-06) obscuration error = 0.00007237, expected = 0.86139000, calculated = 0.86146237
C GlobalAnnularCase(2028-01-26) obscuration error = 0.00003656, expected = 0.84787000, calculated = 0.84790656
C GlobalAnnularCase(2030-06-01) obscuration error = 0.00008605, expected = 0.89163000, calculated = 0.89171605
C LocalSolarCase(2023-10-14) obscuration diff = 0.00006323, expected = 0.90638000, calculated = 0.90644323
C LocalSolarCase(2023-10-14) obscuration diff = -0.00521043, expected = 0.57800000, calculated = 0.57278957
C LocalSolarCase(2024-04-08) obscuration diff = 0.00000000, expected = 1.00000000, calculated = 1.00000000
C LocalSolarCase(2024-04-08) obscuration diff = 0.00304558, expected = 0.34000000, calculated = 0.34304558
C LocalSolarCase(2024-10-02) obscuration diff = 0.00007858, expected = 0.86975000, calculated = 0.86982858
C LocalSolarCase(2024-10-02) obscuration diff = -0.00343797, expected = 0.43600000, calculated = 0.43256203
C LocalSolarCase(2030-06-01) obscuration diff = 0.00007259, expected = 0.89163000, calculated = 0.89170259
C LocalSolarCase(2030-06-01) obscuration diff = -0.00059871, expected = 0.67240000, calculated = 0.67180129
C SolarFractionTest: PASS
I am going to rework using xjubier.free.fr in a subsequent commit.
Fixed bug in internal C function Obscuration().
It was not calculating obscuration correctly when
the second disc is completely inside the first disc,
i.e. the annular solar eclipse case.
Added C/C++ calculation of obscuration for global solar
eclipses that are total or annular at their peak
location and time. Obscuration is not calculated
for partial solar eclipses by SearchGlobalSolarEclipse.
Soon SearchLocalSolarEclipse will calculate obscuration
for partial solar eclipses at the geographic location
provided by the caller.
Starting to add support for calculating the intensity
of lunar eclipses and solar eclipses in terms of "obscuration".
This commit adds calculation of obscuration for lunar eclipses
in C/C++. The structure returned by SearchLunarEclipse and
NextLunarEclipse now includes an `obscuration` field whose value
is in the range [0, 1], indicating what fraction of the Moon's
apparent disc is covered by the Earth's umbra at the eclipse's peak.
I ported the NOVAS C 3.1 functions julian_date and cal_date to Python,
and removed the dependence on the standard datetime class for calculating UT.
Now we can create Time objects for a much wider range of year values.
Simplified the julian_date formula in C and C#.
In the Python version, I had to account for a difference
in the way integer division works for negative numbers.
In Python, integer division always rounds down, not toward
zero like it does in C/C#. So I reworked the formulas to
avoid dividing a negative integer (month-14), dividing the
positive quantity (14-month) instead and toggling addition
of the term with subtraction of the term.
I use the reworked (14-month) version in C and C# for consistency.
Also, the formatting of the formula was wacky and didn't make sense,
so now it easier to read and understand.
The Python regex for parsing dates has been expanded to allow
years before 0 and after 9999.
Allow converting Python Time to string for years before 0 and after 9999.
The .NET type System.DateTime is limited to the years 0000..9999.
The Astronomy Engine type AstroTime was using System.DateTime to
convert a (year, month, day, hour, minute, second) tuple into a
fractional day value. This caused an exception for years outside
the supported range 0000..9999.
I ported the NOVAS C 3.1 functions julian_date and cal_date to C#,
and removed the dependence on System.DateTime.
Now we can create AstroTime for a much wider range of year values.
Allow converting AstroTime to string for years before 0 and after 9999.