Skip to content
Open
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
2 changes: 1 addition & 1 deletion docs/examples/shading/plot_martinez_shade_loss.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
shading_row_rotation=tracker_theta,
collector_width=width,
pitch=pitch,
cross_axis_slope=cross_axis_tilt,
cross_axis_tilt=cross_axis_tilt,
)

# %%
Expand Down
12 changes: 6 additions & 6 deletions docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
collector_width = 3.2 # m
pitch = 4.15 # m
gcr = collector_width / pitch
cross_axis_slope = -5 # degrees
cross_axis_tilt = -5 # degrees
surface_to_axis_offset = 0.07 # m

# Generate a time range for the simulation
Expand All @@ -76,7 +76,7 @@
max_angle=(-50, 50), # (min, max) degrees
backtrack=False,
gcr=gcr,
cross_axis_tilt=cross_axis_slope,
cross_axis_tilt=cross_axis_tilt,
)["tracker_theta"]

# %%
Expand Down Expand Up @@ -112,7 +112,7 @@
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
cross_axis_slope=cross_axis_slope,
cross_axis_tilt=cross_axis_tilt,
shading_row_rotation=rotation_angle,
),
)
Expand All @@ -130,7 +130,7 @@
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
cross_axis_slope=cross_axis_slope,
cross_axis_tilt=cross_axis_tilt,
shading_row_rotation=rotation_angle,
),
# shaded fraction in the evening
Expand All @@ -143,7 +143,7 @@
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
cross_axis_slope=cross_axis_slope,
cross_axis_tilt=cross_axis_tilt,
shading_row_rotation=rotation_angle,
),
)
Expand All @@ -161,7 +161,7 @@
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
cross_axis_slope=cross_axis_slope,
cross_axis_tilt=cross_axis_tilt,
shading_row_rotation=rotation_angle,
),
0, # no shaded fraction in the evening
Expand Down
14 changes: 14 additions & 0 deletions docs/sphinx/source/user_guide/extras/nomenclature.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ There is a convention on consistent variable names throughout the library:
bhi
Beam/direct horizontal irradiance

cross_axis_tilt
Cross-axis tilt angle [°].
Copy link
Member

Choose a reason for hiding this comment

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

I guess we should go for this syntax given the current style guide and the rest of the nomenclature page

Suggested change
Cross-axis tilt angle [°].
Cross-axis tilt angle. [°]

Consider two parallel rows of modules at different height;
``cross_axis_tilt`` is the angle formed by the line formed by the
intersection between the slope containing the tracker axes and a plane
perpendicular to the tracker axes, and the horizontal plane.
Cross-axis tilt is measured by using a right-handed convention.
For example, trackers with axis azimuth of 180 degrees (heading south)
will have a negative cross-axis tilt if the tracker axes plane slopes
down to the east and positive cross-axis tilt if the tracker axes plane
slopes up to the east.
Use :func:`~pvlib.tracking.calc_cross_axis_tilt` to calculate
``cross_axis_tilt``
Comment on lines +53 to +59
Copy link
Member

Choose a reason for hiding this comment

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

Just a few style suggestions, mostly my personal preference. Feel free to take them all, cherry pick a few, or reject them all.
Removed "by", swapped "degrees" for °, added a comma after east.

Suggested change
Cross-axis tilt is measured by using a right-handed convention.
For example, trackers with axis azimuth of 180 degrees (heading south)
will have a negative cross-axis tilt if the tracker axes plane slopes
down to the east and positive cross-axis tilt if the tracker axes plane
slopes up to the east.
Use :func:`~pvlib.tracking.calc_cross_axis_tilt` to calculate
``cross_axis_tilt``
Cross-axis tilt is measured using a right-handed convention.
For example, trackers with axis azimuth of 180° (heading south)
will have a negative cross-axis tilt if the tracker axes plane slopes
down to the east, and positive cross-axis tilt if the tracker axes plane
slopes up to the east.
Use :func:`~pvlib.tracking.calc_cross_axis_tilt` to calculate
``cross_axis_tilt``


dhi
Diffuse horizontal irradiance

Expand Down
1 change: 1 addition & 0 deletions docs/sphinx/source/whatsnew/v0.13.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Deprecations
* Deprecate :py:func:`~pvlib.modelchain.get_orientation`. (:pull:`2495`)
* Rename parameter name ``aparent_azimuth`` to ``solar_azimuth`` in :py:func:`~pvlib.tracking.singleaxis`.
(:issue:`2479`, :pull:`2480`)
* Rename parameter ``cross_axis_slope`` to ``cross_axis_tilt`` in :py:func:`pvlib.shading.shaded_fraction1d`. (:issue:`2334`, :pull:`2543`)

Bug fixes
~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion pvlib/_deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def renamed_kwarg_warning(since, old_param_name, new_param_name, removal=""):
Not compatible with positional-only arguments.

.. note::
Documentation for the function may updated to reflect the new parameter
Affected function docstring may be updated to reflect the new parameter
name; it is suggested to add a |.. versionchanged::| directive.

Parameters
Expand Down
32 changes: 20 additions & 12 deletions pvlib/shading.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import pandas as pd
from pvlib.tools import sind, cosd

from pvlib._deprecation import renamed_kwarg_warning


def ground_angle(surface_tilt, gcr, slant_height):
"""
Expand Down Expand Up @@ -344,6 +346,12 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth,
return theta_T


@renamed_kwarg_warning(
since="0.13.1",
old_param_name="cross_axis_slope",
new_param_name="cross_axis_tilt",
removal="0.15.0",
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
removal="0.15.0",

We usually don't specify a removal version as there's not standard timeline for when minor versions come out. If we really wanted to specify a removal, I think this should be in the form of a date, e.g., removal="Earliest September 2026".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I never thought of that, but looks a promising idea

Copy link
Member

@AdamRJensen AdamRJensen Sep 9, 2025

Choose a reason for hiding this comment

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

I'm interested in what @wholmgren thinks of this?

)
def shaded_fraction1d(
solar_zenith,
solar_azimuth,
Expand All @@ -354,7 +362,7 @@ def shaded_fraction1d(
pitch,
axis_tilt=0,
surface_to_axis_offset=0,
cross_axis_slope=0,
cross_axis_tilt=0,
shading_row_rotation=None,
):
r"""
Expand Down Expand Up @@ -397,10 +405,10 @@ def shaded_fraction1d(
surface_to_axis_offset : numeric, default 0
Distance between the rotating axis and the collector surface.
May be used to account for a torque tube offset.
cross_axis_slope : numeric, default 0
Angle of the plane containing the rows' axes from
cross_axis_tilt : numeric, default 0
Angle of the plane containing the rows' axes relative to
horizontal. Right-handed rotation with respect to the rows axes.
In degrees :math:`^{\circ}`.
See :term:`cross_axis_tilt`. In degrees :math:`^{\circ}`.
shading_row_rotation : numeric, optional
Right-handed rotation of the row casting the shadow, with respect
to the row axis. In degrees :math:`^{\circ}`.
Expand Down Expand Up @@ -430,7 +438,7 @@ def shaded_fraction1d(
+------------------+----------------------------+ |
| :math:`\theta_2` | ``shaded_row_rotation`` | Degrees |
+------------------+----------------------------+ :math:`^{\circ}` |
| :math:`\beta_c` | ``cross_axis_slope`` | |
| :math:`\beta_c` | ``cross_axis_tilt`` | |
+------------------+----------------------------+---------------------+
| :math:`p` | ``pitch`` | Any consistent |
+------------------+----------------------------+ length unit across |
Expand All @@ -452,7 +460,7 @@ def shaded_fraction1d(
>>> shaded_fraction1d(solar_zenith=80, solar_azimuth=135,
... axis_azimuth=90, shaded_row_rotation=30, shading_row_rotation=30,
... collector_width=2, pitch=3, axis_tilt=0,
... surface_to_axis_offset=0.05, cross_axis_slope=0)
... surface_to_axis_offset=0.05, cross_axis_tilt=0)
0.47755694708090535

**Fixed-tilt north-facing array on sloped terrain**
Expand All @@ -466,7 +474,7 @@ def shaded_fraction1d(
>>> shaded_fraction1d(solar_zenith=80, solar_azimuth=75.5,
... axis_azimuth=270, shaded_row_rotation=50, shading_row_rotation=30,
... collector_width=2.5, pitch=4, axis_tilt=10,
... surface_to_axis_offset=0.05, cross_axis_slope=0)
... surface_to_axis_offset=0.05, cross_axis_tilt=0)
0.793244836197256

**N-S single-axis tracker on sloped terrain**
Expand All @@ -478,7 +486,7 @@ def shaded_fraction1d(

>>> shaded_fraction1d(solar_zenith=80, solar_azimuth=90, axis_azimuth=180,
... shaded_row_rotation=-30, collector_width=1.4, pitch=3, axis_tilt=0,
... surface_to_axis_offset=0.10, cross_axis_slope=7)
... surface_to_axis_offset=0.10, cross_axis_tilt=7)
0.8242176864434579

Note the previous example only is valid for the shaded fraction of the
Expand All @@ -493,7 +501,7 @@ def shaded_fraction1d(

>>> shaded_fraction1d(solar_zenith=80, solar_azimuth=270, axis_azimuth=180,
... shaded_row_rotation=30, collector_width=1.4, pitch=3, axis_tilt=0,
... surface_to_axis_offset=0.10, cross_axis_slope=7)
... surface_to_axis_offset=0.10, cross_axis_tilt=7)
0.018002567182254348

You must switch the input/output depending on the
Expand Down Expand Up @@ -528,7 +536,7 @@ def shaded_fraction1d(
# calculate repeated elements
thetas_1_S_diff = shading_row_rotation - projected_solar_zenith
thetas_2_S_diff = shaded_row_rotation - projected_solar_zenith
thetaS_rotation_diff = projected_solar_zenith - cross_axis_slope
thetaS_rotation_diff = projected_solar_zenith - cross_axis_tilt

cos_theta_2_S_diff_abs = np.abs(cosd(thetas_2_S_diff))

Expand All @@ -548,7 +556,7 @@ def shaded_fraction1d(
/ collector_width
* cosd(thetaS_rotation_diff)
/ cos_theta_2_S_diff_abs
/ cosd(cross_axis_slope)
/ cosd(cross_axis_tilt)
)
)

Expand Down Expand Up @@ -660,7 +668,7 @@ def direct_martinez(
>>> solar_zenith=80, solar_azimuth=180,
>>> axis_azimuth=90, shaded_row_rotation=25,
>>> collector_width=0.5, pitch=1, surface_to_axis_offset=0,
>>> cross_axis_slope=5.711, shading_row_rotation=50)
>>> cross_axis_tilt=5.711, shading_row_rotation=50)
>>> # calculation of the number of shaded blocks
>>> shaded_blocks = np.ceil(total_blocks*shaded_fraction)
>>> # apply the Martinez power losses to the calculated shading
Expand Down
14 changes: 4 additions & 10 deletions pvlib/tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
def singleaxis(apparent_zenith, solar_azimuth,
axis_tilt=0, axis_azimuth=0, max_angle=90,
backtrack=True, gcr=2.0/7.0, cross_axis_tilt=0):
"""
r"""
Determine the rotation angle of a single-axis tracker when given particular
solar zenith and azimuth angles.

Expand Down Expand Up @@ -80,15 +80,9 @@ def singleaxis(apparent_zenith, solar_azimuth,
2/7 is default. ``gcr`` must be <=1.

cross_axis_tilt : float, default 0.0
The angle, relative to horizontal, of the line formed by the
intersection between the slope containing the tracker axes and a plane
perpendicular to the tracker axes. The cross-axis tilt should be
specified using a right-handed convention. For example, trackers with
axis azimuth of 180 degrees (heading south) will have a negative
cross-axis tilt if the tracker axes plane slopes down to the east and
positive cross-axis tilt if the tracker axes plane slopes down to the
west. Use :func:`~pvlib.tracking.calc_cross_axis_tilt` to calculate
``cross_axis_tilt``. [degrees]
Angle of the plane containing the rows' axes relative to
horizontal. Right-handed rotation with respect to the rows axes.
See :term:`cross_axis_tilt`. In degrees :math:`^{\circ}`.

Returns
-------
Expand Down
23 changes: 21 additions & 2 deletions tests/test_shading.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
from pvlib import shading
from pvlib.tools import atand

from .conftest import fail_on_pvlib_version
from pvlib._deprecation import pvlibDeprecationWarning


@pytest.fixture
def test_system():
Expand Down Expand Up @@ -258,7 +261,7 @@ def sf1d_premises_and_expected():
),
) # fmt: skip

test_data["cross_axis_slope"] = atand(
test_data["cross_axis_tilt"] = atand(
(test_data["z_R"] - test_data["z_L"])
/ (test_data["x_L"] - test_data["x_R"])
)
Expand Down Expand Up @@ -314,7 +317,7 @@ def test_shaded_fraction1d_unprovided_shading_row_rotation():
test_data = pd.DataFrame(
columns=[
"shaded_row_rotation", "surface_to_axis_offset", "collector_width",
"solar_zenith", "cross_axis_slope", "pitch", "solar_azimuth",
"solar_zenith", "cross_axis_tilt", "pitch", "solar_azimuth",
"axis_azimuth", "expected_sf",
],
data=[
Expand All @@ -329,6 +332,22 @@ def test_shaded_fraction1d_unprovided_shading_row_rotation():
assert_allclose(sf, expected_sf, atol=1e-2)


@fail_on_pvlib_version("0.15.0")
def test_shaded_fraction1d_renamed_cross_axis_slope2cross_axis_tilt():
# Tests shaded_fraction1d with cross_axis_slope instead of cross_axis_tilt
with pytest.warns(pvlibDeprecationWarning, match="cross_axis_slope"):
shading.shaded_fraction1d(
solar_zenith=60,
solar_azimuth=90,
axis_azimuth=180,
shaded_row_rotation=30,
collector_width=3,
pitch=7,
surface_to_axis_offset=0,
cross_axis_slope=0,
)


@pytest.fixture
def direct_martinez_Table2():
"""
Expand Down
Loading