-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Agrivoltaics - PAR diffuse fraction model #2048
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
Changes from 17 commits
90dd1e0
8cc7ffc
ae63127
5880453
5af860a
bdc2303
aec7870
02ebe81
c5d133d
149961e
eff3a25
d18827e
18619a4
feded95
b9aa23e
1c6d416
899844c
9268a44
bce50b6
2825e2c
764bf8b
0e0f836
0d23fe0
a7c84b5
d1bb64b
eeef154
6082fe7
94df738
ac9d45c
77f3ba8
a6c3c6b
f5449d7
bafe63b
1a5d0d9
189efe5
7c28be6
59faee0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Agrivoltaic Systems Modelling | ||
| ----------------------------- |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,145 @@ | ||||||
| """ | ||||||
| Calculating the diffuse PAR using Spitter's relationship | ||||||
| ========================================================= | ||||||
|
|
||||||
| This example demonstrates how to calculate the diffuse photosynthetically | ||||||
| active radiation (PAR) from total PAR using Spitter's relationship. | ||||||
| """ | ||||||
|
|
||||||
| # %% | ||||||
| # The photosynthetically active radiation (PAR) is a key component in the | ||||||
| # photosynthesis process of plants. As in photovoltaic systems, PAR can be | ||||||
|
echedey-ls marked this conversation as resolved.
Outdated
|
||||||
| # divided into direct and diffuse components. The diffuse fraction of PAR | ||||||
| # with respect to the total PAR is important in agrivoltaic systems, where | ||||||
| # crops are grown under solar panels. The diffuse fraction of PAR can be | ||||||
| # calculated using the Spitter's relationship [1]_ implemented in | ||||||
| # :py:func:`~pvlib.irradiance.spitters_relationship`. | ||||||
| # This model requires the solar zenith angle and the fraction of the global | ||||||
| # radiation that is diffuse as inputs. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To (perhaps) head off a discussion of whether "radiation" or "irradiance" should be used here: radiation is usually used when referring to the source, and irradiance (or irradiation) when referring to the receiver. So the sun emits radiation, and a tilted plane on the earth's surface receives solar irradiation. Either perspective seems OK to me in the context of this PR. But mixing PAR (..."radiation") with "irradiance" may be confusing to some. |
||||||
| # | ||||||
| # .. note:: | ||||||
| # Understanding the distinction between the global radiation and the PAR is | ||||||
| # a key concept. The global radiation is the total amount of solar radiation | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is global radiation limited to any particular bandwidth in [1]? If it is not, then I'd describe it as "broadband solar radiation" and not mention PV at all. Mentioning PV may imply to some that the global solar radiation means the radiation in the photovoltaic band, usually 400-1100nm.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I only see:
but no mention of the bandwidth. |
||||||
| # that is usually accounted for in PV applications, while the PAR is a | ||||||
| # measurement of a narrower range of wavelengths that are used in | ||||||
| # photosynthesis. See section on *Photosynthetically Active Radiation* in | ||||||
| # pp. 222-223 of [1]_. | ||||||
| # | ||||||
| # The key function used in this example is | ||||||
| # :py:func:`pvlib.irradiance.spitters_relationship` to calculate the diffuse | ||||||
| # PAR fraction, as a function of global diffuse fraction and solar zenith. | ||||||
| # | ||||||
| # References | ||||||
| # ---------- | ||||||
| # .. [1] C. J. T. Spitters, H. A. J. M. Toussaint, and J. Goudriaan, | ||||||
| # 'Separating the diffuse and direct component of global radiation and its | ||||||
| # implications for modeling canopy photosynthesis Part I. Components of | ||||||
| # incoming radiation', Agricultural and Forest Meteorology, vol. 38, | ||||||
| # no. 1, pp. 217-229, Oct. 1986, :doi:`10.1016/0168-1923(86)90060-2`. | ||||||
| # | ||||||
| # Read some example data | ||||||
| # ^^^^^^^^^^^^^^^^^^^^^^ | ||||||
|
|
||||||
| import pvlib | ||||||
| import pandas as pd | ||||||
| import matplotlib.pyplot as plt | ||||||
| from matplotlib.dates import DateFormatter | ||||||
| from pathlib import Path | ||||||
|
|
||||||
| # Read some sample data | ||||||
| DATA_FILE = Path(pvlib.__path__[0]).joinpath("data", "723170TYA.CSV") | ||||||
|
|
||||||
| tmy, metadata = pvlib.iotools.read_tmy3( | ||||||
| DATA_FILE, coerce_year=1990, map_variables=True | ||||||
| ) | ||||||
| tmy = tmy.filter( | ||||||
| ["ghi", "dhi", "dni", "pressure", "temp_air"] | ||||||
| ) # remaining data is not needed | ||||||
| tmy = tmy[ | ||||||
| "1990-04-11T06":"1990-04-11T22" | ||||||
| ] # select a single day for this example | ||||||
|
|
||||||
| solar_position = pvlib.solarposition.get_solarposition( | ||||||
| # TMY timestamp is at end of hour, so shift to center of interval | ||||||
| tmy.index.shift(freq="-30T"), | ||||||
| latitude=metadata["latitude"], | ||||||
| longitude=metadata["longitude"], | ||||||
| altitude=metadata["altitude"], | ||||||
| pressure=tmy["pressure"] * 100, # convert from millibar to Pa | ||||||
| temperature=tmy["temp_air"], | ||||||
| ) | ||||||
| solar_position.index = tmy.index # reset index to end of the hour | ||||||
|
|
||||||
| # %% | ||||||
| # Calculate Photosynthetically Active Radiation | ||||||
| # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||||||
| # The total PAR can be approximated as 0.50 times the global horizontal | ||||||
| # irradiance (GHI) for solar elevation higher that 10°. | ||||||
| # See section on *Photosynthetically Active Radiation* in pp. 222-223 of [1]_. | ||||||
|
|
||||||
| par = pd.DataFrame({"total": 0.50 * tmy["ghi"]}, index=tmy.index) | ||||||
|
|
||||||
| # Calculate global irradiance diffuse fraction, input of the Spitter's model | ||||||
| tmy["diffuse_fraction"] = tmy["dhi"] / tmy["ghi"] | ||||||
|
|
||||||
| # Calculate diffuse PAR fraction using Spitter's relationship | ||||||
| par["diffuse_fraction"] = pvlib.irradiance.spitters_relationship( | ||||||
| solar_position["zenith"], tmy["diffuse_fraction"] | ||||||
| ) | ||||||
|
|
||||||
| # Finally, calculate the diffuse PAR | ||||||
| par["diffuse"] = par["total"] * par["diffuse_fraction"] | ||||||
| par[solar_position["zenith"] > 80] = ( | ||||||
| 0 # set to zero for elevation < 10 degrees | ||||||
| ) | ||||||
|
|
||||||
| # %% | ||||||
| # Plot the results | ||||||
| # ^^^^^^^^^^^^^^^^ | ||||||
| # Irradiances on left axis, diffuse fractions on right axis | ||||||
|
|
||||||
| fig, ax_l = plt.subplots(figsize=(12, 6)) | ||||||
| ax_l.set( | ||||||
| xlabel="Time", | ||||||
| ylabel="Irradiance $[W/m^2]$", | ||||||
| title="Diffuse PAR using Spitter's relationship", | ||||||
| ) | ||||||
| ax_l.xaxis.set_major_formatter(DateFormatter("%H:%M", tz=tmy.index.tz)) | ||||||
| ax_l.plot(tmy.index, tmy["ghi"], label="Global: total", color="deepskyblue") | ||||||
| ax_l.plot( | ||||||
| tmy.index, | ||||||
| tmy["dhi"], | ||||||
| label="Global: diffuse", | ||||||
| color="skyblue", | ||||||
| linestyle="-.", | ||||||
| ) | ||||||
| ax_l.plot(tmy.index, par["total"], label="PAR: total", color="orangered") | ||||||
| ax_l.plot( | ||||||
| tmy.index, | ||||||
| par["diffuse"], | ||||||
| label="PAR: diffuse", | ||||||
| color="coral", | ||||||
| linestyle="-.", | ||||||
| ) | ||||||
| ax_l.grid() | ||||||
| ax_l.legend(loc="upper left") | ||||||
|
|
||||||
| ax_r = ax_l.twinx() | ||||||
| ax_r.set(ylabel="Diffuse fraction") | ||||||
| ax_r.plot( | ||||||
| tmy.index, | ||||||
| tmy["diffuse_fraction"], | ||||||
| label="Global diffuse fraction", | ||||||
| color="plum", | ||||||
| linestyle=":", | ||||||
| ) | ||||||
| ax_r.plot( | ||||||
| tmy.index, | ||||||
| par["diffuse_fraction"], | ||||||
| label="PAR diffuse fraction", | ||||||
| color="chocolate", | ||||||
| linestyle=":", | ||||||
| ) | ||||||
| ax_r.legend(loc="upper right") | ||||||
|
|
||||||
| plt.show() | ||||||
Uh oh!
There was an error while loading. Please reload this page.