hefty 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hefty-0.0.1/LICENSE +28 -0
- hefty-0.0.1/PKG-INFO +117 -0
- hefty-0.0.1/README.md +97 -0
- hefty-0.0.1/pyproject.toml +30 -0
- hefty-0.0.1/setup.cfg +4 -0
- hefty-0.0.1/src/hefty/__init__.py +0 -0
- hefty-0.0.1/src/hefty/custom.py +204 -0
- hefty-0.0.1/src/hefty/pv_model.py +568 -0
- hefty-0.0.1/src/hefty/solar.py +1770 -0
- hefty-0.0.1/src/hefty/utilities.py +261 -0
- hefty-0.0.1/src/hefty/wind.py +269 -0
- hefty-0.0.1/src/hefty.egg-info/PKG-INFO +117 -0
- hefty-0.0.1/src/hefty.egg-info/SOURCES.txt +14 -0
- hefty-0.0.1/src/hefty.egg-info/dependency_links.txt +1 -0
- hefty-0.0.1/src/hefty.egg-info/requires.txt +2 -0
- hefty-0.0.1/src/hefty.egg-info/top_level.txt +1 -0
hefty-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Will Hobbs
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
hefty-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hefty
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Some (relatively) lightweight short-term energy forecasting tools for solar, wind, and load.
|
|
5
|
+
Author: Will Hobbs
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/williamhobbs/hefty
|
|
8
|
+
Project-URL: Issues, https://github.com/williamhobbs/hefty/issues
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: herbie-data[extras]>=2025.11.2
|
|
18
|
+
Requires-Dist: pvlib>=0.13.1
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# hEFTy
|
|
22
|
+
Some (relatively) lightweight short-term **e**nergy **f**orecasting **t**ools for solar, wind, and load.
|
|
23
|
+
|
|
24
|
+
This repository currently includes solar and wind tools, but may expand one day to include electric load. Forecasts can be created using the NOAA GFS, NOAA GEFS, NOAA HRRR, and ECMWF IFS and AIFS (open data versions) models.
|
|
25
|
+
|
|
26
|
+
For solar, look at the notebook [solar_example.ipynb](examples/solar_example.ipynb) for some examples, and [more_solar_examples.ipynb](examples/more_solar_examples.ipynb) for more examples. Both of these convert the resource forecasts to power.
|
|
27
|
+
|
|
28
|
+
There are also solar ensemble forecasts demonstrated in [ensemble_example.ipynb](examples/ensemble_example.ipynb).
|
|
29
|
+
|
|
30
|
+
For wind, look at the notebook [wind_example.ipynb](examples/wind_example.ipynb). The wind tools are not as developed at the solar tools.
|
|
31
|
+
|
|
32
|
+
The [custom.py](src/hefty/custom.py) module is intended to help with getting forecasts of "custom" weather parameters, not necessarily specific to wind or solar, which migh be useful for load forecasting.
|
|
33
|
+
|
|
34
|
+
## Quick examples
|
|
35
|
+
|
|
36
|
+
Here's a quick example of getting a solar resource data forecast:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from hefty.solar import get_solar_forecast
|
|
40
|
+
|
|
41
|
+
latitude = 33.5
|
|
42
|
+
longitude = -86.8
|
|
43
|
+
init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
|
|
44
|
+
resource_data = get_solar_forecast(
|
|
45
|
+
latitude,
|
|
46
|
+
longitude,
|
|
47
|
+
init_date,
|
|
48
|
+
run_length=18, # 18 hours are included in the forecast
|
|
49
|
+
lead_time_to_start=3, # forecast starts 3 hours out from the init_date
|
|
50
|
+
model='hrrr', # use NOAA HRRR
|
|
51
|
+
)
|
|
52
|
+
resource_data[
|
|
53
|
+
['ghi','dni','dhi','temp_air','wind_speed']
|
|
54
|
+
].plot(drawstyle='steps-mid')
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
with this output:
|
|
58
|
+
|
|
59
|
+
<img src="images/output.png" width="500"/>
|
|
60
|
+
|
|
61
|
+
Here's a wind resource forecast:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from hefty.wind import get_wind_forecast
|
|
65
|
+
|
|
66
|
+
latitude = 33.5
|
|
67
|
+
longitude = -86.8
|
|
68
|
+
init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
|
|
69
|
+
resource_data = get_wind_forecast(
|
|
70
|
+
latitude,
|
|
71
|
+
longitude,
|
|
72
|
+
init_date,
|
|
73
|
+
run_length=18, # 18 hours are included in the forecast
|
|
74
|
+
lead_time_to_start=3, # forecast starts 3 hours out from the init_date
|
|
75
|
+
model='gfs', # use NOAA GFS
|
|
76
|
+
)
|
|
77
|
+
resource_data[
|
|
78
|
+
['wind_speed_10m', 'wind_speed_80m',
|
|
79
|
+
'wind_speed_100m', 'temp_air_2m',
|
|
80
|
+
'pressure_0m']
|
|
81
|
+
].plot(secondary_y=['pressure_0m'], drawstyle='steps-mid')
|
|
82
|
+
```
|
|
83
|
+
with this output (note that pressure is on the secondary y-axis):
|
|
84
|
+
|
|
85
|
+
<img src="images/output_wind.png" width="500"/>
|
|
86
|
+
|
|
87
|
+
## Installation
|
|
88
|
+
|
|
89
|
+
A virtual environment is strongly recommended. You can install from PyPi with:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
pip install hefty
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
To run the example jupyter notebooks:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
pip install jupyter
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## References
|
|
102
|
+
This project uses several Python packages, including pvlib, an open-source solar PV modeling package [1, 2], and Herbie [3, 4], a package for accessing weather forecast data from NOAA. `pv_model.py` (with the `model_pv_power()` function used here) comes from [5] which leverages some functions from [6].
|
|
103
|
+
|
|
104
|
+
<img src="images/pvlib_powered_logo_horiz.png" width="200"/>
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
[1] Anderson, K., Hansen, C., Holmgren, W., Jensen, A., Mikofski, M., and Driesse, A. “pvlib python: 2023 project update.” Journal of Open Source Software, 8(92), 5994, (2023). [DOI: 10.21105/joss.05994](http://dx.doi.org/10.21105/joss.05994).
|
|
108
|
+
|
|
109
|
+
[2] https://github.com/pvlib/pvlib-python
|
|
110
|
+
|
|
111
|
+
[3] Blaylock, B. K. (2025). Herbie: Retrieve Numerical Weather Prediction Model Data (Version 2025.3.1) [Computer software]. https://doi.org/10.5281/zenodo.4567540
|
|
112
|
+
|
|
113
|
+
[4] https://github.com/blaylockbk/Herbie
|
|
114
|
+
|
|
115
|
+
[5] https://github.com/williamhobbs/pv-system-model
|
|
116
|
+
|
|
117
|
+
[6] Hobbs, W., Anderson, K., Mikofski, M., and Ghiz, M. "An approach to modeling linear and non-linear self-shading losses with pvlib." 2024 PV Performance Modeling Collaborative (PVPMC). https://github.com/williamhobbs/2024_pvpmc_self_shade
|
hefty-0.0.1/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# hEFTy
|
|
2
|
+
Some (relatively) lightweight short-term **e**nergy **f**orecasting **t**ools for solar, wind, and load.
|
|
3
|
+
|
|
4
|
+
This repository currently includes solar and wind tools, but may expand one day to include electric load. Forecasts can be created using the NOAA GFS, NOAA GEFS, NOAA HRRR, and ECMWF IFS and AIFS (open data versions) models.
|
|
5
|
+
|
|
6
|
+
For solar, look at the notebook [solar_example.ipynb](examples/solar_example.ipynb) for some examples, and [more_solar_examples.ipynb](examples/more_solar_examples.ipynb) for more examples. Both of these convert the resource forecasts to power.
|
|
7
|
+
|
|
8
|
+
There are also solar ensemble forecasts demonstrated in [ensemble_example.ipynb](examples/ensemble_example.ipynb).
|
|
9
|
+
|
|
10
|
+
For wind, look at the notebook [wind_example.ipynb](examples/wind_example.ipynb). The wind tools are not as developed at the solar tools.
|
|
11
|
+
|
|
12
|
+
The [custom.py](src/hefty/custom.py) module is intended to help with getting forecasts of "custom" weather parameters, not necessarily specific to wind or solar, which migh be useful for load forecasting.
|
|
13
|
+
|
|
14
|
+
## Quick examples
|
|
15
|
+
|
|
16
|
+
Here's a quick example of getting a solar resource data forecast:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from hefty.solar import get_solar_forecast
|
|
20
|
+
|
|
21
|
+
latitude = 33.5
|
|
22
|
+
longitude = -86.8
|
|
23
|
+
init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
|
|
24
|
+
resource_data = get_solar_forecast(
|
|
25
|
+
latitude,
|
|
26
|
+
longitude,
|
|
27
|
+
init_date,
|
|
28
|
+
run_length=18, # 18 hours are included in the forecast
|
|
29
|
+
lead_time_to_start=3, # forecast starts 3 hours out from the init_date
|
|
30
|
+
model='hrrr', # use NOAA HRRR
|
|
31
|
+
)
|
|
32
|
+
resource_data[
|
|
33
|
+
['ghi','dni','dhi','temp_air','wind_speed']
|
|
34
|
+
].plot(drawstyle='steps-mid')
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
with this output:
|
|
38
|
+
|
|
39
|
+
<img src="images/output.png" width="500"/>
|
|
40
|
+
|
|
41
|
+
Here's a wind resource forecast:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from hefty.wind import get_wind_forecast
|
|
45
|
+
|
|
46
|
+
latitude = 33.5
|
|
47
|
+
longitude = -86.8
|
|
48
|
+
init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
|
|
49
|
+
resource_data = get_wind_forecast(
|
|
50
|
+
latitude,
|
|
51
|
+
longitude,
|
|
52
|
+
init_date,
|
|
53
|
+
run_length=18, # 18 hours are included in the forecast
|
|
54
|
+
lead_time_to_start=3, # forecast starts 3 hours out from the init_date
|
|
55
|
+
model='gfs', # use NOAA GFS
|
|
56
|
+
)
|
|
57
|
+
resource_data[
|
|
58
|
+
['wind_speed_10m', 'wind_speed_80m',
|
|
59
|
+
'wind_speed_100m', 'temp_air_2m',
|
|
60
|
+
'pressure_0m']
|
|
61
|
+
].plot(secondary_y=['pressure_0m'], drawstyle='steps-mid')
|
|
62
|
+
```
|
|
63
|
+
with this output (note that pressure is on the secondary y-axis):
|
|
64
|
+
|
|
65
|
+
<img src="images/output_wind.png" width="500"/>
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
A virtual environment is strongly recommended. You can install from PyPi with:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
pip install hefty
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
To run the example jupyter notebooks:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
pip install jupyter
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## References
|
|
82
|
+
This project uses several Python packages, including pvlib, an open-source solar PV modeling package [1, 2], and Herbie [3, 4], a package for accessing weather forecast data from NOAA. `pv_model.py` (with the `model_pv_power()` function used here) comes from [5] which leverages some functions from [6].
|
|
83
|
+
|
|
84
|
+
<img src="images/pvlib_powered_logo_horiz.png" width="200"/>
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
[1] Anderson, K., Hansen, C., Holmgren, W., Jensen, A., Mikofski, M., and Driesse, A. “pvlib python: 2023 project update.” Journal of Open Source Software, 8(92), 5994, (2023). [DOI: 10.21105/joss.05994](http://dx.doi.org/10.21105/joss.05994).
|
|
88
|
+
|
|
89
|
+
[2] https://github.com/pvlib/pvlib-python
|
|
90
|
+
|
|
91
|
+
[3] Blaylock, B. K. (2025). Herbie: Retrieve Numerical Weather Prediction Model Data (Version 2025.3.1) [Computer software]. https://doi.org/10.5281/zenodo.4567540
|
|
92
|
+
|
|
93
|
+
[4] https://github.com/blaylockbk/Herbie
|
|
94
|
+
|
|
95
|
+
[5] https://github.com/williamhobbs/pv-system-model
|
|
96
|
+
|
|
97
|
+
[6] Hobbs, W., Anderson, K., Mikofski, M., and Ghiz, M. "An approach to modeling linear and non-linear self-shading losses with pvlib." 2024 PV Performance Modeling Collaborative (PVPMC). https://github.com/williamhobbs/2024_pvpmc_self_shade
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools >= 77.0.3"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hefty"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "Some (relatively) lightweight short-term energy forecasting tools for solar, wind, and load."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name="Will Hobbs" },
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"Topic :: Scientific/Engineering",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"herbie-data[extras] >= 2025.11.2",
|
|
23
|
+
"pvlib >= 0.13.1",
|
|
24
|
+
]
|
|
25
|
+
license = "BSD-3-Clause"
|
|
26
|
+
license-files = ["LICENSE*"]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/williamhobbs/hefty"
|
|
30
|
+
Issues = "https://github.com/williamhobbs/hefty/issues"
|
hefty-0.0.1/setup.cfg
ADDED
|
File without changes
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import xarray as xr
|
|
4
|
+
from herbie import Herbie, FastHerbie
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_custom_forecast(latitude, longitude, init_date, run_length,
|
|
9
|
+
lead_time_to_start=0, period=3, model='gfs',
|
|
10
|
+
product='pgrb2.0p25', search_str=':TMP:2 m above',
|
|
11
|
+
member=None, attempts=2, hrrr_hour_middle=True,
|
|
12
|
+
hrrr_coursen_window=None, priority=None):
|
|
13
|
+
"""
|
|
14
|
+
Get a custom forecast for one or several sites from one of several
|
|
15
|
+
NWPs. This function uses Herbie [1]_.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
latitude : float or list of floats
|
|
20
|
+
Latitude in decimal degrees. Positive north of equator, negative
|
|
21
|
+
to south.
|
|
22
|
+
|
|
23
|
+
longitude : float or list of floats
|
|
24
|
+
Longitude in decimal degrees. Positive east of prime meridian,
|
|
25
|
+
negative to west.
|
|
26
|
+
|
|
27
|
+
init_date : pandas-parsable datetime
|
|
28
|
+
Model initialization datetime.
|
|
29
|
+
|
|
30
|
+
run_length : int
|
|
31
|
+
Length of the forecast in hours - number of hours forecasted
|
|
32
|
+
|
|
33
|
+
search_str : string
|
|
34
|
+
regex search string for grib files. See [2]_ for more info.
|
|
35
|
+
|
|
36
|
+
lead_time_to_start : int, optional
|
|
37
|
+
Number of hours between init_date (initialization) and
|
|
38
|
+
the first forecasted interval. NOAA GFS data goes out
|
|
39
|
+
384 hours, so run_length + lead_time_to_start must be less
|
|
40
|
+
than or equal to 384.
|
|
41
|
+
|
|
42
|
+
model : string, default 'gfs'
|
|
43
|
+
Forecast model. Default is NOAA GFS ('gfs'), but can also be
|
|
44
|
+
ECMWF IFS ('ifs'), NOAA HRRR ('hrrr'), or NOAA GEFS ('gefs).
|
|
45
|
+
|
|
46
|
+
member: string or int
|
|
47
|
+
For models that are ensembles, pass an appropriate single member label.
|
|
48
|
+
|
|
49
|
+
attempts : int, optional
|
|
50
|
+
Number of times to try getting forecast data. The function will pause
|
|
51
|
+
for n^2 minutes after each n attempt, e.g., 1 min after the first
|
|
52
|
+
attempt, 4 minutes after the second, etc.
|
|
53
|
+
|
|
54
|
+
hrrr_hour_middle : bool, default True
|
|
55
|
+
If model is 'hrrr', setting this False keeps the forecast at the
|
|
56
|
+
native instantaneous top-of-hour format. True (default) shifts
|
|
57
|
+
the forecast to middle of the hour, more closely representing an
|
|
58
|
+
integrated hourly forecast that is centered in the middle of the
|
|
59
|
+
hour.
|
|
60
|
+
|
|
61
|
+
hrrr_coursen_window : int or None, default None
|
|
62
|
+
If model is 'hrrr', optional setting that is the x and y window size
|
|
63
|
+
for coarsening the xarray dataset, effectively applying spatial
|
|
64
|
+
smoothing to the HRRR model. The HRRR has a native resolution of
|
|
65
|
+
about 3 km, so a value of 10 results in approx. 30 x 30 km grid.
|
|
66
|
+
|
|
67
|
+
priority : list or string
|
|
68
|
+
List of model sources to get the data in the order of download
|
|
69
|
+
priority, or string for a single source. See Herbie docs.
|
|
70
|
+
Typical values would be 'aws' or 'google'.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
data : pandas.DataFrane
|
|
75
|
+
timeseries forecasted weather data
|
|
76
|
+
|
|
77
|
+
References
|
|
78
|
+
----------
|
|
79
|
+
|
|
80
|
+
.. [1] `Blaylock, B. K. (YEAR). Herbie: Retrieve Numerical Weather
|
|
81
|
+
Prediction Model Data (Version 20xx.x.x) [Computer software].
|
|
82
|
+
<https://doi.org/10.5281/zenodo.4567540>`_
|
|
83
|
+
.. [2] <https://herbie.readthedocs.io/en/latest/user_guide/tutorial/search.html> # noqa
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
# variable formatting
|
|
87
|
+
# if lat, lon are single values, convert to lists for pickpoints later
|
|
88
|
+
if type(latitude) is float or type(latitude) is int:
|
|
89
|
+
latitude = [latitude]
|
|
90
|
+
longitude = [longitude]
|
|
91
|
+
# convert init_date to datetime
|
|
92
|
+
init_date = pd.to_datetime(init_date)
|
|
93
|
+
|
|
94
|
+
# get model-specific Herbie inputs
|
|
95
|
+
date = init_date
|
|
96
|
+
fxx_max = run_length + lead_time_to_start
|
|
97
|
+
fxx_range = range(lead_time_to_start, fxx_max, period)
|
|
98
|
+
|
|
99
|
+
i = []
|
|
100
|
+
for fxx in fxx_range:
|
|
101
|
+
# get solar, 10m wind, and 2m temp data
|
|
102
|
+
# try n times based loosely on
|
|
103
|
+
# https://thingspython.wordpress.com/2021/12/05/how-to-try-something-n-times-in-python/
|
|
104
|
+
for attempts_remaining in reversed(range(attempts)):
|
|
105
|
+
attempt_num = attempts - attempts_remaining
|
|
106
|
+
try:
|
|
107
|
+
if attempt_num == 1:
|
|
108
|
+
# try downloading
|
|
109
|
+
ds = Herbie(
|
|
110
|
+
date,
|
|
111
|
+
model=model,
|
|
112
|
+
product=product,
|
|
113
|
+
fxx=fxx,
|
|
114
|
+
member=member,
|
|
115
|
+
priority=priority
|
|
116
|
+
).xarray(search_str)
|
|
117
|
+
else:
|
|
118
|
+
# after first attempt, set overwrite=True to overwrite
|
|
119
|
+
# partial files
|
|
120
|
+
ds = Herbie(
|
|
121
|
+
date,
|
|
122
|
+
model=model,
|
|
123
|
+
product=product,
|
|
124
|
+
fxx=fxx,
|
|
125
|
+
member=member,
|
|
126
|
+
priority=priority
|
|
127
|
+
).xarray(search_str, overwrite=True)
|
|
128
|
+
except Exception:
|
|
129
|
+
if attempts_remaining:
|
|
130
|
+
print('attempt ' + str(attempt_num) + ' failed, pause for '
|
|
131
|
+
+ str((attempt_num)**2) + ' min')
|
|
132
|
+
time.sleep(60*(attempt_num)**2)
|
|
133
|
+
else:
|
|
134
|
+
break
|
|
135
|
+
else:
|
|
136
|
+
raise ValueError('download failed, ran out of attempts')
|
|
137
|
+
|
|
138
|
+
# merge - override avoids hight conflict between 2m temp and 10m wind
|
|
139
|
+
ds = xr.merge(ds, compat='override')
|
|
140
|
+
# calculate wind speed from u and v components
|
|
141
|
+
ds = ds.herbie.with_wind('both')
|
|
142
|
+
|
|
143
|
+
if model == 'hrrr' and hrrr_coursen_window is not None:
|
|
144
|
+
ds = ds.coarsen(x=hrrr_coursen_window,
|
|
145
|
+
y=hrrr_coursen_window,
|
|
146
|
+
boundary='trim').mean()
|
|
147
|
+
|
|
148
|
+
# use pick_points for single point or list of points
|
|
149
|
+
i.append(
|
|
150
|
+
ds.herbie.pick_points(
|
|
151
|
+
pd.DataFrame(
|
|
152
|
+
{
|
|
153
|
+
"latitude": latitude,
|
|
154
|
+
"longitude": longitude,
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
ts = xr.concat(i, dim="valid_time") # concatenate
|
|
160
|
+
|
|
161
|
+
# convert to dataframe
|
|
162
|
+
df_temp = ts.to_dataframe()
|
|
163
|
+
|
|
164
|
+
# work through sites
|
|
165
|
+
dfs = {} # empty list of dataframes
|
|
166
|
+
if type(latitude) is float or type(latitude) is int:
|
|
167
|
+
num_sites = 1
|
|
168
|
+
else:
|
|
169
|
+
num_sites = len(latitude)
|
|
170
|
+
|
|
171
|
+
for j in range(num_sites):
|
|
172
|
+
df = df_temp[df_temp.index.get_level_values('point') == j]
|
|
173
|
+
df = df.droplevel('point')
|
|
174
|
+
|
|
175
|
+
if model == 'hrrr' and hrrr_hour_middle is False:
|
|
176
|
+
# keep top of hour instantaneous HRRR convention
|
|
177
|
+
dfs[j] = df
|
|
178
|
+
else:
|
|
179
|
+
# 60min version of data, centered at bottom of the hour
|
|
180
|
+
# 1min interpolation, then 60min mean
|
|
181
|
+
df_60min = (
|
|
182
|
+
df
|
|
183
|
+
.resample('1min')
|
|
184
|
+
.interpolate()
|
|
185
|
+
.resample('60min').mean()
|
|
186
|
+
)
|
|
187
|
+
df_60min.index = df_60min.index + pd.Timedelta('30min')
|
|
188
|
+
dfs[j] = df_60min
|
|
189
|
+
|
|
190
|
+
# concatenate creating multiindex with keys of the list of point numbers
|
|
191
|
+
# assigned to 'point', reorder indices, and sort by valid_time
|
|
192
|
+
df_60min = (
|
|
193
|
+
pd.concat(dfs, keys=list(range(num_sites)), names=['point'])
|
|
194
|
+
.reorder_levels(["valid_time", "point"])
|
|
195
|
+
.sort_index(level='valid_time')
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# set "point" index as a column
|
|
199
|
+
df_60min = df_60min.reset_index().set_index('valid_time')
|
|
200
|
+
|
|
201
|
+
# drop unneeded columns if they exist
|
|
202
|
+
# df_60min = df_60min.drop(['t2m', 'sdswrf'], axis=1, errors='ignore')
|
|
203
|
+
|
|
204
|
+
return df_60min
|