Skip to content

fix for *_TMY3.epw reading issue #782 #816

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

Merged
merged 1 commit into from
Nov 14, 2019
Merged
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
8 changes: 8 additions & 0 deletions docs/sphinx/source/whatsnew/v0.7.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ API Changes
- Methods `PVSystem.ashraeiam`, `PVSystem.physicaliam` and
`PVSystem.sapm_aoi_loss` are deprecated and will be removed in v0.8.

* Changes related to spectral modifier (:issue:`782`):
* Changes to functions
- Added the argument `pw_min` and `pw_max`, default values 0.1 and 8 resp.,
to `atmosphere.first_solar_spectral_correction`. This function now returns NaN
if pw value higher than `pw_max`.

* Calling :py:func:`pvlib.pvsystem.retrieve_sam` with no parameters will raise
an exception instead of displaying a dialog.
* The `times` keyword argument has been deprecated in the
Expand Down Expand Up @@ -145,6 +151,8 @@ Documentation
* Edited docstring for `pvsystem.sapm` to remove DataFrame option for input
`module`. The DataFrame option was never tested and would cause an error if
used. (:issue:`785`)
* Note warning about _TMY3.epw files retrieved from energyplus.net in docstring
of `epw.read_epw`

Removal of prior version deprecations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
31 changes: 21 additions & 10 deletions pvlib/atmosphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,9 @@ def gueymard94_pw(temp_air, relative_humidity):
return pw


def first_solar_spectral_correction(pw, airmass_absolute, module_type=None,
coefficients=None):
def first_solar_spectral_correction(pw, airmass_absolute,
module_type=None, coefficients=None,
min_pw=0.1, max_pw=8):
Copy link
Member

Choose a reason for hiding this comment

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

Need to add a test or two that calls the function using these kwargs, ideally different from the default.

r"""
Spectral mismatch modifier based on precipitable water and absolute
(pressure corrected) airmass.
Expand Down Expand Up @@ -364,6 +365,14 @@ def first_solar_spectral_correction(pw, airmass_absolute, module_type=None,
airmass_absolute : array-like
absolute (pressure corrected) airmass.

min_pw : float, default 0.1
minimum atmospheric precipitable water (cm). A lower pw value will be
automatically set to this minimum value to avoid model divergence.

max_pw : float, default 8
maximum atmospheric precipitable water (cm). If a higher value is
encountered it will be set to np.nan to avoid model divergence.

module_type : None or string, default None
a string specifying a cell type. Can be lower or upper case
letters. Admits values of 'cdte', 'monosi', 'xsi', 'multisi',
Expand Down Expand Up @@ -422,16 +431,18 @@ def first_solar_spectral_correction(pw, airmass_absolute, module_type=None,
# *** Pwat ***
# Replace Pwat Values below 0.1 cm with 0.1 cm to prevent model from
# diverging"

if np.min(pw) < 0.1:
pw = np.maximum(pw, 0.1)
warn('Exceptionally low Pwat values replaced with 0.1 cm to prevent' +
' model divergence')
pw = np.atleast_1d(pw)
pw = pw.astype('float64')
Copy link
Member

Choose a reason for hiding this comment

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

why is the type casting necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is necessary for the case when the input is an integer (or array of integers). In this case, the data type of the array is int32 and is not compatible with np.nan (which is a float) for the executing of pw[pw > max_pw] = np.nan. It raises an error if I don't cast the type here.

if np.min(pw) < min_pw:
pw = np.maximum(pw, min_pw)
warn('Exceptionally low pw values replaced with {0} cm to prevent '
'model divergence'.format(min_pw))

# Warn user about Pwat data that is exceptionally high
if np.max(pw) > 8:
warn('Exceptionally high Pwat values. Check input data:' +
' model may diverge in this range')
if np.max(pw) > max_pw:
pw[pw > max_pw] = np.nan
warn('Exceptionally high pw values replaced by np.nan: '
'check input data.')

# *** AMa ***
# Replace Extremely High AM with AM 10 to prevent model divergence
Expand Down
8 changes: 4 additions & 4 deletions pvlib/iotools/epw.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ def read_epw(filename, coerce_year=None):
=============== ====== =========================================


============================= ==============================================================================================================================================================
============================= ================================================================================================================================================================================================================== # noqa: E501
EPWData field description
============================= ==============================================================================================================================================================
============================= ==================================================================================================================================================================================================================
index A pandas datetime index. NOTE, times are set to local standard time (daylight savings is not included). Days run from 0-23h to comply with PVLIB's convention
year Year, from original EPW file. Can be overwritten using coerce function.
month Month, from original EPW file
Expand Down Expand Up @@ -99,14 +99,14 @@ def read_epw(filename, coerce_year=None):
ceiling_height Height of cloud base above local terrain (7777=unlimited), meter
present_weather_observation Indicator for remaining fields: If 0, then the observed weather codes are taken from the following field. If 9, then missing weather is assumed.
present_weather_codes Present weather code, see [1], chapter 2.9.1.28
precipitable_water Total precipitable water contained in a column of unit cross section from earth to top of atmosphere, cm
precipitable_water Total precipitable water contained in a column of unit cross section from earth to top of atmosphere, cm. Note that some old *_TMY3.epw files may have incorrect unit if it was retrieved from www.energyplus.net.
aerosol_optical_depth The broadband aerosol optical depth per unit of air mass due to extinction by aerosol component of atmosphere, unitless
snow_depth Snow depth in centimeters on the day indicated, (999 = missing data)
days_since_last_snowfall Number of days since last snowfall (maximum value of 88, where 88 = 88 or greater days; 99 = missing data)
albedo The ratio of reflected solar irradiance to global horizontal irradiance, unitless
liquid_precipitation_depth The amount of liquid precipitation observed at indicated time for the period indicated in the liquid precipitation quantity field, millimeter
liquid_precipitation_quantity The period of accumulation for the liquid precipitation depth field, hour
============================= ==============================================================================================================================================================
============================= ==================================================================================================================================================================================================================

References
----------
Expand Down
21 changes: 21 additions & 0 deletions pvlib/test/test_atmosphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,27 @@ def test_first_solar_spectral_correction_ambiguous():
atmosphere.first_solar_spectral_correction(1, 1)


def test_first_solar_spectral_correction_range():
with pytest.warns(UserWarning, match='Exceptionally high pw values'):
out = atmosphere.first_solar_spectral_correction(np.array([.1, 3, 10]),
np.array([1, 3, 5]),
module_type='monosi')
expected = np.array([0.96080878, 1.03055092, nan])
assert_allclose(out, expected, atol=1e-3)
with pytest.warns(UserWarning, match='Exceptionally high pw values'):
out = atmosphere.first_solar_spectral_correction(6, 1.5, max_pw=5,
module_type='monosi')
with pytest.warns(UserWarning, match='Exceptionally low pw values'):
out = atmosphere.first_solar_spectral_correction(np.array([0, 3, 8]),
np.array([1, 3, 5]),
module_type='monosi')
expected = np.array([0.96080878, 1.03055092, 1.04932727])
assert_allclose(out, expected, atol=1e-3)
with pytest.warns(UserWarning, match='Exceptionally low pw values'):
out = atmosphere.first_solar_spectral_correction(0.2, 1.5, min_pw=1,
module_type='monosi')


def test_kasten96_lt():
"""Test Linke turbidity factor calculated from AOD, Pwat and AM"""
amp = np.array([1, 3, 5])
Expand Down