Skip to content

Add scipy.optimize.elementwise.find_root (method='chandrupatla') to bishop88 functions #2498

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

kandersolar
Copy link
Member

@kandersolar kandersolar commented Jul 8, 2025

  • Partway towards Use scipy's new optimize.elementwise functions #2497
  • I am familiar with the contributing guidelines
  • Tests added
  • [ ] Updates entries in docs/sphinx/source/reference for API changes.
  • Adds description and name entries in the appropriate "what's new" file in docs/sphinx/source/whatsnew for 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`).
  • New code is fully documented. Includes numpydoc compliant docstrings, examples, and comments where necessary.
  • Pull request is nearly complete and ready for detailed review.
  • Maintainer: Appropriate GitHub Labels (including remote-data) and Milestone are assigned to the Pull Request and linked Issue.

This PR adds method='chandrupatla' to the bishop88 functions. I decided to leave lambertw for a separate PR, since it's not clear how to opt into using the new scipy function instead of our golden section search.

Some basic timing comparisons for the wrapper functions in pvlib.pvsystem (all times in milliseconds):

function inputs lambertw brentq newton chandrupatla
singlediode 8760 simulation 156 6370 32.2 48
v_from_i I-V curve, 1000 points 0.685 136 3.39 5.62
i_from_v I-V curve, 1000 points 0.664 87.5 1.06 3.64

Still need to figure out a clean way to skip the tests on python 3.9, where this new functionality is not available.

@kandersolar kandersolar added this to the v0.13.1 milestone Jul 8, 2025
@@ -162,12 +162,11 @@ def bishop88(diode_voltage, photocurrent, saturation_current,
# calculate temporary values to simplify calculations
v_star = diode_voltage / nNsVth # non-dimensional diode voltage
g_sh = 1.0 / resistance_shunt # conductance
if breakdown_factor > 0: # reverse bias is considered
Copy link
Member Author

@kandersolar kandersolar Jul 8, 2025

Choose a reason for hiding this comment

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

Had to get rid of the if for vectorized evaluation in find_root. The math works out the same either way, it's just a bit of unnecessary computation when breakdown_factor is zero.

(see also #1821)

Copy link
Member

Choose a reason for hiding this comment

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

Not sure now why that was there, maybe thinking to save few microseconds.

@@ -177,18 +176,14 @@ def bishop88(diode_voltage, photocurrent, saturation_current,
grad_i_recomb = np.where(is_recomb, i_recomb / v_recomb, 0)
grad_2i_recomb = np.where(is_recomb, 2 * grad_i_recomb / v_recomb, 0)
g_diode = saturation_current * np.exp(v_star) / nNsVth # conductance
if breakdown_factor > 0: # reverse bias is considered
Copy link
Member Author

Choose a reason for hiding this comment

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

Same here

@mikofski
Copy link
Member

mikofski commented Jul 9, 2025

I think Chandrupatla is a great alternative to Brent Q or Toms-748, neither which are vectorized. The Cythonized version of Brent Q is problematic to deploy in pvlib, and Newton can fail if guesses are too far from the roots. Another option to consider is Toms-748 with Numba

@echedey-ls
Copy link
Contributor

Another option to consider is Toms-748 with Numba

Feel free to open an issue regarding that! It's a bit out-of-scope for this PR IMO (not the issue, as long as it's timing gets compared there). It would make for a great contribution thou.

Copy link
Contributor

@echedey-ls echedey-ls left a comment

Choose a reason for hiding this comment

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

Nice PR :)
Waiting for it to get merged soon.

Comment on lines 412 to 413
Either ``'newton'``, ``'brentq'``, or ``'chandrupatla'`` (requires
scipy 1.15 or greater). ''method'' must be ``'newton'``
Copy link
Contributor

Choose a reason for hiding this comment

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

At this point I would send users to See methods allowed by :py:func:`pvlib.singlediode.bishop88_mpp` or equivalent.

kandersolar and others added 4 commits July 9, 2025 09:30
Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com>
@kandersolar
Copy link
Member Author

Coverage failure should be ignored. It is failing because coverage is calculated based on the python 3.9 jobs, and these tests are skipped on python 3.9 because of the required scipy version.

@@ -162,12 +162,11 @@ def bishop88(diode_voltage, photocurrent, saturation_current,
# calculate temporary values to simplify calculations
v_star = diode_voltage / nNsVth # non-dimensional diode voltage
g_sh = 1.0 / resistance_shunt # conductance
if breakdown_factor > 0: # reverse bias is considered
Copy link
Member

Choose a reason for hiding this comment

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

Not sure now why that was there, maybe thinking to save few microseconds.

Either ``'newton'`` or ``'brentq'``. ''method'' must be ``'newton'``
if ``breakdown_factor`` is not 0.
Either ``'newton'``, ``'brentq'``, or ``'chandrupatla'``.
''method'' must be ``'newton'`` if ``breakdown_factor`` is not 0.
Copy link
Member

Choose a reason for hiding this comment

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

Why this requirement for 'newton'? The arguments passed when method='brentq' or method='chandrupatla' include all the reverse bias parameters.

Copy link
Member Author

Choose a reason for hiding this comment

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

I do not know the answer to this. I see in #948 you wrote this:

The Lambert W technique cannot solve the single diode equation with the term for current at reverse bias. The Bishop '88 methods can solve the equation. Tested with method='newton', not clear if method='brentq' is reliable for this application.

Copy link
Member

Choose a reason for hiding this comment

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

My apologies for asking you to explain something I added 5 years ago :). I didn't pick up that all you did was reformat a bit of documentation.

I think that comment was added because the tests didn't confirm that 'brentq' works. I can't think of a reason why it wouldn't work. I suspect there was a vectorization issue that I didn't see how to fix at the time. It may be gone with removal of the if breakdown > 0: statement.

@pytest.mark.parametrize('method', ['lambertw', 'brentq', 'newton',
chandrupatla])
def test_i_from_v_size(method):
if method == 'newton':
Copy link
Member

Choose a reason for hiding this comment

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

Is this why the previous restriction to method='newton'?

Co-authored-by: Cliff Hansen <cwhanse@sandia.gov>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants