Skip to content

Add lambertw_pvlib#2723

Open
cwhanse wants to merge 12 commits intopvlib:mainfrom
cwhanse:lambertw
Open

Add lambertw_pvlib#2723
cwhanse wants to merge 12 commits intopvlib:mainfrom
cwhanse:lambertw

Conversation

@cwhanse
Copy link
Member

@cwhanse cwhanse commented Mar 23, 2026

  • Closes #xxxx
  • I am familiar with the contributing guidelines
  • I attest that all AI-generated material has been vetted for accuracy and is in compliance with the pvlib license
  • 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.

Add a real-valued-only Lamberts W function. As tested, function is as precise as scipy's lambertw, and 4x faster due to not doing all arithmetic with complex values.

@cwhanse
Copy link
Member Author

cwhanse commented Mar 23, 2026

Once this is accepted, next PR will replace calls to scipy's lambertw in ivtools. I'm splitting this in two parts, since it's not a matter of replacing a function name. The private function _log_lambertw handles the overflow cases that are computed using a Newton's technique in the ivtools functions.

@cwhanse
Copy link
Member Author

cwhanse commented Mar 23, 2026

Put this in pvlib.tools or in pvlib.ivtools.utils? Make lambertw_pvlib private?

pvlib docs don't provide links to public function in either of these folders so there's no API change.

Copy link
Member

@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.

In general terms, I'd prefer to keep this function internal. Or at least give it some internal period just in case anything arises later. A function in the API is somewhat a contract with the user, and even thou I'm confident that it works pretty well, I'm not sure about the maintenance purely numerical API may bring later, or if users start assuming it follows numpy/scipy conventions... On the other hand, the more people that use it, the better to confirm that it works. I don't have a strong opinion.

Last big comment: what is the source of the equations? scipy's implementation? any source linked by them? I would add it for the sake of completeness. Sry if I missed it previously.

I don't mind its placement; thou I prefer pvlib.ivtools.utils, the nearest junk drawer to where it will be used.

Some minor comments below.

def test_lambertw_pvlib():
test_exp = np.arange(-10., 300, step=10)
test_x = 10.**test_exp
# known solution from scipy.special.lambertw
Copy link
Member

Choose a reason for hiding this comment

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

Can you please add the exact version of scipy and date you generated it? For traceability. Else, we could generate the comparison on the fly, so if there ever is a change at scipy we can catch it soon.

cwhanse and others added 3 commits March 23, 2026 17:58
Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com>
@cwhanse
Copy link
Member Author

cwhanse commented Mar 24, 2026

Last big comment: what is the source of the equations? scipy's implementation? any source linked by them? I would add it for the sake of completeness. Sry if I missed it previously.

It's direct application of two well-known methods (Halley's, Newton) to the Lambert W function. I can write a derivation (a few lines) in the function documentation, if that helps.

I don't mind its placement; thou I prefer pvlib.ivtools.utils, the nearest junk drawer to where it will be used.

I agree, moved to ivtools.utils

@echedey-ls
Copy link
Member

echedey-ls commented Mar 24, 2026

Last big comment: what is the source of the equations? scipy's implementation? any source linked by them? I would add it for the sake of completeness. Sry if I missed it previously.

It's direct application of two well-known methods (Halley's, Newton) to the Lambert W function. I can write a derivation (a few lines) in the function documentation, if that helps.

I retract my opinion, it should have been clear to me when I read the code.

Copy link
Member

@kandersolar kandersolar left a comment

Choose a reason for hiding this comment

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

Seems like convergence is poor as it approaches the branch point at -1/e. Should we tighten that up and test for negative inputs?

I also see larger error for 10 < x < 100 or so, although "larger" is still quite small. Still, it seems like it could be easily eliminated by switching methods at x == 100 instead of x == 10?

Image

Comment on lines +579 to +580
x : np.array
Must be real numbers.
Copy link
Member

Choose a reason for hiding this comment

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

Will requiring np.array (i.e., not allowing float) be a problem for supporting single-value I-V curve calculations?

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 think it should accept float, added that

@cwhanse
Copy link
Member Author

cwhanse commented Mar 24, 2026

Seems like convergence is poor as it approaches the branch point at -1/e. Should we tighten that up and test for negative inputs?

The problem at the branch point is that the derivative -> infinity as x -> -1/e. Accurate estimation for negative x approaching -1/e will require a different technique (note scipy has a bug at the branch point scipy/scipy#24770).

In the solution for the single diode equation, the argument of lambertw will be positive, unless parameters are out of bounds (e.g., negative resistance). This holds even for negative voltage. I changed the docstring to specify x>=0.

I also see larger error for 10 < x < 100 or so, although "larger" is still quite small. Still, it seems like it could be easily eliminated by switching methods at x == 100 instead of x == 10?

Done. 10 was just my guess, I didn't draw the error figure like yours, that's great.

Also, I added x=0. to the test and simplified that a bit.

cwhanse and others added 2 commits March 24, 2026 16:29
Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com>
@echedey-ls echedey-ls added this to the v0.15.1 milestone Mar 25, 2026
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.

3 participants