-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add retrieval function for ERA5 reanalysis data #1264
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
Open
AdamRJensen
wants to merge
44
commits into
pvlib:main
Choose a base branch
from
AdamRJensen:era5
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
8e8661c
Create era5.py
AdamRJensen 25662a4
Update era5.py
AdamRJensen f6bc57e
Update era5.py
AdamRJensen 57eecb5
Update era5.py
AdamRJensen c135481
Fix stickler
AdamRJensen f4e9242
Add xarray and cdsapi to requirements and setup.py
AdamRJensen af3067e
Remove grib support and update variable_map
AdamRJensen b2c400c
Fix stickler
AdamRJensen bb62d7f
Add era5 to api.rst, __init__, and whatsnewfile
AdamRJensen 9f6b15f
Fix error in __init__.py
AdamRJensen 9a22c04
Change parse to read in __init__.py
AdamRJensen 21bedd1
Update get_era5 documentation
AdamRJensen 6c76efd
Merge remote-tracking branch 'upstream/master' into era5
AdamRJensen 3422ddf
Improve docs and use open_mfdataset in read_era5
AdamRJensen 545bafa
Coverage for ERA5 incl. test file
AdamRJensen 8ed6df5
Export CDSAPI_KEY in conda_linux.yml
AdamRJensen 041732f
Fix stickler
AdamRJensen 93bd4ec
Install xarray with pip in requirements-py36
AdamRJensen 519b060
Include xarray in TEST_REQUIRE in setup.py
AdamRJensen b732c76
Add UID to era5 tests
AdamRJensen 4c911ac
Add requires_xarray to conftest.py
AdamRJensen f1b83a2
Renaming get_era5 inputs
AdamRJensen 7a13531
Updated CDSAPI_KEY usage
AdamRJensen 87b6a50
Extend test coverage
AdamRJensen bff7299
Add dask as optional dependency
AdamRJensen 5de52bc
Update documentation
AdamRJensen 0721f15
More documentation updates
AdamRJensen 2e90c67
Extend parsed metadata
AdamRJensen 9f0a624
Coverage for output_format parameter
AdamRJensen 7921666
Fix stickler
AdamRJensen 03e4a5f
Update description of test_get_cams_bad_request
AdamRJensen 5e1db86
Implement changes from review by kanderso-nrel
AdamRJensen dd443e4
Remove cds_client input parameter
AdamRJensen c25780e
Localize dataframe and add helper functions to pvlib.tools
AdamRJensen 5a00ad5
Reformat imports of non-standard packages
AdamRJensen 46f38c1
Set quit=True in cds_client and add depdencies in whatsnew
AdamRJensen cde8a4a
Rename variables before extracting metadata
AdamRJensen 3f96eec
Change file_location to file_url and remove lat/lon offset
AdamRJensen 6cd44b1
Merge branch 'master' into era5
AdamRJensen 5db2fef
Remove has_tables from conftest.py
AdamRJensen f6443fc
Merge branch 'era5' of https://github.com/AdamRJensen/pvlib-python in…
AdamRJensen 6534c66
Revert "Merge branch 'era5' of https://github.com/AdamRJensen/pvlib-p…
AdamRJensen 3ae5327
Revert back to 3f96eec
AdamRJensen faa5a45
Merge remote-tracking branch 'upstream/master' into era5
AdamRJensen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,277 @@ | ||
"""Functions to retreive and read ERA5 data from the CDS. | ||
.. codeauthor:: Adam R. Jensen<[email protected]> | ||
""" | ||
# The functions only support single-level 2D data and not 3D / pressure-level | ||
# data. Also, monthly datasets and grib files are no supported. | ||
|
||
import requests | ||
from pvlib.tools import (_extract_metadata_from_dataset, | ||
_convert_C_to_K_in_dataset) | ||
|
||
try: | ||
import cdsapi | ||
except ImportError: | ||
cdsapi = None | ||
|
||
try: | ||
import xarray as xr | ||
except ImportError: | ||
xr = None | ||
|
||
# The returned data uses shortNames, whereas the request requires variable | ||
# names according to the CDS convention - passing shortNames results in an | ||
# "Ambiguous" error being raised | ||
ERA5_DEFAULT_VARIABLES = [ | ||
'2m_temperature', # t2m | ||
'10m_u_component_of_wind', # u10 | ||
'10m_v_component_of_wind', # v10 | ||
'surface_pressure', # sp | ||
'mean_surface_downward_short_wave_radiation_flux', # msdwswrf | ||
'mean_surface_downward_short_wave_radiation_flux_clear_sky', # msdwswrfcs | ||
'mean_surface_direct_short_wave_radiation_flux', # msdrswrf | ||
'mean_surface_direct_short_wave_radiation_flux_clear_sky', # msdrswrfcs | ||
] | ||
|
||
ERA5_VARIABLE_MAP = { | ||
't2m': 'temp_air', | ||
'd2m': 'temp_dew', | ||
'sp': 'pressure', | ||
'msdwswrf': 'ghi', | ||
'msdwswrfcs': 'ghi_clear', | ||
'msdwlwrf': 'lwd', | ||
'msdwlwrfcs': 'lwd_clear', | ||
'msdrswrf': 'bhi', | ||
'msdrswrfcs': 'bhi_clear', | ||
'mtdwswrf': 'ghi_extra'} | ||
|
||
ERA5_HOURS = [ | ||
'00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', | ||
'08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', | ||
'16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00'] | ||
|
||
CDSAPI_URL = 'https://cds.climate.copernicus.eu/api/v2' | ||
|
||
|
||
def get_era5(latitude, longitude, start, end, api_key=None, | ||
variables=ERA5_DEFAULT_VARIABLES, | ||
dataset='reanalysis-era5-single-levels', | ||
product_type='reanalysis', grid=(0.25, 0.25), save_path=None, | ||
output_format=None, map_variables=True): | ||
""" | ||
Retrieve ERA5 reanalysis data from the Copernicus Data Store (CDS). | ||
|
||
* Temporal coverage: 1979 to present (latency of ~5 days) | ||
* Temporal resolution: hourly | ||
* Spatial coverage: global | ||
* Spatial resolution: 0.25° by 0.25° | ||
|
||
An overview of ERA5 is given in [1]_ and [2]_. Data is retrieved using the | ||
CDSAPI [3]_. | ||
|
||
.. admonition:: Time reference | ||
|
||
ERA5 time stamps are in UTC and corresponds to the end of the period | ||
(right labeled). E.g., the time stamp 12:00 for hourly data refers to | ||
the period from 11:00 to 12:00. | ||
|
||
.. admonition:: Usage notes | ||
|
||
To use this function the package CDSAPI [4]_ needs to be installed | ||
[3]_. The CDSAPI keywords are described in [5]_. | ||
|
||
Requested variables should be specified according to the naming | ||
convention used by the CDS. The returned data contains the short-name | ||
versions of the variables. See [2]_ for a list of variables names and | ||
units. | ||
|
||
Access to the CDS requires user registration, see [6]_. The obtaining | ||
API key can either be passed directly to the function or be saved in a | ||
local file as described in [3]_. | ||
|
||
It is possible to check your | ||
`request status <https://cds.climate.copernicus.eu/cdsapp#!/yourrequests>`_ | ||
and the `status of all queued requests <https://cds.climate.copernicus.eu/live/queue>`_. | ||
|
||
Parameters | ||
---------- | ||
latitude: float or list | ||
in decimal degrees, between -90 and 90, north is positive (ISO 19115). | ||
If latitude is a list, it should have the format [S, N] and | ||
latitudes within the range are selected according to the grid. | ||
longitude: float or list | ||
in decimal degrees, between -180 and 180, east is positive (ISO 19115). | ||
If longitude is a list, it should have the format [W, E] and | ||
longitudes within the range are selected according to the grid. | ||
start: datetime like | ||
First day of the requested period | ||
end: datetime like | ||
Last day of the requested period | ||
api_key: str, optional | ||
Personal API key for the CDS with the format "uid:key" e.g. | ||
'00000:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' | ||
variables: list, default: ERA5_DEFAULT_VARIABLES | ||
List of variables to retrieve (according to CDS naming convention) | ||
dataset: str, default 'reanalysis-era5-single-levels' | ||
Name of the dataset to retrieve the variables from. Can be either | ||
'reanalysis-era5-single-levels' or 'reanalysis-era5-land'. | ||
product_type: str, {'reanalysis', 'ensemble_members', 'ensemble_mean', 'ensemble_spread'}, default: 'reanalysis' | ||
ERA5 product type | ||
grid: list or tuple, default: (0.25, 0.25) | ||
User specified grid resolution | ||
save_path: str or path-like, optional | ||
Filename of where to save data. Should have ".nc" extension. | ||
output_format: {'dataframe', 'dataset'}, optional | ||
Type of data object to return. Default is to return a pandas DataFrame | ||
if file only contains one location and otherwise return an xarray | ||
Dataset. | ||
map_variables: bool, default: True | ||
When true, renames columns of the DataFrame to pvlib variable names | ||
where applicable. See variable ERA5_VARIABLE_MAP. | ||
|
||
Notes | ||
----- | ||
The returned data includes the following fields by default: | ||
|
||
======================== ====== ========================================= | ||
Key, mapped key Format Description | ||
======================== ====== ========================================= | ||
*Mapped field names are returned when the map_variables argument is True* | ||
--------------------------------------------------------------------------- | ||
2tm, temp_air float Air temperature at 2 m above ground [K] | ||
u10 float Horizontal airspeed towards east at 10 m [m/s] | ||
v10 float Horizontal airspeed towards north at 10 m [m/s] | ||
sp, pressure float Atmospheric pressure at the ground [Pa] | ||
msdwswrf, ghi float Mean surface downward short-wave radiation flux [W/m^2] | ||
msdwswrfcs, ghi_clear float Mean surface downward short-wave radiation flux, clear sky [W/m^2] | ||
msdrswrf, bhi float Mean surface direct short-wave radiation flux [W/m^2] | ||
msdrswrfcs, bhi_clear float Mean surface direct short-wave radiation flux, clear sky [W/m^2] | ||
======================== ====== ========================================= | ||
|
||
Returns | ||
------- | ||
data: DataFrame | ||
ERA5 time-series data, fields depend on the requested data. The | ||
returned object is either a pandas DataFrame or an xarray dataset, | ||
depending on the output_format parameter. | ||
metadata: dict | ||
Metadata for the time-series. | ||
|
||
See Also | ||
-------- | ||
pvlib.iotools.read_era5 | ||
|
||
References | ||
---------- | ||
.. [1] `ERA5 hourly data on single levels from 1979 to present | ||
<https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels?tab=overview>`_ | ||
.. [2] `ERA5 data documentation | ||
<https://confluence.ecmwf.int/display/CKB/ERA5%3A+data+documentation>`_ | ||
.. [3] `How to use the CDS API | ||
<https://cds.climate.copernicus.eu/api-how-to>`_ | ||
.. [4] `CDSAPI source code | ||
<https://github.com/ecmwf/cdsapi>`_ | ||
.. [5] `Climate Data Store (CDS) API Keywords | ||
<https://confluence.ecmwf.int/display/CKB/Climate+Data+Store+%28CDS%29+API+Keywords>`_ | ||
.. [6] `Climate Data Storage user registration | ||
<https://cds.climate.copernicus.eu/user/register>`_ | ||
""" # noqa: E501 | ||
if cdsapi is None: | ||
raise ImportError('Retrieving ERA5 data requires cdsapi to be installed.') # noqa: E501 | ||
|
||
cds_client = cdsapi.Client(url=CDSAPI_URL, key=api_key, | ||
verify=1, quiet=True) | ||
|
||
# Area is selected by a box made by the four coordinates: [N, W, S, E] | ||
try: | ||
area = [latitude[1], longitude[0], latitude[0], longitude[1]] | ||
except TypeError: | ||
area = [latitude, longitude, latitude, longitude] | ||
|
||
params = { | ||
'product_type': product_type, | ||
'variable': variables, | ||
'date': start.strftime('%Y-%m-%d') + '/' + end.strftime('%Y-%m-%d'), | ||
'time': ERA5_HOURS, | ||
'grid': grid, | ||
'area': area, | ||
'format': 'netcdf'} | ||
|
||
# Retrieve request url | ||
request = cds_client.retrieve(dataset, params) | ||
file_url = request.location | ||
|
||
# Load file into memory | ||
with requests.get(file_url) as res: | ||
|
||
# Save the file locally if save_path has been specified | ||
if save_path is not None: | ||
with open(save_path, 'wb') as f: | ||
f.write(res.content) | ||
|
||
return read_era5(res.content, map_variables=map_variables, | ||
output_format=output_format) | ||
|
||
|
||
def read_era5(filename, output_format=None, map_variables=True): | ||
"""Read one or more ERA5 netcdf files. | ||
|
||
Parameters | ||
---------- | ||
filename: str or path-like or list | ||
Filename of a netcdf file containing ERA5 data or a list of filenames. | ||
output_format: {'dataframe', 'dataset'}, optional | ||
Type of data object to return. Default is to return a pandas DataFrame | ||
if file only contains one location and otherwise return an xarray | ||
dataset. | ||
map_variables: bool, default: True | ||
When true, renames columns to pvlib variable names where applicable. | ||
See variable ERA5_VARIABLE_MAP. | ||
|
||
Returns | ||
------- | ||
data: DataFrame | ||
ERA5 time-series data, fields depend on the requested data. The | ||
returned object is either a pandas DataFrame or an xarray dataset, | ||
depending on the output_format parameter. | ||
metadata: dict | ||
Metadata for the time-series. | ||
|
||
See Also | ||
-------- | ||
pvlib.iotools.get_era5 | ||
|
||
References | ||
---------- | ||
.. [1] `ERA5 hourly data on single levels from 1979 to present | ||
<https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels?tab=overview>`_ | ||
.. [2] `ERA5 data documentation | ||
<https://confluence.ecmwf.int/display/CKB/ERA5%3A+data+documentation>`_ | ||
""" | ||
if xr is None: | ||
raise ImportError('Reading ERA5 data requires xarray to be installed.') | ||
|
||
# open multiple-files (mf) requires dask | ||
AdamRJensen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if isinstance(filename, (list, tuple)): | ||
ds = xr.open_mfdataset(filename) | ||
else: | ||
ds = xr.open_dataset(filename) | ||
|
||
if map_variables: | ||
# Renaming of xarray datasets throws an error if keys are missing | ||
ds = ds.rename_vars( | ||
{k: v for k, v in ERA5_VARIABLE_MAP.items() if k in list(ds)}) | ||
|
||
ds = _convert_C_to_K_in_dataset(ds) | ||
metadata = _extract_metadata_from_dataset(ds) | ||
|
||
if (output_format == 'dataframe') or ( | ||
(output_format is None) & (ds['latitude'].size == 1) & | ||
(ds['longitude'].size == 1)): | ||
data = ds.to_dataframe() | ||
# Localize timezone to UTC | ||
data.index = data.index.set_levels(data.index.get_level_values('time').tz_localize('utc'), level='time') # noqa: E501 | ||
if (ds['latitude'].size == 1) & (ds['longitude'].size == 1): | ||
data = data.droplevel(['latitude', 'longitude']) | ||
return data, metadata | ||
kandersolar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else: | ||
return ds, metadata |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.