Skip to content

Commit 1703cef

Browse files
karlhillxAdamRJensenechedey-ls
authored
Update nasa_power VARIABLE_MAP with additional parameters (#2762)
* Update nasa_power VARIABLE_MAP with additional parameters - Added: ALLSKY_SFC_LW_DWN, ALLSKY_TOA_SW_DWN, CLRSKY_DIFF, PS, T2MDEW, T2MWET, RH2M, SRF_ALB, TQV - Fix PS unit conversion: kPa to Pa for pvlib.atmosphere compatibility - Fix parameter names: CLRSKY_DIFF -> CLRSKY_SFC_SW_DIFF, ALLSKY_TOA_SW_DWN -> TOA_SW_DWN, SRF_ALB -> ALLSKY_SRF_ALB - Drop T2MWET (duplicate target name breaks pandas rename) - Add TQV unit conversion: kg/m^2 to cm - Add regression tests for all VARIABLE_MAP params and unit conversions * Fix flake8 E501/E702 in test file * Address review comments: move unit conversion note to Notes section, simplify inline comments - Move unit conversion documentation from map_variables param description to a dedicated Notes section in the docstring - Simplify pressure conversion comment (remove specific function list) - Simplify TQV conversion comment (remove specific function reference) * Add dni_clear to variable map * Update notes section * Fix linter * Split test_get_nasa_power_all_variable_map_parameters_valid into two batches VARIABLE_MAP now has 16 entries, exceeding NASA POWER's 15-parameter-per-request limit. Split the test into two batches of 8 instead of asserting the limit. * Add whatsnew entry for nasa_power VARIABLE_MAP additions (PR #2762) * Address review: simplify whatsnew entry, add self to Contributors (PR #2762) * Apply suggestion from @echedey-ls Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> * Apply suggestion from @AdamRJensen - combine whatsnew entries --------- Co-authored-by: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com> Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com>
1 parent 66d43b3 commit 1703cef

3 files changed

Lines changed: 134 additions & 8 deletions

File tree

docs/sphinx/source/whatsnew/v0.15.2.rst

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,11 @@ Bug fixes
4040

4141
Enhancements
4242
~~~~~~~~~~~~
43-
* Add the ``front_side_fraction`` parameter to
44-
:py:func:`pvlib.snow.loss_townsend` to support Townsend snow-loss
45-
workflows for bifacial systems. (:issue:`2755`, :pull:`2756`)
46-
47-
* Added mapping of the parameter ``"albedo"`` in
48-
:py:func:`~pvlib.iotools.get_nasa_power` when ``map_variables=True``
49-
(:pull:`2753`)
43+
* Add the following parameters to :py:func:`~pvlib.iotools.get_nasa_power`
44+
when ``map_variables=True``: ``temp_dew``, ``precipitable_water``,
45+
``relative_humidity``, ``ghi_extra``, ``dhi_clear``, ``longwave_down``,
46+
and ``albedo``.
47+
(:issue:`2731`, :pull:`2753`, :pull:`2762`)
5048

5149

5250
Documentation
@@ -83,4 +81,5 @@ Contributors
8381
* :ghuser:`shethkajal7`
8482
* Arthur Onno (:ghuser:`ArthurOnnoTerabase`)
8583
* Adam R. Jensen (:ghuser:`AdamRJensen`)
84+
* Karl Hill (:ghuser:`karlhillx`)
8685
* Rajiv Daxini (:ghuser:`RDaxini`)

pvlib/iotools/nasa_power.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,19 @@
1414
'ALLSKY_SFC_SW_DWN': 'ghi',
1515
'ALLSKY_SFC_SW_DIFF': 'dhi',
1616
'ALLSKY_SFC_SW_DNI': 'dni',
17+
'ALLSKY_SRF_ALB': 'albedo',
18+
'ALLSKY_SFC_LW_DWN': 'longwave_down',
19+
'CLRSKY_SFC_SW_DIFF': 'dhi_clear',
20+
'CLRSKY_SFC_SW_DNI': 'dni_clear',
1721
'CLRSKY_SFC_SW_DWN': 'ghi_clear',
22+
'PS': 'pressure',
23+
'RH2M': 'relative_humidity',
1824
'T2M': 'temp_air',
25+
'T2MDEW': 'temp_dew',
26+
'TQV': 'precipitable_water',
27+
'TOA_SW_DWN': 'ghi_extra',
1928
'WS2M': 'wind_speed_2m',
2029
'WS10M': 'wind_speed',
21-
'ALLSKY_SRF_ALB': 'albedo',
2230
}
2331

2432

@@ -82,6 +90,12 @@ def get_nasa_power(latitude, longitude, start, end,
8290
requests.HTTPError
8391
Raises an error when an incorrect request is made.
8492
93+
Notes
94+
-----
95+
When ``map_variables=True`` the following unit conversions are applied:
96+
pressure is converted from kPa to Pa, and precipitable water
97+
is converted from kg/m² (mm) to cm.
98+
8599
Returns
86100
-------
87101
data : pd.DataFrame
@@ -150,5 +164,11 @@ def get_nasa_power(latitude, longitude, start, end,
150164
# Rename according to pvlib convention
151165
if map_variables:
152166
df = df.rename(columns=VARIABLE_MAP)
167+
# PS is returned in kPa; convert to Pa for pvlib compatibility.
168+
if 'pressure' in df.columns:
169+
df['pressure'] = df['pressure'] * 1000
170+
# TQV is returned in kg/m^2 (=mm); convert to cm for compatibility
171+
if 'precipitable_water' in df.columns:
172+
df['precipitable_water'] = df['precipitable_water'] / 10
153173

154174
return df, meta

tests/iotools/test_nasa_power.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,110 @@ def test_get_nasa_power_duplicate_parameter_name(data_index):
9898
start=data_index[0],
9999
end=data_index[-1],
100100
parameters=2*['ALLSKY_SFC_SW_DWN'])
101+
102+
103+
@pytest.mark.remote_data
104+
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
105+
def test_get_nasa_power_all_variable_map_parameters_valid():
106+
"""
107+
Every NASA POWER parameter name in VARIABLE_MAP must be accepted by the
108+
live API. A typo or stale name (e.g. CLRSKY_DIFF vs CLRSKY_SFC_SW_DIFF)
109+
causes the API to return an HTTPError, which would fail this test.
110+
111+
NASA POWER allows max 15 parameters per request; VARIABLE_MAP is split
112+
into two batches to stay within that limit.
113+
"""
114+
from pvlib.iotools.nasa_power import VARIABLE_MAP
115+
nasa_params = list(VARIABLE_MAP.keys())
116+
# Split into two batches; API limit is 15.
117+
half = (len(nasa_params) + 1) // 2
118+
batch1 = nasa_params[:half]
119+
batch2 = nasa_params[half:]
120+
121+
for batch in [batch1, batch2]:
122+
data, meta = pvlib.iotools.get_nasa_power(
123+
latitude=44.76,
124+
longitude=7.64,
125+
start='2025-02-02',
126+
end='2025-02-02',
127+
parameters=batch,
128+
map_variables=False,
129+
)
130+
missing = set(batch) - set(data.columns)
131+
assert not missing, f"NASA POWER did not return: {sorted(missing)}"
132+
133+
134+
@pytest.mark.remote_data
135+
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
136+
def test_get_nasa_power_all_variable_map_renamed():
137+
"""
138+
With map_variables=True every NASA name must be renamed to its pvlib
139+
equivalent. Catches duplicate-target collisions (e.g. two entries both
140+
mapping to 'temp_dew', which silently drops a column under pandas rename).
141+
"""
142+
from pvlib.iotools.nasa_power import VARIABLE_MAP
143+
nasa_params = list(VARIABLE_MAP.keys())
144+
pvlib_names = set(VARIABLE_MAP.values())
145+
146+
data, _ = pvlib.iotools.get_nasa_power(
147+
latitude=44.76,
148+
longitude=7.64,
149+
start='2025-02-02',
150+
end='2025-02-02',
151+
parameters=nasa_params,
152+
map_variables=True,
153+
)
154+
155+
missing = pvlib_names - set(data.columns)
156+
assert not missing, (
157+
f"map_variables=True dropped pvlib columns: {sorted(missing)}. "
158+
"Likely cause: duplicate target names in VARIABLE_MAP."
159+
)
160+
161+
162+
@pytest.mark.remote_data
163+
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
164+
def test_get_nasa_power_pressure_unit_conversion():
165+
"""
166+
NASA POWER returns PS in kPa; pvlib convention is Pa.
167+
Sea-level surface pressure should be ~101 kPa = ~101325 Pa, not ~101.
168+
"""
169+
data, _ = pvlib.iotools.get_nasa_power(
170+
latitude=0.0, # sea-level equatorial point
171+
longitude=-30.0,
172+
start='2025-02-02',
173+
end='2025-02-02',
174+
parameters=['PS'],
175+
map_variables=True,
176+
)
177+
mean_pressure = data['pressure'].mean()
178+
# Anywhere on earth, surface pressure in Pa is between ~50k and ~110k.
179+
# If the conversion is missing, value will be ~100 (kPa) and fail this.
180+
assert 50_000 < mean_pressure < 110_000, (
181+
f"PS not converted from kPa to Pa. Got mean={mean_pressure}"
182+
)
183+
184+
185+
@pytest.mark.remote_data
186+
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
187+
def test_get_nasa_power_precipitable_water_unit_conversion():
188+
"""
189+
NASA POWER returns TQV in kg/m^2 (= mm of water column);
190+
pvlib convention is cm. Typical atmospheric column is 1-5 cm,
191+
never above ~7 cm. If the /10 conversion is missing, values will
192+
be 10-50 and fail this bound.
193+
"""
194+
data, _ = pvlib.iotools.get_nasa_power(
195+
latitude=0.0, # tropics: high water vapor, worst case for bounds
196+
longitude=-60.0,
197+
start='2025-02-02',
198+
end='2025-02-02',
199+
parameters=['TQV'],
200+
map_variables=True,
201+
)
202+
mean_pw = data['precipitable_water'].mean()
203+
# pvlib precipitable_water is in cm. Tropical column is <~7 cm.
204+
# Missing /10 conversion would give 10-70 (kg/m^2 = mm).
205+
assert 0 < mean_pw < 10, (
206+
f"TQV not converted from kg/m^2 to cm. Got mean={mean_pw}"
207+
)

0 commit comments

Comments
 (0)