Package: helisol
Abouthelisolis a Python 3 package that calculates precisely the earth trajectory (tilt, longitude, true anomaly etc.) and absolute and apparent sun position (declination, right ascension, height above horizon, azimuth etc.) in the sky seen from any specified position on Earth and at any time. Sunset, solar noon, and sunrise times are also provided. It uses Meeus' equations including perturbations from planets on the earth orbit.Earthdescribes the motion of earth around the sunSundescribes the position of the sun seen from earth, irrespective of exact location on earth (declination, equation of time, etc.)SunObservationdescribes the position of the sun in the sky as observed at a given location on earth (azimuth, height, etc.).The package also includes tools to store and manipulate angles (Angleclass) and times (Timeclass), and a function to calculate refraction effects (refraction()).SeeExampleShadow.ipynbfor an example on how to use the package to calculate the shadow of an object at different times of the year.SOON:Sundial calculation and generationPrecisioncan be evaluated by comparison to published ephemerids. We have used ephemerids for March 2023 for sunset / sunrise and solar noon, and ephemerids for August 2023 for right ascension, declination and equation of time (see test file).Sunset, sunrise and solar noon are within the displayed precision of each other (1 second for noon, 1 minute for sunset/sunrise)Right ascension and equation of time are within the displayed precision of each other (1 second in time)Declination deviates less than 2.5 arc-seconds (0.0007°, or 0.17 seconds in time).Sun to Earth distance deviates less than 1600 km; extracted aphelion and perihelion dates extracted from the extrema of this distance seem to be off by a few hours depending on the year.InstallpipinstallhelisolUsageEarth position and orbitfromhelisolimportEarth# Get current axial tilt and true anomaly of the earthearth=Earth()earth.true_anomalyearth.orbit.axial_tilt# Get properties at a given dateearth=Earth('Sept. 9, 2003')# Update to current timeearth.update()# Update to specific timeearth.update(utc_time='2023-03-21, 12:00')# Min and max sun-eath distanceEarth(2019).orbit.perihelion()# specific yearEarth().orbit.aphelion()# current yearSun absolute positionfromhelisolimportSun# Get current sun positionsun=Sun()sun.declinationsun.right_ascensionsun.equation_of_time# Access earth object associated with sunsun.earth# Get sun at specific UTC time and then update to current timesun=Sun('March 3, 13:30')sun.update()Sun viewed from given location on earthfromhelisolimportSunObservation# Get current position of the sun# NOTE: location can be a tuple of coords, a location name (if stored in the# JSON database), or a location object (see below).obs=Sun(location=(42.4,-76.5))print(obs)# Some info (azimuth height, sunrise etc. is printed here)# Update position to current timeobs.update()print(obs)# Update position to specified time and dateobs.update(utc_time='Jan 6, 2023, 4:25:03pm')print(obs.height)# Height above horizon, in degreesprint(obs.azimuth)# azimuth with respect to south in degrees# It is possible to specify time upon instantiation directly:obs=Sun(location=(42.4,-76.5),utc_time='2023-1-6, 16:25:03')# sunrise, noon (meridian), sunset [center of sun, no refraction]print(obs.sunrise,obs.noon,obs.sunset)# To include refraction and other options to calculate sunrise / sunset:obs.actual_sunrise()# [top of sun, with refraction]obs.actual_sunrise(point='center')# [center of sun, with refraction]obs.actual_sunrise(refract=False,point='bottom')# [sun bottom, no refract]obs.actual_sunrise(obstacle=Angle(26))# with an obstacle of 26° of height# The method also exists for sunset:obs.actual_sunset()# (NOTE: options for the precision of the calculation also exists, see docstring)# Access sun object associated with the observation:obs.sunAnglesfromhelisolimportAngle,sin,cos,tana=Angle(degrees=30.7)sin(a)a.sin()# equivalent to line aboveb=Angle(radians=np.pi/4)tan(b)c=Angle(degrees=3,minutes=45,seconds=10)# °, ', "cos(c)d=Angle(hms=(8,44,43))# in hours, min, sece=Angle.arctan(1)# pi/4# Allowed operationsa+ba-ba*22*aa/2-aa<ba==b# and other comparisons# And combinations, e.g.(a-b)/4cos(2*a-b)# access values in different units (decimal)a.radiansa.degrees# Read-only info on minutes and seconds of anglea.minutesa.seconds# Read_only info on time in hours (min/sec):a.hmsIf having performance issues withAngle, it is possible to increase speed by shortcutting tests of units during instantiation, using more specializedAnglesubclasses:fromhelisolimportAngleFromDegrees,AngleFromRadiansfromhelisolimportAngleFromMinutes,AngleFromSecondsa=AngleFromDegrees(30)b=AngleFromRadians(np.pi/6)c=AngleFromMinutes(1.5)d=90*AngleFromSeconds(1)a-b+c-dIt is also possible to use arrays with theAngleArrayclass, e.g.fromhelisolimportAngleArraya=AngleArray(degrees=[44.5,2.5,3],minutes=[30,30,0])a.tan()DistancesDistances are managed by theDistanceclassfromhelisolimportDistanced=Distance(au=2.5)# 2.5 astronomical unitsd.md.kmd.auDate / timesfromhelisolimportTimetime=Time(utc_time='2022, July 3, 6:12')time.utc# datetime with no timezone (implicitly UTC)time.julian_years# Julian years since Jan 1 2000, 12:00time.fraction_of_day# 0 for midnight, 0.5 for noon# It is possible to manually adjust the fraction of day to set the time:time.fraction_of_day=0.5# It is also possible to instantiate a Time object with a fraction of daytime=Time(utc_time='2023, March 10',fraction_of_day=0.25)# 6am# To obtain a rounded version of time:time.rounded_to('second')time.rounded_to('minute')RefractionfromhelisolimportAngle,refraction# When true height is at horizon level (29' approx.)refraction(true_height=Angle(0))# When apparent height is at horizon level (34' approx)refraction(apparent_height=Angle(0))# At arbitrary true height or apparent heightsrefraction(Angle(23))# true height of 23 degreesrefraction(true_height=Angle(degrees=23))# same thingrefraction(apparent_height=Angle(minutes=66))# apparent height of 10'Generate tables of dataIt is possible to generate tables (pandas DataFrames) containing sun position data, or sunset/sunrise data between selected dates and with selected frequency, with the functions:generate_table()extend_table()sunset_table()(see docstrings for help and examples).Location managementIt is possible to save/load location information with theLocationclass.FromhelisolimportLocation,SunObservation# Load existing location and use it to instantiate a Sun objectlocation=Location.load('Home')obs=SunObservation(location)# equivalently:obs=SunObservation('Home')# It is possible to configure a default location in config.py (default 'Home')# so that one can do justSunObservation()# Define custom location and save it in the database# NOTE: it is possible to define elevation, although not used in helisol at# the moment.location=Location(name='Work',coords=(40.78,-73.97))location.save()# save in a non-shared file (excluded from version )location.save('global')# save in globals.json file, version controlled.# Remove location from database:location.remove('Work')RequirementsPython >= 3.7PackagesnumpypandasoclockAuthorOlivier Vincent
(ovinc.py@gmail.com)ContributorsGilbert Vincent (equations and advice)ReferencesMeeus, J.,Calculs astronomiques à l’usage des amateurs, Société astronomique de France (2014).Saemundsson, T.,Astronomical Refraction, Sky and Telescope,72, 70 (1986).Bennett, G. G.,The calculation of astronomical refraction in marine navigation, Journal of Navigation,35, 255-259 (1982).LicenseGNU GPLv3, seeLICENSEfile