Skip to content
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
70e0156
changed default types to float in solarposition.py
Oct 29, 2024
0ec0cbf
switched to floats in the docstrings and removed type hints
Oct 30, 2024
5eb9d00
added magnus_tetens equations
Oct 30, 2024
ab2de3a
line too long in solarposition.py
Oct 30, 2024
f62bd8e
revert solarposition.py to pre-PR state
Oct 30, 2024
77025c7
set default magnus coefficients per conversation in #1744
Nov 5, 2024
b52f9a9
moved equations to atmosphere.py, updated function names to suggested…
Nov 11, 2024
58b246e
moved tests to atmosphere.py tests
Nov 11, 2024
a06871a
changed reference to WMO
Nov 11, 2024
caa4417
dry-bult temperature in the docstring
Nov 11, 2024
edd84b1
revert pyproject.toml
Nov 11, 2024
9c32f6a
remove uv.lock
Nov 11, 2024
63ed5c7
Update pvlib/atmosphere.py
kurt-rhee Nov 18, 2024
6312f92
fixing flake8 errors for tdew/rh functions
Nov 18, 2024
410e95f
Update pvlib/atmosphere.py
kurt-rhee Nov 25, 2024
d94df47
Update pvlib/atmosphere.py
kurt-rhee Nov 25, 2024
e6b5908
Update pvlib/atmosphere.py
kurt-rhee Nov 25, 2024
63a9226
Update pvlib/atmosphere.py
kurt-rhee Nov 25, 2024
459d5a6
Update pvlib/atmosphere.py
kurt-rhee Nov 25, 2024
05b846f
Update pvlib/atmosphere.py
kurt-rhee Nov 25, 2024
0ae31e1
added some unit tests for different coefficients and input types
kurt-rhee Dec 1, 2024
337f723
refactored tests, removed magnus_tetens, updated whatsnew
kurt-rhee Dec 5, 2024
8bc9b86
reference and whatsnew
kurt-rhee Dec 5, 2024
9651c3b
revert line 36 (linter)
kurt-rhee Dec 5, 2024
b860ca5
Update pvlib/atmosphere.py
kurt-rhee Dec 7, 2024
2bdc1dc
Update docs/sphinx/source/whatsnew/v0.11.2.rst
kurt-rhee Dec 7, 2024
c39c449
Update pvlib/atmosphere.py
kurt-rhee Dec 7, 2024
b5a6f09
Update pvlib/tests/test_atmosphere.py
kurt-rhee Dec 7, 2024
aedc835
Update pyproject.toml
kurt-rhee Dec 7, 2024
4fcb9e3
Merge branch 'main' into relative-humidity
AdamRJensen Dec 9, 2024
c956c91
Update pvlib/atmosphere.py
kurt-rhee Dec 10, 2024
f682815
Update pvlib/atmosphere.py
kurt-rhee Dec 10, 2024
0bfc6cb
Update pvlib/atmosphere.py
kurt-rhee Dec 10, 2024
71a165e
Update pvlib/atmosphere.py
kurt-rhee Dec 10, 2024
25527d6
Update pvlib/atmosphere.py
kurt-rhee Dec 10, 2024
1eff53f
added a round-trip test for magnus tetens
kurt-rhee Dec 11, 2024
df33a31
temperature -> temp_air; dewpoint -> temp_dew
kandersolar Dec 12, 2024
b4802a3
miscellaneous other cleanup
kandersolar Dec 12, 2024
3893692
tests: put assertions next to calculations
kandersolar Dec 12, 2024
11d81c3
linter
kandersolar Dec 12, 2024
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
2 changes: 2 additions & 0 deletions docs/sphinx/source/reference/airmass_atmospheric.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Airmass and atmospheric models
atmosphere.get_relative_airmass
atmosphere.pres2alt
atmosphere.alt2pres
atmosphere.tdew_from_rh
atmosphere.rh_from_tdew
atmosphere.gueymard94_pw
atmosphere.first_solar_spectral_correction
atmosphere.bird_hulstrom80_aod_bb
Expand Down
3 changes: 3 additions & 0 deletions docs/sphinx/source/whatsnew/v0.11.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Deprecations

Enhancements
~~~~~~~~~~~~
* :py:func:`~pvlib.atmosphere.rh_from_tdew` and :py:func:`~pvlib.atmosphere.tdew_from_rh`
added. (:issue:`1744`, :pull:`2286`)
* :py:func:`~pvlib.ivtools.sdm.fit_desoto` now allows input of initial
parameter guesses. (:issue:`1014`, :pull:`2291`)

Expand All @@ -20,6 +22,7 @@ Bug Fixes
* Handle DST transitions that happen at midnight in :py:func:`pvlib.solarposition.hour_angle`
(:issue:`2132` :pull:`2133`)


Bug fixes
~~~~~~~~~
* :py:func:`~pvlib.spa.julian_day_dt` now accounts for the 10 day difference
Expand Down
80 changes: 80 additions & 0 deletions pvlib/atmosphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,86 @@
return pw


def rh_from_tdew(temperature, dewpoint, coeff=(6.112, 17.62, 243.12)):
Copy link
Member

@kandersolar kandersolar Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed earlier but forgot to comment: we should rename this parameter to temp_dew, the name used by other pvlib models and iotools functions. I'll push a commit for that to give @kurt-rhee a break from this PR :P

edit: and same for temp_air of course

"""
Calculate relative humidity from dewpoint temperature using the Magnus equation.

Check failure on line 342 in pvlib/atmosphere.py

View workflow job for this annotation

GitHub Actions / flake8-linter

E501 line too long (84 > 79 characters)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Calculate relative humidity from dewpoint temperature using the Magnus equation.
Calculate relative humidity from dew-point temperature using the Magnus equation.

Copy link
Member

@cwhanse cwhanse Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(inner grammarian emerges) the term is either "dewpoint" or "dew point": NOAA glossary. The AMS glossary prefers "dewpoint".

I can't find any instances of "dew-point" as a hyphenated adjective, although I understand that's what grammar rules suggest it should be, rather than "dew point".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admittedly I didn't search beyond the WMO document we referenced, so it could be an old-world / new-world thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to use any term that you all prefer

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like EPW and TMY3 files use the hyphen. Most of the pvlib docs use "dew point", with the exception of the Nomenclature page which says "Dewpoint".

I suggest we leave this for a potential package-wide cleanup and not worry about it here.

Parameters
----------
temperature : numeric
Air temperature (dry-bulb temperature). [°C]
dewpoint : numeric
Dew-point temperature. [°C]
coeff : tuple, default (6.112, 17.62, 243.12)
Magnus equation coefficients (A, B, C). The default values are those
recommended by the WMO [1]_.
Returns
-------
numeric
Relative humidity (0.0-100.0). [%]
References
----------
.. [1] "Guide to Instruments and Methods of Observation",
World Meteorological Organization, WMO-No. 8, 2023.
https://library.wmo.int/idurl/4/68695
"""

# Calculate vapor pressure (e) and saturation vapor pressure (es)
e = coeff[0] * np.exp((coeff[1] * temperature) / (coeff[2] + temperature))
es = coeff[0] * np.exp((coeff[1] * dewpoint) / (coeff[2] + dewpoint))

# Calculate relative humidity as percentage
relative_humidity = 100 * (es / e)

return relative_humidity


def tdew_from_rh(
temperature, relative_humidity, coeff=(6.112, 17.62, 243.12)
):
"""
Calculate dewpoint temperature using Magnus equation.
This is a reversal of the calculation in :py:func:`rh_from_tdew`.
Parameters
----------
temperature : numeric
Air temperature (dry-bulb temperature). [°C]
relative_humidity : numeric
Relative humidity (0-100). [%]
coeff: tuple, default (6.112, 17.62, 243.12)
Magnus equation coefficients (A, B, C). The default values are those
recommended by the WMO [1]_.
Returns
-------
numeric
Dewpoint temperature.. [°C]
References
----------
.. [1] "Guide to Instruments and Methods of Observation",
World Meteorological Organization, WMO-No. 8, 2023.
https://library.wmo.int/idurl/4/68695
"""
# Calculate the term inside the log
# From RH = 100 * (es/e), we get es = (RH/100) * e
# Substituting the Magnus equation and solving for dewpoint

# First calculate ln(es/A)
ln_term = (
(coeff[1] * temperature) / (coeff[2] + temperature)
+ np.log(relative_humidity/100)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like RH zero might throw an error or warning here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a check for zero values or leave the original message in the stack trace?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's necessary, RH=0% is practically impossible (source).

)

# Then solve for dewpoint
dewpoint = coeff[2] * ln_term / (coeff[1] - ln_term)

return dewpoint


first_solar_spectral_correction = deprecated(
since='0.10.0',
alternative='pvlib.spectrum.spectral_factor_firstsolar'
Expand Down
163 changes: 163 additions & 0 deletions pvlib/tests/test_atmosphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,169 @@ def test_gueymard94_pw():
assert_allclose(pws, expected, atol=0.01)


def test_tdew_to_rh_to_tdew():

# dewpoint temp calculated with who and aekr coefficients
dewpoint_original = pd.Series([
15.0, 20.0, 25.0, 12.0, 8.0
])

temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])

# Calculate relative humidity using pandas series as input
relative_humidity = atmosphere.rh_from_tdew(
temperature=temperature_ambient,
dewpoint=dewpoint_original
)

dewpoint_calculated = atmosphere.tdew_from_rh(
temperature=temperature_ambient,
relative_humidity=relative_humidity
)

# test
pd.testing.assert_series_equal(
dewpoint_original,
dewpoint_calculated,
check_names=False
)


def test_rh_from_tdew():

# dewpoint temp calculated with who and aekr coefficients
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

several comments and variables in these two test functions say "who" instead of "wmo" :)

dewpoint = pd.Series([
15.0, 20.0, 25.0, 12.0, 8.0
])

# relative humidity calculated with who and aekr coefficients
relative_humidity_who = pd.Series([
72.95185312581116, 73.81500029087906, 74.6401272083123,
82.27063889868842, 87.39018119185337
])
relative_humidity_aekr = pd.Series([
72.93876680928582, 73.8025121880607, 74.62820502423823,
82.26135295757305, 87.38323744820416
])

temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])

# Calculate relative humidity using pandas series as input
rh_series = atmosphere.rh_from_tdew(
temperature=temperature_ambient,
dewpoint=dewpoint
)

# Calulate relative humidity using pandas series as input
# with AEKR coefficients
rh_series_aekr = atmosphere.rh_from_tdew(
temperature=temperature_ambient,
dewpoint=dewpoint,
coeff=(6.1094, 17.625, 243.04)
)

# Calculate relative humidity using array as input
rh_array = atmosphere.rh_from_tdew(
temperature=temperature_ambient.to_numpy(),
dewpoint=dewpoint.to_numpy()
)

# test
pd.testing.assert_series_equal(
rh_series,
relative_humidity_who,
check_names=False
)

pd.testing.assert_series_equal(
rh_series_aekr,
relative_humidity_aekr,
check_names=False
)

np.testing.assert_allclose(
rh_array,
relative_humidity_who.to_numpy(),
)

# Calculate relative humidity using float as input
rh_float = atmosphere.rh_from_tdew(
temperature=temperature_ambient.iloc[0],
dewpoint=dewpoint.iloc[0]
)

assert np.isclose(
rh_float,
relative_humidity_who.iloc[0]
)


# Unit tests
def test_tdew_from_rh():

# dewpoint temp calculated with who and aekr coefficients
dewpoint = pd.Series([
15.0, 20.0, 25.0, 12.0, 8.0
])

# relative humidity calculated with who and aekr coefficients
relative_humidity_who = pd.Series([
72.95185312581116, 73.81500029087906, 74.6401272083123,
82.27063889868842, 87.39018119185337
])
relative_humidity_aekr = pd.Series([
72.93876680928582, 73.8025121880607, 74.62820502423823,
82.26135295757305, 87.38323744820416
])

temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])

# test as series
dewpoint_series = atmosphere.tdew_from_rh(
temperature=temperature_ambient,
relative_humidity=relative_humidity_who
)

# test as series with AEKR coefficients
dewpoint_series_aekr = atmosphere.tdew_from_rh(
temperature=temperature_ambient,
relative_humidity=relative_humidity_aekr,
coeff=(6.1094, 17.625, 243.04)
)

# test as numpy array
dewpoint_array = atmosphere.tdew_from_rh(
temperature=temperature_ambient.to_numpy(),
relative_humidity=relative_humidity_who.to_numpy()
)

# test as float
dewpoint_float = atmosphere.tdew_from_rh(
temperature=temperature_ambient.iloc[0],
relative_humidity=relative_humidity_who.iloc[0]
)

# test
pd.testing.assert_series_equal(
dewpoint_series, dewpoint, check_names=False
)

pd.testing.assert_series_equal(
dewpoint_series_aekr, dewpoint,
check_names=False
)

np.testing.assert_allclose(
dewpoint_array,
dewpoint.to_numpy(),
)

assert np.isclose(
dewpoint_float,
dewpoint.iloc[0]
)


def test_first_solar_spectral_correction_deprecated():
with pytest.warns(pvlibDeprecationWarning,
match='Use pvlib.spectrum.spectral_factor_firstsolar'):
Expand Down
Loading