Solar Position
PVGIS features API functions
for each and every elementary solar positioning angle.
To start we launch an interactive i/python session
Where ?¶
Define the geographic location and the positioning of our solar surface
Native objects for coordinates¶
We can also use PVGIS' native classes Longitude and Latitude
for the coordinates. We can import them as every other Python module
and create objects
inspect them
and use them as in the following example
>>> from pvgis import Longitude
>>> Longitude(value=8.628)
>>> longitude = Longitude(value=8.628, unit="degrees")
Let's see what is in the longitude variable
value=8.628 unit='degrees' min_radians=-3.141592653589793 max_radians=3.141592653589793 min_degrees=-180 max_degrees=180 symbol='Λ' desription="The angle between a point on the Earth's surface and the meridian plane, with its value ranging from 0° at the Prime Meridian in Greenwich, England, to 180° east or west."
Tip
The Longitude and Latitude data classes have some functionality
such as converting from degrees to radians and vice versa just by calling
its attribute .radians or .degrees. Such methods make it easier to
write programs on top of PVGIS and not only.
When ?¶
Prepare a series of timestamps as a Pandas DatetimeIndex,
using our helper function generate_datetime_series
>>> from pvgis.api.datetime.datetimeindex import generate_datetime_series
>>> timestamps = generate_datetime_series(start_time="2010-01-27 08:00:00", end_time="2010-01-27 18:00:00", frequency="h")
and the default UTC timezone as a ZoneInfo object
Let's confirm the generation of the timestamps and the timezone :
timestamps=DatetimeIndex(['2010-01-27 08:00:00', '2010-01-27 09:00:00', '2010-01-27 10:00:00', '2010-01-27 11:00:00', '2010-01-27 12:00:00', '2010-01-27 13:00:00', '2010-01-27 14:00:00', '2010-01-27 15:00:00', '2010-01-27 16:00:00', '2010-01-27 17:00:00', '2010-01-27 18:00:00'], dtype='datetime64[us]', freq='h')
utc_zone=zoneinfo.ZoneInfo(key='UTC')
Solar altitude¶
>>> from pvgis.api.position.altitude import calculate_solar_altitude_series
>>> calculate_solar_altitude_series
We can see the required arguments to run the command
Error Handling¶
Let's give it a first try with some reasonable input values for longitude,
latitude and timestamps plus timezone
Failure
>>> from pydantic import ValidationError
>>> try:
... calculate_solar_altitude_series(8, 45, '2001-01-01 10:00:00', 'UTC')
... except ValidationError as exc:
... print(exc)
6 validation errors for ModelSolarAltitudeTimeSeriesInputModel
timestamps.is-instance[DatetimeIndex]
Input should be an instance of DatetimeIndex [type=is_instance_of, input_value='2001-01-01 10:00:00', input_type=str]
For further information visit https://errors.pydantic.dev/2.12/v/is_instance_of
timestamps.is-instance[Timestamp]
Input should be an instance of Timestamp [type=is_instance_of, input_value='2001-01-01 10:00:00', input_type=str]
For further information visit https://errors.pydantic.dev/2.12/v/is_instance_of
latitude.constrained-float
Input should be less than or equal to 1.5707963267948966 [type=less_than_equal, input_value=45, input_type=int]
For further information visit https://errors.pydantic.dev/2.12/v/less_than_equal
latitude.Latitude
Input should be a valid dictionary or instance of Latitude [type=model_type, input_value=45, input_type=int]
For further information visit https://errors.pydantic.dev/2.12/v/model_type
longitude.constrained-float
Input should be less than or equal to 3.141592653589793 [type=less_than_equal, input_value=8, input_type=int]
For further information visit https://errors.pydantic.dev/2.12/v/less_than_equal
longitude.Longitude
Input should be a valid dictionary or instance of Longitude [type=model_type, input_value=8, input_type=int]
For further information visit https://errors.pydantic.dev/2.12/v/model_type
PVGIS' API is indeed idiomatic and our reasonable inputs won't work ! However, the input arguments are validated via Pydantic and thus we receive informative error messages.
Speaking PVGIS' API language¶
Let's import the required modules
>>> from pandas import Timestamp
>>> from zoneinfo import ZoneInfo
>>> from pvgis.api.utilities.conversions import convert_float_to_radians_if_requested
Setting the input parameters
>>> longitude = convert_float_to_radians_if_requested(8, 'radians')
>>> latitude = convert_float_to_radians_if_requested(45, 'radians')
>>> timestamps=Timestamp('2001-01-01 10:00:00+00:00')
>>> timezone=ZoneInfo('UTC')
And re-run the calculation
>>> solar_altitude = calculate_solar_altitude_series(longitude=longitude, latitude=latitude, timestamps=timestamps, timezone=timezone)
>>> print(f"Solar altitude from PVGIS' API : {solar_altitude}")
Solar altitude from PVGIS' API : {'noaa': {<SolarPositionParameter.timing: 'time_algorithm'>: 'NOAA', <SolarPositionParameter.positioning: 'position_algorithm'>: 'NOAA', <SolarPositionParameter.altitude: 'altitude'>: array([0.32986832], dtype=float32), 'unit': None}}
Solar Azimuth¶
We can calculate solar azimuth angles
for a specific geographic location and over a time series
with the API function model_solar_azimuth_series().
Help¶
What exactly can we do with it ?
We can use the Python built-in function help to find out
Or indeed, in an interactive ipython session, it suffices to use a ? right
after the function name and without space
More Imports¶
>>> from math import radians
>>> from pvgis.api.datetime.datetimeindex import generate_datetime_series
>>> timestamps = generate_datetime_series(start_time='2010-01-27', end_time='2010-01-28')
>>> from zoneinfo import ZoneInfo
Calculate solar azimuth time series for the 27th January 2010
>>> model_solar_azimuth_series(
... longitude=radians(longitude),
... latitude=radians(latitude),
... timestamps=timestamps,
... timezone=ZoneInfo("UTC"),
... apply_atmospheric_refraction=True
... )
The above command returns a PVGIS-native data class SolarAzimuth.
Of course we can feed the result to a new variable
and print or re-use it for further processing
>>> solar_azimuth_series = model_solar_azimuth_series(
... longitude=radians(longitude),
... latitude=radians(latitude),
... timestamps=timestamps,
... timezone=ZoneInfo("UTC"),
... apply_atmospheric_refraction=True
... )
>>> print(solar_azimuth_series)
value=array([0.20324278, 0.68162394, 1.0347457 , 1.2956886 , 1.5057368 , 1.6915469 , 1.8700204 , 2.0612493 , 2.250216 , 2.466558 , 2.7086406 , 2.975184 , 3.2346225 , 3.5088406 , 3.7576592 , 3.9807858 , 4.1786404 , 4.3685203 , 4.547683 , 4.73073 , 4.933111 , 5.178298 , 5.503539 , 5.949113 , 0.19983101], dtype=float32) unit='radians' position_algorithm='NOAA' timing_algorithm='NOAA' definition='Solar azimuth angle' description='Solar azimuth angle' origin='North' min_radians=0 max_radians=6.283185307179586 min_degrees=0 max_degrees=360
Convert output to degrees
Note, most PVGIS data classes feature a standard .degrees method
-- it'll convert the values to geographic degrees :
[ 11.644953 39.054173 59.286556 74.23749 86.27236 96.918495 107.14427 118.100876 128.92787 141.32335 155.19366 170.46547 185.3302 201.04175 215.298 228.08221 239.41844 250.29776 260.56302 271.05084 282.64642 296.6946 315.32956 340.85904 11.449472]