Skip to content
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

[FIX] iam.physical returns nan for aoi > 90° when n = 1 (#1706) #1707

Merged
merged 5 commits into from Jun 20, 2023

Conversation

kdebrab
Copy link
Contributor

@kdebrab kdebrab commented Mar 24, 2023

  • Closes regression: iam.physical returns nan for aoi > 90° when n = 1 #1706
  • 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.

@cwhanse
Copy link
Member

cwhanse commented Mar 24, 2023

The nan appears to enter here and on the following line, because n1costheta1 and n2costheta1 are both zero when AOI>90, n=1 and n_ar is None. I wonder if there is a condensed mathematical expression for the IAM in the limit case of n1=1, n2=1, and n3=1.

@kdebrab
Copy link
Contributor Author

kdebrab commented Mar 24, 2023

The nan appears to enter here and on the following line, because n1costheta1 and n2costheta1 are both zero when AOI>90, n=1 and n_ar is None. I wonder if there is a condensed mathematical expression for the IAM in the limit case of n1=1, n2=1, and n3=1.

That condensed mathematical expression is np.exp(-K * L / costheta) / np.exp(-K * L) (I think) but it has the same problem of a division by zero for AOI>90. Moreover, we also need to support n2 as a vector (see #1616 (comment)), where potentially some elements are 1 and others not. For both cases we need the lines included in the current pull request.
In the end, I'm not sure whether it's worth to have a special path for a minor speedup of a rather uncommon use case.

Copy link
Member

@mikofski mikofski left a comment

Choose a reason for hiding this comment

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

Thanks

@kandersolar kandersolar added this to the 0.9.6 milestone Apr 5, 2023
@kandersolar kandersolar added the bug label Apr 5, 2023
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.

Thanks @kdebrab! Can you add a bug fix entry in the 0.9.6 what's new file?

One thing is that the new test produces some runtime warning clutter: https://github.com/pvlib/pvlib-python/actions/runs/4510438842/jobs/7941391259?pr=1707#step:9:58

It would be nice to prevent iam.physical from emitting those, but n=1 seems uncommon enough that I'd be okay with just suppressing them in the test function if there's not a clean way of preventing them at the source.

@adriesse
Copy link
Member

adriesse commented Apr 7, 2023

There is an interesting thing happening with this sequence of inexact trig calculations:

costheta = np.maximum(0, cosd(aoi))  # --> 6.123233995736766e-17
sintheta = np.sqrt(1 - costheta**2)  # --> 1.0
costheta = np.sqrt(1 - sintheta**2) # --> 0.0

If the first line were producing a true zero this function would blow up sooner and more often; therefore, the previous use of zeroang = 1e-06 might be the preferred solution.

We shouldn't really rely on cosd(90) != 0 anywhere, although we probably unwittingly do.

@adriesse
Copy link
Member

adriesse commented Apr 7, 2023

I would follow this up with a suggestion (now retracted) to rewrite tools.cosd as

np.sqrt(1 - np.square(np.sin(angle * (np.pi / 180))))

@cwhanse
Copy link
Member

cwhanse commented Apr 7, 2023

I would follow this up with a suggestion to rewrite tools.cosd as

np.sqrt(1 - np.square(np.sin(90 * (np.pi / 180))))

I'm puzzled by this. I assume you meant theta * (np.pi/180)). How would it properly evaluate cosd(135)? It can't return a negative value, since np.sqrt only returns the principal root.

@adriesse
Copy link
Member

adriesse commented Apr 7, 2023

I'm puzzled by this

Sorry, didn't think that through all the way.

Still, I hope this does not detract from the preceding (hopefully) valid observation about what's going wrong in this function.

@kandersolar kandersolar modified the milestones: 0.9.6, 0.10.0 May 16, 2023
@kandersolar
Copy link
Member

I'm going to merge this since it's ready to go and an improvement. Additional improvements can always be future PRs :)

Thanks again @kdebrab for noticing and fixing this bug!

@kandersolar kandersolar merged commit e643dc3 into pvlib:main Jun 20, 2023
28 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

regression: iam.physical returns nan for aoi > 90° when n = 1
5 participants