Skip to content

Add get_meteonorm_tmy iotools function #2066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/sphinx/source/reference/iotools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ of sources and file formats relevant to solar energy modeling.
iotools.get_solcast_forecast
iotools.get_solcast_live
iotools.get_solargis
iotools.get_meteonorm_tmy


A :py:class:`~pvlib.location.Location` object may be created from metadata
Expand Down
2 changes: 2 additions & 0 deletions docs/sphinx/source/whatsnew/v0.11.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Deprecations

Enhancements
~~~~~~~~~~~~
* Add :py:func:`pvlib.iotools.get_meteonorm_tmy` for retrieving
Meteonorm weather and solar irradiance data. (:pull:`2066`)


Bug fixes
Expand Down
1 change: 1 addition & 0 deletions pvlib/iotools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@
from pvlib.iotools.solcast import get_solcast_historic # noqa: F401
from pvlib.iotools.solcast import get_solcast_tmy # noqa: F401
from pvlib.iotools.solargis import get_solargis # noqa: F401
from pvlib.iotools.meteonorm import get_meteonorm_tmy # noqa: F401
109 changes: 109 additions & 0 deletions pvlib/iotools/meteonorm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""Functions to read and retrieve Meteonorm data."""

import requests
import pandas as pd

URL = 'https://mdx.meteotest.ch/api_v1'


@dataclass
class ParameterMap:
meteonorm_name: str
pvlib_name: str
conversion: callable = lambda x: x


# define the conventions between Meteonorm and pvlib nomenclature and units
VARIABLE_MAP = [
# 'Gh' is GHI without horizon effects
ParameterMap('Gh hor', 'ghi'),
ParameterMap('Gh max', 'ghi_clear'),
ParameterMap('Bn', 'dni'),
ParameterMap('Bh', 'bhi'),
# 'Dh' is 'DHI' without horizon effects
ParameterMap('Dh hor', 'dhi'),
ParameterMap('Dh min ', 'dhi_clear'),
# Check units of wind stuff XXX
ParameterMap('DD', 'wind_direction'),
ParameterMap('FF', 'wind_speed'),
ParameterMap('rh', 'relative_humidity'),
# surface_pressure (hPa) -> pressure (Pa)
ParameterMap('p', 'pressure', lambda x: x*100),
ParameterMap('w', 'precipitable_water'), # cm
ParameterMap('aot', 'aod'),
ParameterMap('hs', 'solar_elevation'),
ParameterMap('az', 'solar_azimuth'),
ParameterMap('rho', 'albedo'),
ParameterMap('ta', 'temp_air'),
ParameterMap('td', 'temp_dew'),
]

# inclination, azimuth, parameters, randomseed (default is 1), local situation, horname (optional, =auto -> topographic horizon)


def get_meteonorm_tmy(latitude, longitude, *, api_key, altitude=None,
parameters=None, map_variables=True, URL=URL):
"""Get irradiance and weather for a Typical Meteorological Year (TMY) at a
requested location.

Parameters
----------
latitude : float
in decimal degrees, between -90 and 90, north is positive
longitude : float
in decimal degrees, between -180 and 180, east is positive
api_key : str
To access Meteonorm data you will need an API key [2]_.
map_variables: bool, default: True
When true, renames columns of the DataFrame to pvlib variable names
where applicable. See variable :const:`VARIABLE_MAP`.
altitude : float, optional
DESCRIPTION.
parameters : list, optional
DESCRIPTION.

Raises
------
requests
DESCRIPTION.

Returns
-------
data : pandas.DataFrame
DESCRIPTION.
meta : dict
DESCRIPTION.

"""
params = {
'key': api_key,
'service': 'meteonorm',
'action': 'calculatestandard',
'lat': latitude,
'lon': longitude,
'format': 'json',
}

# Optional variable, defaults to XXX
if altitude is not None:
params['altitude'] = altitude

response = requests.get(URL, params=params)

if not response.ok:
raise requests.HTTPError(response.json())

data = pd.DataFrame(response.json()['payload']['meteonorm']['target']).T
meta = response.json()['payload']['_metadata']

# rename and convert variables
for variable in VARIABLE_MAP:
if variable.meteonorm_name in data.columns:
data.rename(
columns={variable.meteonorm_name: variable.pvlib_name},
inplace=True
)
data[variable.pvlib_name] = data[
variable.pvlib_name].apply(variable.conversion)

return data, meta