From 9e98d0fb17ed6cc43b5841356c4f3c5b8d94487c Mon Sep 17 00:00:00 2001 From: Don Cross Date: Sun, 12 Feb 2023 16:20:33 -0500 Subject: [PATCH] PY: Implemented HourAngle function. --- demo/browser/astronomy.browser.js | 2 +- demo/nodejs/astronomy.js | 2 +- demo/python/astronomy.py | 35 ++++++++++++++++++++++ generate/template/astronomy.py | 35 ++++++++++++++++++++++ generate/template/astronomy.ts | 2 +- generate/test.py | 44 ++++++++++++++++++++++++++++ source/js/README.md | 2 +- source/js/astronomy.browser.js | 2 +- source/js/astronomy.d.ts | 2 +- source/js/astronomy.js | 2 +- source/js/astronomy.ts | 2 +- source/js/esm/astronomy.js | 2 +- source/python/README.md | 25 ++++++++++++++++ source/python/astronomy/astronomy.py | 35 ++++++++++++++++++++++ 14 files changed, 183 insertions(+), 9 deletions(-) diff --git a/demo/browser/astronomy.browser.js b/demo/browser/astronomy.browser.js index 34bfec46..0f5701f9 100644 --- a/demo/browser/astronomy.browser.js +++ b/demo/browser/astronomy.browser.js @@ -5314,7 +5314,7 @@ exports.SearchHourAngle = SearchHourAngle; * The body whose observed hour angle is to be found. * * @param {FlexibleDateTime} date - * The and and time of the observation. + * The date and time of the observation. * * @param {Observer} observer * The geographic location where the observation takes place. diff --git a/demo/nodejs/astronomy.js b/demo/nodejs/astronomy.js index 29b78ba7..bba5da54 100644 --- a/demo/nodejs/astronomy.js +++ b/demo/nodejs/astronomy.js @@ -5313,7 +5313,7 @@ exports.SearchHourAngle = SearchHourAngle; * The body whose observed hour angle is to be found. * * @param {FlexibleDateTime} date - * The and and time of the observation. + * The date and time of the observation. * * @param {Observer} observer * The geographic location where the observation takes place. diff --git a/demo/python/astronomy.py b/demo/python/astronomy.py index c96025bc..921accfb 100644 --- a/demo/python/astronomy.py +++ b/demo/python/astronomy.py @@ -6127,6 +6127,41 @@ def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1): delta_days = (delta_sidereal_hours / 24.0) * _SOLAR_DAYS_PER_SIDEREAL_DAY time = time.AddDays(delta_days) + +def HourAngle(body, time, observer): + """Finds the hour angle of a body for a given observer and time. + + The *hour angle* of a celestial body indicates its position in the sky with respect + to the Earth's rotation. The hour angle depends on the location of the observer on the Earth. + The hour angle is 0 when the body's center reaches its highest angle above the horizon in a given day. + The hour angle increases by 1 unit for every sidereal hour that passes after that point, up + to 24 sidereal hours when it reaches the highest point again. So the hour angle indicates + the number of hours that have passed since the most recent time that the body has culminated, + or reached its highest point. + + This function returns the hour angle of the body as seen at the given time and geogrpahic location. + The hour angle is a number in the half-open range [0, 24). + + Parameters + ---------- + body : Body + The body whose observed hour angle is to be found. + time : Time + The date and time of the observation. + observer : Observer + The geographic location where the observation takes place. + + Returns + ------- + float + """ + gast = SiderealTime(time) + ofdate = Equator(body, time, observer, True, True) + hourAngle = math.fmod(observer.longitude/15.0 + gast - ofdate.ra, 24.0) + if hourAngle < 0.0: + hourAngle += 24.0 + return hourAngle + @enum.unique class Direction(enum.Enum): """Indicates whether a body is rising above or setting below the horizon. diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py index bdedfa60..df34bde8 100644 --- a/generate/template/astronomy.py +++ b/generate/template/astronomy.py @@ -4621,6 +4621,41 @@ def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1): delta_days = (delta_sidereal_hours / 24.0) * _SOLAR_DAYS_PER_SIDEREAL_DAY time = time.AddDays(delta_days) + +def HourAngle(body, time, observer): + """Finds the hour angle of a body for a given observer and time. + + The *hour angle* of a celestial body indicates its position in the sky with respect + to the Earth's rotation. The hour angle depends on the location of the observer on the Earth. + The hour angle is 0 when the body's center reaches its highest angle above the horizon in a given day. + The hour angle increases by 1 unit for every sidereal hour that passes after that point, up + to 24 sidereal hours when it reaches the highest point again. So the hour angle indicates + the number of hours that have passed since the most recent time that the body has culminated, + or reached its highest point. + + This function returns the hour angle of the body as seen at the given time and geogrpahic location. + The hour angle is a number in the half-open range [0, 24). + + Parameters + ---------- + body : Body + The body whose observed hour angle is to be found. + time : Time + The date and time of the observation. + observer : Observer + The geographic location where the observation takes place. + + Returns + ------- + float + """ + gast = SiderealTime(time) + ofdate = Equator(body, time, observer, True, True) + hourAngle = math.fmod(observer.longitude/15.0 + gast - ofdate.ra, 24.0) + if hourAngle < 0.0: + hourAngle += 24.0 + return hourAngle + @enum.unique class Direction(enum.Enum): """Indicates whether a body is rising above or setting below the horizon. diff --git a/generate/template/astronomy.ts b/generate/template/astronomy.ts index 9852fabd..e8b5cb3b 100644 --- a/generate/template/astronomy.ts +++ b/generate/template/astronomy.ts @@ -5016,7 +5016,7 @@ export function SearchHourAngle( * The body whose observed hour angle is to be found. * * @param {FlexibleDateTime} date - * The and and time of the observation. + * The date and time of the observation. * * @param {Observer} observer * The geographic location where the observation takes place. diff --git a/generate/test.py b/generate/test.py index 289e36a4..1a9b593d 100755 --- a/generate/test.py +++ b/generate/test.py @@ -3131,6 +3131,49 @@ def StarRiseSetCulm(): #----------------------------------------------------------------------------------------------------------- +class HourAngleTester: + def __init__(self): + self.cases = 0 + self.maxdiff = 0.0 + + def Case(self, latitude, longitude, hourAngle): + threshold = 0.1 / 3600 # SearchHourAngle() accuracy: 0.1 seconds converted to hours + observer = astronomy.Observer(latitude, longitude, 0) + startTime = astronomy.Time.Make(2023, 2, 11, 0, 0, 0) + search = astronomy.SearchHourAngle(astronomy.Body.Sun, observer, hourAngle, startTime, +1) + calc = astronomy.HourAngle(astronomy.Body.Sun, search.time, observer) + diff = vabs(calc - hourAngle) + if diff > 12.0: + diff = 24.0 - diff; + if diff > self.maxdiff: + self.maxdiff = diff + self.cases += 1 + if diff > threshold: + print('PY HourAngleCase: EXCESSIVE ERROR = {:0.6e}, calc HA = {:0.16f}, for hourAngle={:0.1f}'.format(diff, calc, hourAngle)) + return False + Debug('PY HourAngleCase: Hour angle = {:4.1f}, longitude = {:6.1f}, diff = {:9.4e}'.format(hourAngle, longitude, diff)) + return True + + def Pass(self): + print('PY HourAngle ({:d} cases, maxdiff = {:9.4e}): PASS'.format(self.cases, self.maxdiff)) + return 0 + + +def HourAngle(): + tester = HourAngleTester() + latitude = 35 + longitude = -170 + while longitude <= 180: + hour = 0 + while hour < 24: + if not tester.Case(latitude, longitude, hour): + return 1 + hour += 1 + longitude += 5 + return tester.Pass() + +#----------------------------------------------------------------------------------------------------------- + UnitTests = { 'aberration': Aberration, 'axis': Axis, @@ -3143,6 +3186,7 @@ UnitTests = { 'global_solar_eclipse': GlobalSolarEclipse, 'gravsim': GravSimTest, 'heliostate': HelioState, + 'hour_angle': HourAngle, 'issue_103': Issue103, 'jupiter_moons': JupiterMoons, 'lagrange': Lagrange, diff --git a/source/js/README.md b/source/js/README.md index 2ff5e0f5..5fa5706c 100644 --- a/source/js/README.md +++ b/source/js/README.md @@ -1721,7 +1721,7 @@ The hour angle is a number in the half-open range [0, 24). | Param | Type | Description | | --- | --- | --- | | body | [Body](#Body) | The body whose observed hour angle is to be found. | -| date | [FlexibleDateTime](#FlexibleDateTime) | The and and time of the observation. | +| date | [FlexibleDateTime](#FlexibleDateTime) | The date and time of the observation. | | observer | [Observer](#Observer) | The geographic location where the observation takes place. | diff --git a/source/js/astronomy.browser.js b/source/js/astronomy.browser.js index 34bfec46..0f5701f9 100644 --- a/source/js/astronomy.browser.js +++ b/source/js/astronomy.browser.js @@ -5314,7 +5314,7 @@ exports.SearchHourAngle = SearchHourAngle; * The body whose observed hour angle is to be found. * * @param {FlexibleDateTime} date - * The and and time of the observation. + * The date and time of the observation. * * @param {Observer} observer * The geographic location where the observation takes place. diff --git a/source/js/astronomy.d.ts b/source/js/astronomy.d.ts index c37c3f8f..6db0fbd3 100644 --- a/source/js/astronomy.d.ts +++ b/source/js/astronomy.d.ts @@ -1794,7 +1794,7 @@ export declare function SearchHourAngle(body: Body, observer: Observer, hourAngl * The body whose observed hour angle is to be found. * * @param {FlexibleDateTime} date - * The and and time of the observation. + * The date and time of the observation. * * @param {Observer} observer * The geographic location where the observation takes place. diff --git a/source/js/astronomy.js b/source/js/astronomy.js index 29b78ba7..bba5da54 100644 --- a/source/js/astronomy.js +++ b/source/js/astronomy.js @@ -5313,7 +5313,7 @@ exports.SearchHourAngle = SearchHourAngle; * The body whose observed hour angle is to be found. * * @param {FlexibleDateTime} date - * The and and time of the observation. + * The date and time of the observation. * * @param {Observer} observer * The geographic location where the observation takes place. diff --git a/source/js/astronomy.ts b/source/js/astronomy.ts index 6ca327da..444ca68d 100644 --- a/source/js/astronomy.ts +++ b/source/js/astronomy.ts @@ -5944,7 +5944,7 @@ export function SearchHourAngle( * The body whose observed hour angle is to be found. * * @param {FlexibleDateTime} date - * The and and time of the observation. + * The date and time of the observation. * * @param {Observer} observer * The geographic location where the observation takes place. diff --git a/source/js/esm/astronomy.js b/source/js/esm/astronomy.js index 7d883d67..8e7da8be 100644 --- a/source/js/esm/astronomy.js +++ b/source/js/esm/astronomy.js @@ -5248,7 +5248,7 @@ export function SearchHourAngle(body, observer, hourAngle, dateStart, direction * The body whose observed hour angle is to be found. * * @param {FlexibleDateTime} date - * The and and time of the observation. + * The date and time of the observation. * * @param {Observer} observer * The geographic location where the observation takes place. diff --git a/source/python/README.md b/source/python/README.md index cda90a42..870fa34b 100644 --- a/source/python/README.md +++ b/source/python/README.md @@ -1864,6 +1864,31 @@ and is expressed in astronomical units (AU). --- + +### HourAngle(body, time, observer) + +**Finds the hour angle of a body for a given observer and time.** + +The *hour angle* of a celestial body indicates its position in the sky with respect +to the Earth's rotation. The hour angle depends on the location of the observer on the Earth. +The hour angle is 0 when the body's center reaches its highest angle above the horizon in a given day. +The hour angle increases by 1 unit for every sidereal hour that passes after that point, up +to 24 sidereal hours when it reaches the highest point again. So the hour angle indicates +the number of hours that have passed since the most recent time that the body has culminated, +or reached its highest point. +This function returns the hour angle of the body as seen at the given time and geogrpahic location. +The hour angle is a number in the half-open range [0, 24). + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Body`](#Body) | `body` | The body whose observed hour angle is to be found. | +| [`Time`](#Time) | `time` | The date and time of the observation. | +| [`Observer`](#Observer) | `observer` | The geographic location where the observation takes place. | + +**Returns**: `float` + +--- + ### IdentityMatrix() diff --git a/source/python/astronomy/astronomy.py b/source/python/astronomy/astronomy.py index c96025bc..921accfb 100644 --- a/source/python/astronomy/astronomy.py +++ b/source/python/astronomy/astronomy.py @@ -6127,6 +6127,41 @@ def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1): delta_days = (delta_sidereal_hours / 24.0) * _SOLAR_DAYS_PER_SIDEREAL_DAY time = time.AddDays(delta_days) + +def HourAngle(body, time, observer): + """Finds the hour angle of a body for a given observer and time. + + The *hour angle* of a celestial body indicates its position in the sky with respect + to the Earth's rotation. The hour angle depends on the location of the observer on the Earth. + The hour angle is 0 when the body's center reaches its highest angle above the horizon in a given day. + The hour angle increases by 1 unit for every sidereal hour that passes after that point, up + to 24 sidereal hours when it reaches the highest point again. So the hour angle indicates + the number of hours that have passed since the most recent time that the body has culminated, + or reached its highest point. + + This function returns the hour angle of the body as seen at the given time and geogrpahic location. + The hour angle is a number in the half-open range [0, 24). + + Parameters + ---------- + body : Body + The body whose observed hour angle is to be found. + time : Time + The date and time of the observation. + observer : Observer + The geographic location where the observation takes place. + + Returns + ------- + float + """ + gast = SiderealTime(time) + ofdate = Equator(body, time, observer, True, True) + hourAngle = math.fmod(observer.longitude/15.0 + gast - ofdate.ra, 24.0) + if hourAngle < 0.0: + hourAngle += 24.0 + return hourAngle + @enum.unique class Direction(enum.Enum): """Indicates whether a body is rising above or setting below the horizon.