Skip to content

Commit

Permalink
Implement irradiance.complete_irradiance with component sum equations (
Browse files Browse the repository at this point in the history
…#1567)

* added new irradiance function for component sum

* added to docstrings

* updated docstrings

* updated methods with new component_sum_irradiance() function

* added associated unit test for the new component sum function

* added units tests for the component_sum_irradiance() function

* added whatsnew file for v0.9.4

* fixed modelchain error to stop unit test erroring

* removed clearsky_dni arg for cases where it's not used

* updated naming conventions for component_sum_irradiance function in modelchains

* updated the routines to remove pep8 errors, added to clearsky_dni docstring

* updated the routine to return dataframe after calculating component sum + other suggestions

* updated the PR based on @kanderso-nrel review

* made updates based on kanderso-nrel's suggestions

* updated all the unit tests to pass

* Update pvlib/irradiance.py

Co-authored-by: Kevin Anderson <[email protected]>

* Update pvlib/irradiance.py

Co-authored-by: Kevin Anderson <[email protected]>

* moved warning out of dni generation call (just ghi and dhi)

* fix sticklerci formatting errors

* Update pvlib/irradiance.py

Co-authored-by: Kevin Anderson <[email protected]>

* updates to name-changed to 'complete_irradiance'

* fixed over-indentation error

* removed default none from function params

* Update docs/sphinx/source/whatsnew/v0.9.4.rst

Co-authored-by: Cliff Hansen <[email protected]>

* made updates based on @cwhanse's recommendations

* Update pvlib/irradiance.py

Co-authored-by: Will Holmgren <[email protected]>

* Update pvlib/irradiance.py

Co-authored-by: Will Holmgren <[email protected]>

* changed to pytest error raise based on @wholmgren's recommendation

* Made updates to code based on @wholmgren's recommendations

* fix pep8 error 2

* updated modelchains to use zenith instead of apparent zenith

* check that unit tests run

* undo ModelChain.complete_irradiance test changes

Co-authored-by: Perry <[email protected]>
Co-authored-by: Kevin Anderson <[email protected]>
Co-authored-by: Cliff Hansen <[email protected]>
Co-authored-by: Will Holmgren <[email protected]>
  • Loading branch information
5 people authored Nov 1, 2022
1 parent dd6062a commit e50def0
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 91 deletions.
1 change: 1 addition & 0 deletions docs/sphinx/source/reference/irradiance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Decomposing and combining irradiance
irradiance.poa_components
irradiance.get_ground_diffuse
irradiance.dni
irradiance.complete_irradiance

Transposition models
--------------------
Expand Down
6 changes: 5 additions & 1 deletion docs/sphinx/source/whatsnew/v0.9.4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ Deprecations
Enhancements
~~~~~~~~~~~~
* Multiple code style issues fixed that were reported by LGTM analysis. (:issue:`1275`, :pull:`1559`)
* Added a function to calculate one of GHI, DHI, and DNI from values of the other two.
:py:func:`~pvlib.irradiance.complete_irradiance`
(:issue:`1565`, :pull:`1567`)
* Add optional ``return_components`` parameter to :py:func:`pvlib.irradiance.haydavies` to return
individual diffuse irradiance components (:issue:`1553`, :pull:`1568`)


Bug fixes
~~~~~~~~~



Testing
~~~~~~~
* Corrected a flawed test for :py:func:`~pvlib.irradiance.get_ground_diffuse` (:issue:`1569`, :pull:`1575`)
Expand All @@ -36,6 +39,7 @@ Requirements

Contributors
~~~~~~~~~~~~
* Kirsten Perry (:ghuser:`kperrynrel`)
* Christian Orner (:ghuser:`chrisorner`)
* Saurabh Aneja (:ghuser:`spaneja`)
* Marcus Boumans (:ghuser:`bowie2211`)
65 changes: 65 additions & 0 deletions pvlib/irradiance.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import pandas as pd

from pvlib import atmosphere, solarposition, tools
import pvlib # used to avoid dni name collision in complete_irradiance


# see References section of get_ground_diffuse function
Expand Down Expand Up @@ -2948,3 +2949,67 @@ def dni(ghi, dhi, zenith, clearsky_dni=None, clearsky_tolerance=1.1,
(zenith < zenith_threshold_for_zero_dni) &
(dni > max_dni)] = max_dni
return dni


def complete_irradiance(solar_zenith,
ghi=None,
dhi=None,
dni=None,
dni_clear=None):
r"""
Use the component sum equations to calculate the missing series, using
the other available time series. One of the three parameters (ghi, dhi,
dni) is passed as None, and the other associated series passed are used to
calculate the missing series value.
The "component sum" or "closure" equation relates the three
primary irradiance components as follows:
.. math::
GHI = DHI + DNI \cos(\theta_z)
Parameters
----------
solar_zenith : Series
Zenith angles in decimal degrees, with datetime index.
Angles must be >=0 and <=180. Must have the same datetime index
as ghi, dhi, and dni series, when available.
ghi : Series, optional
Pandas series of dni data, with datetime index. Must have the same
datetime index as dni, dhi, and zenith series, when available.
dhi : Series, optional
Pandas series of dni data, with datetime index. Must have the same
datetime index as ghi, dni, and zenith series, when available.
dni : Series, optional
Pandas series of dni data, with datetime index. Must have the same
datetime index as ghi, dhi, and zenith series, when available.
dni_clear : Series, optional
Pandas series of clearsky dni data. Must have the same datetime index
as ghi, dhi, dni, and zenith series, when available. See
:py:func:`dni` for details.
Returns
-------
component_sum_df : Dataframe
Pandas series of 'ghi', 'dhi', and 'dni' columns with datetime index
"""
if ghi is not None and dhi is not None and dni is None:
dni = pvlib.irradiance.dni(ghi, dhi, solar_zenith,
clearsky_dni=dni_clear,
clearsky_tolerance=1.1)
elif dni is not None and dhi is not None and ghi is None:
ghi = (dhi + dni * tools.cosd(solar_zenith))
elif dni is not None and ghi is not None and dhi is None:
dhi = (ghi - dni * tools.cosd(solar_zenith))
else:
raise ValueError(
"Please check that exactly one of ghi, dhi and dni parameters "
"is set to None"
)
# Merge the outputs into a master dataframe containing 'ghi', 'dhi',
# and 'dni' columns
component_sum_df = pd.DataFrame({'ghi': ghi,
'dhi': dhi,
'dni': dni})
return component_sum_df
36 changes: 21 additions & 15 deletions pvlib/modelchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1289,13 +1289,13 @@ def complete_irradiance(self, weather):
self._assign_times()
self.results.solar_position = self.location.get_solarposition(
self.results.times, method=self.solar_position_method)

# Calculate the irradiance using the component sum equations,
# if needed
if isinstance(weather, tuple):
for w in self.results.weather:
self._complete_irradiance(w)
else:
self._complete_irradiance(self.results.weather)

return self

def _complete_irradiance(self, weather):
Expand All @@ -1304,26 +1304,32 @@ def _complete_irradiance(self, weather):
"Results can be too high or negative.\n" +
"Help to improve this function on github:\n" +
"https://github.com/pvlib/pvlib-python \n")

if {'ghi', 'dhi'} <= icolumns and 'dni' not in icolumns:
clearsky = self.location.get_clearsky(
weather.index, solar_position=self.results.solar_position)
weather.loc[:, 'dni'] = pvlib.irradiance.dni(
weather.loc[:, 'ghi'], weather.loc[:, 'dhi'],
self.results.solar_position.zenith,
clearsky_dni=clearsky['dni'],
clearsky_tolerance=1.1)
complete_irrad_df = pvlib.irradiance.complete_irradiance(
solar_zenith=self.results.solar_position.zenith,
ghi=weather.ghi,
dhi=weather.dhi,
dni=None,
dni_clear=clearsky.dni)
weather.loc[:, 'dni'] = complete_irrad_df.dni
elif {'dni', 'dhi'} <= icolumns and 'ghi' not in icolumns:
warnings.warn(wrn_txt, UserWarning)
weather.loc[:, 'ghi'] = (
weather.dhi + weather.dni *
tools.cosd(self.results.solar_position.zenith)
)
complete_irrad_df = pvlib.irradiance.complete_irradiance(
solar_zenith=self.results.solar_position.zenith,
ghi=None,
dhi=weather.dhi,
dni=weather.dni)
weather.loc[:, 'ghi'] = complete_irrad_df.ghi
elif {'dni', 'ghi'} <= icolumns and 'dhi' not in icolumns:
warnings.warn(wrn_txt, UserWarning)
weather.loc[:, 'dhi'] = (
weather.ghi - weather.dni *
tools.cosd(self.results.solar_position.zenith))
complete_irrad_df = pvlib.irradiance.complete_irradiance(
solar_zenith=self.results.solar_position.zenith,
ghi=weather.ghi,
dhi=None,
dni=weather.dni)
weather.loc[:, 'dhi'] = complete_irrad_df.dhi

def _prep_inputs_solar_pos(self, weather):
"""
Expand Down
Loading

0 comments on commit e50def0

Please sign in to comment.