Implement ANTS-2D bifacial irradiance model#2740
Implement ANTS-2D bifacial irradiance model#2740kandersolar wants to merge 46 commits intopvlib:mainfrom
Conversation
echedey-ls
left a comment
There was a problem hiding this comment.
Some first impressions; also, you may want to link to it in other bifacial "See also" sections.
| def vf_ground_sky_2d_integ(surface_tilt, gcr, height, pitch, max_rows=10, | ||
| npoints=100, vectorize=False): | ||
| @renamed_kwarg_warning("0.15.2", "surface_tilt", "tracker_rotation") | ||
| def vf_ground_sky_2d_integ(tracker_rotation, gcr, height, pitch, g0=0, g1=1, |
There was a problem hiding this comment.
| def vf_ground_sky_2d_integ(tracker_rotation, gcr, height, pitch, g0=0, g1=1, | |
| def vf_ground_sky_2d_integ(tracker_rotation, gcr, height, pitch, *, g0=0, g1=1, |
The rationale is that previous versions assume this call signature
vf_ground_sky_2d_integ(0, 0.5, 2, 4, 20, 200), where max_rows=20 and npoints=200
This wouldn't fail in the new version [1], where values g0 and g1 would take 20 and 200 respectively.
[1] At this branch
>>> import pvlib
>>> pvlib.bifacial.utils.vf_ground_sky_2d_integ(0, 0.5, 2, 4, 20, 200)
array(1.14662412e-05)
[2] On main
array([0.49984351])
| def vf_row_ground_2d_integ(surface_tilt, gcr, height=None, pitch=None, | ||
| x0=0, x1=1, g0=0, g1=1, max_rows=20): |
There was a problem hiding this comment.
I'd say this one is also subject to the problem described in previous comment
cwhanse
left a comment
There was a problem hiding this comment.
I'm OK reviewing the whole PR, if we can do it in a sequence of smaller review bites.
| * Add parameters ``g0`` and ``g1`` to allow segmented ground surfaces in | ||
| :py:func:`~pvlib.bifacial.utils.vf_ground_sky_2d_integ` and | ||
| :py:func:`~pvlib.bifacial.utils.vf_row_ground_2d_integ`. (:pull:`2740`) | ||
| * Accelerate :py:func:`~pvlib.bifacial.utils.vf_ground_sky_2d_integ` by one or |
There was a problem hiding this comment.
I think a comment here about "this makes bifacial.infinite_sheds faster would be appreciated.
| Projected solar zenith angle, defined around the same axis as | ||
| ``tracker_rotation``. [degree]. |
There was a problem hiding this comment.
I don't understand this definition. A vector can be projected onto a plane or another vector. An angle is formed by two vectors. "around" suggests an orientation of a vector.
tan_phi was defined in the docstrings for _solar_project_tangent as
Tangent of the angle between the zenith vector and the sun vector
projected to the plane defined by the zenith vector and surface_azimuth.
So I would expect phi to be the angle of the sun vector projected to a plane formed by....
Since phi isn't clear, tracker_rotation becomes unclear also.
| spacing (pitch). [unitless] | ||
| max_zenith : numeric, default 87 | ||
| height : float, optional | ||
| Height of the center point of the row above the ground; must be in the |
There was a problem hiding this comment.
Center point means the center of the row slant length? If that's correct I'd make it
Height above ground of the center point of the row slant length; must be in the
| Distance between two rows; must be in the same units as ``height``. | ||
| Required if ``g0`` is not zero or ``g1`` is not one. | ||
| g0 : numeric, default 0 | ||
| Position on the ground surface, as a fraction of the row-to-row |
There was a problem hiding this comment.
| Position on the ground surface, as a fraction of the row-to-row | |
| Left position on the ground surface, as a fraction of the row-to-row |
g0 is the left position on the ground, I think.
| spacing. ``g0=0`` corresponds to ground underneath the middle of the | ||
| left row. ``g0`` should be less than ``g1``. [unitless] | ||
| g1 : numeric, default 1 | ||
| Position on the ground surface, as a fraction of the row-to-row |
There was a problem hiding this comment.
| Position on the ground surface, as a fraction of the row-to-row | |
| Right position on the ground surface, as a fraction of the row-to-row |
| Required if ``g0`` is not zero or ``g1`` is not one. | ||
| g0 : numeric, default 0 | ||
| Position on the ground surface, as a fraction of the row-to-row | ||
| spacing. ``g0=0`` corresponds to ground underneath the middle of the |
There was a problem hiding this comment.
| spacing. ``g0=0`` corresponds to ground underneath the middle of the | |
| spacing. ``g0=0`` corresponds to ground underneath the center of the |
| left row. ``g0`` should be less than ``g1``. [unitless] | ||
| g1 : numeric, default 1 | ||
| Position on the ground surface, as a fraction of the row-to-row | ||
| spacing. ``g1=1`` corresponds to ground underneath the middle of the |
There was a problem hiding this comment.
| spacing. ``g1=1`` corresponds to ground underneath the middle of the | |
| spacing. ``g1=1`` corresponds to ground underneath the center of the |
| Maximum number of rows to consider on either side of the current | ||
| row. [unitless] |
There was a problem hiding this comment.
| Maximum number of rows to consider on either side of the current | |
| row. [unitless] | |
| Maximum number of rows to consider on either side of the left and right | |
| rows. [unitless] |
Related to the [max_rows, max_rows+1] comment below.
| # TODO seems like this should be np.arange(-max_rows, max_rows+1)? | ||
| # see GH #1867 | ||
| k = np.arange(-max_rows, max_rows)[:, np.newaxis, np.newaxis] |
There was a problem hiding this comment.
I would do (-max_rows, max_rows + 1) or is this a breaking change needing deprecation?
| same units as ``pitch``. Required if ``g0`` is not zero or ``g1`` is | ||
| not one. | ||
| pitch : float, optional | ||
| Distance between two rows; must be in the same units as ``height``. |
There was a problem hiding this comment.
| Distance between two rows; must be in the same units as ``height``. | |
| Distance between centers of two rows; must be in the same units as ``height``. |
"centers" is arbritrary. I think we want to avoid the confusion that the distance is the gap between the right edge of left row, and the left edge of right row.
[ ] Closes #xxxxdocs/sphinx/source/referencefor API changes.docs/sphinx/source/whatsnewfor all changes. Includes link to the GitHub Issue with:issue:`num`or this Pull Request with:pull:`num`. Includes contributor name and/or GitHub username (link with:ghuser:`user`).remote-data) and Milestone are assigned to the Pull Request and linked Issue.@AdamRJensen, @cwhanse, and I have a paper describing a new bifacial irradiance model called ANTS-2D. It is similar to pvlib's
infinite_shedsmodel, but extended to allow:Details available open-access here: https://doi.org/10.1109/JPHOTOV.2026.3677506
This PR is rather large. To summarize:
g0andg1parameters to the view factor functions inpvlib.bifacial.utils. These are analogous tox0andx1invf_row_sky_2d_integand extend the functions to subset the ground surface.vf_ground_sky_2d_integto use Hottel's crossed-string rule instead of burdensome numerical integration. This makes thenpointsandvectorizeparameters unnecessary.pvlib.bifacial.utilsto be cleaner with the new calculations.pvlib.bifacial.infinite_shedsto accommodate theutilschangespvlib.bifacial.ant2d, which houses the model itself and uses the newutilsfunctionality.Let me know if it would help reviewers to split it up and review separate PRs, starting with
utils.