Skip to content

Commit

Permalink
Shaded Fraction on Sloped Terrains - PR1725 partial continuation (#1962)
Browse files Browse the repository at this point in the history
* Update shading.py

* Minimal test

* Implementation

From NREL paper

* Fix, fix, fix, fix & format

* Format issues

* Extend tests (compare with singleaxis) & format with ruff

* Format fixes

* Upgrade tests

* Array -> Axis

* type

* Whatsnew

* xd

* bruh

* Minor Python optimization a la tracking.singleaxis

* Comment and minor optimizations

* Surface -> Axis

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Elevation -> Zenith

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Elev -> Zenith

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Update shading.py

* Update docstring

Co-Authored-By: Anton Driesse <9001027+adriesse@users.noreply.github.com>

* Add comments from `tracking.singleaxis`

Co-Authored-By: Will Holmgren <william.holmgren@gmail.com>
Co-Authored-By: Mark Mikofski <bwana.marko@yahoo.com>

* Singleaxis implementation port & test addition, based on old pvlib.tracking.singleaxis

* Update v0.10.4.rst

* Linter

* Code review

Co-Authored-By: Cliff Hansen <5393711+cwhanse@users.noreply.github.com>

* Add Fig 5 [1] (still gotta check the built output)

* Add caption, change size and describe in alternate text

* rST fixes ?

* Figures have captions, images do not

https://pandemic-overview.readthedocs.io/en/latest/myGuides/reStructuredText-Images-and-Figures-Examples.html#id18

* Flip arguments order

* I forgot 💀

* Linter are you happy now?

* Remove port test and add edge cases test

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Update test_shading.py

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Indentation xd

* Update test_shading.py

* I forgot how to code

* Align data

* Docstring suggestion from Kevin

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Update link to example?

* add linear shade loss for thin films

* add tests, update docs, what's new

* fix what's new gh issue and pr links

* fix trailing whitespace

* responding to comments

- move linear shade loss to shading module
- don't use ternary, doesn't work on vectors, instead use np.where()
- set cross axis default to zero
- test vectors
- update docs

* update docstring for linear shade loss

- applicable to other monolithic thin film like CIGS, not just CdTe
- only when shade is perpendicular to scribe lines

* update example in linear_shade_loss

* add figure and formulas to shaded fraction

* shaded fraction consistently

* Add alternative text to image

* Update implementation based on PSZ PR. See description.

Commit highlights ✨ :
* I think I made all the code a bit more legible; sorry for the big changes @mikofski
* Tests a bit more complete (not much, still consider the same test data)
* Rename shaded fraction acronym from `fs` to `sf`
* Asserts changed to `assert_allclose` for a more legible output in case of failure

Co-Authored-By: Mark Mikofski <bwana.marko@yahoo.com>

* Whatsnew entries

Co-Authored-By: Mark Mikofski <bwana.marko@yahoo.com>

* Linter

* Clear things, convert Mark's reference to a reference

* Linter

* Update according to changes at PSZA PR

* Another commit, another try

* Ahhh, I rebased too fast

* whatsnews

* Update v0.10.4.rst

* Update v0.10.3.rst

* Rename to `shaded_fraction1d`, change params to `surface_*` instead of `tracker_*`

* Left this tracker refs behind

* Change rename in rst entries

* Add another testcase

* Improve docs references, clarify nomenclature

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Update test_shading.py

* Remove linear_shade_loss

* First implementation of the new shaded fraction model (missing figure)

* Create Anderson_Jensen_2024_Fig3.png

* Update shading.py

* Update shading.py

* Update shading.py

* lintaaargggg

* Fill reference

* Next release 0.10.5?

* Fix tests

* Update test_shading.py

* Little improvement to table definitions

* Change `l` to `\ell`

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* `pvlib.tracking.projected_solar_zenith_angle` to `pvlib.shading.projected_solar_zenith_angle`

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* pitch references to `pitch`

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* `trackers_axis_azimuth` to `axis_azimuth`

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* whatsnews

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Update v0.10.5.rst

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Change `tilt`s to `rotation`s and add `axis_tilt`

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Forgot to update tests 💀

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Add examples section

* roles assumption messin w/ me docs 😲

* roles assumption messin w/ me docs 😲

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Update shading.py

* Update shading.py

* Add gallery example

* This was fixed in recent sphinx-gallery releases IIRC

* Extra empty line or admonition type unsupported

* Fix example link (hopefully 🙏  )

* Update shading.py

* Fix subsubsections?

* Nah, bulleted list didn't work

* tilted -> tracker, only affects text

* Typos and unreasonable physical values

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* See the Examples section below, not the unlinkable link

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* tracker -> row, param names, code and docs

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Fix broken example 🔧

Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com>

* "the row axis/axes" instead of ``axis_azimuth``

* Unnecessary math mode

Co-Authored-By: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com>

* Example suggestions and text trimming

Co-Authored-By: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com>

* whatsmes

* Add test to fix coverage issue

* Apply suggestions from code review (Adam)

Co-authored-by: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com>

* Update docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py

* Update docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py

---------

Co-authored-by: Kevin Anderson <57452607+kandersolar@users.noreply.github.com>
Co-authored-by: Anton Driesse <9001027+adriesse@users.noreply.github.com>
Co-authored-by: Will Holmgren <william.holmgren@gmail.com>
Co-authored-by: Mark Mikofski <bwana.marko@yahoo.com>
Co-authored-by: Cliff Hansen <5393711+cwhanse@users.noreply.github.com>
Co-authored-by: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com>
Co-authored-by: Kevin Anderson <kevin.anderso@gmail.com>
  • Loading branch information
8 people committed May 24, 2024
1 parent eeec98c commit d53f97e
Show file tree
Hide file tree
Showing 6 changed files with 505 additions and 2 deletions.
181 changes: 181 additions & 0 deletions docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
"""
Shaded fraction of a horizontal single-axis tracker
====================================================
This example illustrates how to calculate the 1D shaded fraction of three rows
in a North-South horizontal single axis tracker (HSAT) configuration.
"""

# %%
# :py:func:`pvlib.shading.shaded_fraction1d` exposes a useful method for the
# calculation of the shaded fraction of the width of a solar collector. Here,
# the width is defined as the dimension perpendicular to the axis of rotation.
# This method for calculating the shaded fraction only requires minor
# modifications to be applicable for fixed-tilt systems.
#
# It is highly recommended to read :py:func:`pvlib.shading.shaded_fraction1d`
# documentation to understand the input parameters and the method's
# capabilities. For more in-depth information, please see the journal paper
# `10.1063/5.0202220 <https://doi.org/10.1063/5.0202220>`_ describing
# the methodology.
#
# Let's start by obtaining the true-tracking angles for each of the rows and
# limiting the angles to the range of -50 to 50 degrees. This decision is
# done to create an example scenario with significant shading.
#
# Key functions used in this example are:
#
# 1. :py:func:`pvlib.tracking.singleaxis` to calculate the tracking angles.
# 2. :py:func:`pvlib.shading.projected_solar_zenith_angle` to calculate the
# projected solar zenith angle.
# 3. :py:func:`pvlib.shading.shaded_fraction1d` to calculate the shaded
# fractions.
#
# .. sectionauthor:: Echedey Luis <echelual (at) gmail.com>

import pvlib

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter

# Define the solar system parameters
latitude, longitude = 28.51, -13.89
altitude = pvlib.location.lookup_altitude(latitude, longitude)

axis_tilt = 3 # degrees, positive is upwards in the axis_azimuth direction
axis_azimuth = 180 # degrees, N-S tracking axis
collector_width = 3.2 # m
pitch = 4.15 # m
gcr = collector_width / pitch
cross_axis_slope = -5 # degrees
surface_to_axis_offset = 0.07 # m

# Generate a time range for the simulation
times = pd.date_range(
start="2024-01-01T05",
end="2024-01-01T21",
freq="5min",
tz="Atlantic/Canary",
)

# Calculate the solar position
solar_position = pvlib.solarposition.get_solarposition(
times, latitude, longitude, altitude
)
solar_azimuth = solar_position["azimuth"]
solar_zenith = solar_position["apparent_zenith"]

# Calculate the tracking angles
rotation_angle = pvlib.tracking.singleaxis(
solar_zenith,
solar_azimuth,
axis_tilt,
axis_azimuth,
max_angle=(-50, 50), # (min, max) degrees
backtrack=False,
gcr=gcr,
cross_axis_tilt=cross_axis_slope,
)["tracker_theta"]

# %%
# Once the tracker angles have been obtained, the next step is to calculate
# the shaded fraction. Special care must be taken
# to ensure that the shaded or shading tracker roles are correctly assigned
# depending on the solar position.
# This means we will have a result for each row, ``eastmost_shaded_fraction``,
# ``middle_shaded_fraction``, and ``westmost_shaded_fraction``.
# Switching the parameters will be based on the
# sign of :py:func:`pvlib.shading.projected_solar_zenith_angle`.
#
# The following code is verbose to make it easier to understand the process,
# but with some effort you may be able to simplify it. This verbosity also
# allows to change the premises easily per case, e.g., in case of a tracker
# failure or with a different system configuration.

psza = pvlib.shading.projected_solar_zenith_angle(
solar_zenith, solar_azimuth, axis_tilt, axis_azimuth
)

# Calculate the shaded fraction for the eastmost row
eastmost_shaded_fraction = np.where(
psza < 0,
0, # no shaded fraction in the morning
# shaded fraction in the evening
pvlib.shading.shaded_fraction1d(
solar_zenith,
solar_azimuth,
axis_azimuth,
shaded_row_rotation=rotation_angle,
axis_tilt=axis_tilt,
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
cross_axis_slope=cross_axis_slope,
shading_row_rotation=rotation_angle,
),
)

# Calculate the shaded fraction for the middle row
middle_shaded_fraction = np.where(
psza < 0,
# shaded fraction in the morning
pvlib.shading.shaded_fraction1d(
solar_zenith,
solar_azimuth,
axis_azimuth,
shaded_row_rotation=rotation_angle,
axis_tilt=axis_tilt,
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
cross_axis_slope=cross_axis_slope,
shading_row_rotation=rotation_angle,
),
# shaded fraction in the evening
pvlib.shading.shaded_fraction1d(
solar_zenith,
solar_azimuth,
axis_azimuth,
shaded_row_rotation=rotation_angle,
axis_tilt=axis_tilt,
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
cross_axis_slope=cross_axis_slope,
shading_row_rotation=rotation_angle,
),
)

# Calculate the shaded fraction for the westmost row
westmost_shaded_fraction = np.where(
psza < 0,
# shaded fraction in the morning
pvlib.shading.shaded_fraction1d(
solar_zenith,
solar_azimuth,
axis_azimuth,
shaded_row_rotation=rotation_angle,
axis_tilt=axis_tilt,
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
cross_axis_slope=cross_axis_slope,
shading_row_rotation=rotation_angle,
),
0, # no shaded fraction in the evening
)

# %%
# Plot the shaded fraction result for each row:
plt.plot(times, eastmost_shaded_fraction, label="East-most", color="blue")
plt.plot(times, middle_shaded_fraction, label="Middle", color="green",
linewidth=3, linestyle="--") # fmt: skip
plt.plot(times, westmost_shaded_fraction, label="West-most", color="red")
plt.title(r"$shaded\_fraction1d$ of each row vs time")
plt.xlabel("Time")
plt.gca().xaxis.set_major_formatter(DateFormatter("%H:%M"))
plt.ylabel("Shaded Fraction")
plt.legend()
plt.show()
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ Shading
shading.masking_angle_passias
shading.sky_diffuse_passias
shading.projected_solar_zenith_angle
shading.shaded_fraction1d

7 changes: 6 additions & 1 deletion docs/sphinx/source/whatsnew/v0.11.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Deprecations

Enhancements
~~~~~~~~~~~~
* Add function :py:func:`pvlib.shading.shaded_fraction1d`, to calculate the
shade perpendicular to ``axis_azimuth``. The function is applicable to both
fixed-tilt and one-axis tracking systems.
(:issue:`1689`, :pull:`1725`, :pull:`1962`)


Bug fixes
Expand All @@ -36,4 +40,5 @@ Requirements
Contributors
~~~~~~~~~~~~
* Cliff Hansen (:ghuser:`cwhanse`)
* Siddharth Kaul (:ghuser:`k10blogger`)
* Mark Mikofski (:ghuser:`mikofski`)
* Siddharth Kaul (:ghuser:`k10blogger`)
Loading

0 comments on commit d53f97e

Please sign in to comment.