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

Test pvsystem.singlediode against precisely generated IV curves #1573

Merged
merged 29 commits into from
Mar 15, 2023

Conversation

reepoi
Copy link
Contributor

@reepoi reepoi commented Oct 16, 2022

Generated IV curves are added to pvlib/data to test the precision of pvsystem.singlediode, pvsystem.v_from_i, and pvsystem.i_from_v. The parameters of the single diode equation that generated each IV curve are in CSV files, and the IV curve data are in JSON files following this JSON schema. i_x and i_xx are added in addition to the fields of the JSON schema since they are also calculated by pvsystem.singlediode.
The generated IV curve data are calculated using the functions in the ivcurves repository. These functions use the arbitrary precision math library mpmath. The data may be reproduced by checking out the code of this commit of ivcurves and running the command

python3 ivcurves/precise.py --save-json test_sets

The data are in the files test_sets/case1.json and test_sets/case2.json.

@reepoi
Copy link
Contributor Author

reepoi commented Nov 17, 2022

I updated the description of this pull request. The test cases added now test:

  • pvsystem.singlediode with ivcurve_pnts=None and all options for method: checks all the returned values.
  • pvsystem.singlediode with ivcurve_pnts=100 and method='lambertw': checks only the returned current and voltage values.
  • pvsystem.v_from_i and pvsystem.i_from_v with all options for method: checks the returned voltage or current values.

The tests for pvsystem.v_from_i and pvsystem.i_from_v indirectly test the precision of pvsystem.singlediode with methods brentq and newton when ivcurves_pnts=100 since it they all eventually call pvsystem.bishop88.

@cwhanse cwhanse added this to the 0.9.4 milestone Nov 30, 2022
@cwhanse
Copy link
Member

cwhanse commented Nov 30, 2022

Ready for review. @markcampanelli would appreciate your input if this closes #411

Copy link
Contributor

@markcampanelli markcampanelli left a comment

Choose a reason for hiding this comment

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

Thanks for this submission. Generally looks good.

The big thing I would like to see is some better documentation in this repo (mostly for posterity) about how the precise I-V data points were generated elsewhere. For example, how did you choose the precision cutoff using mpmath with respect to the precision used in the pvsystem.singlediode calculations? The choice of constants in the upstream calculation could also have a better "paper trail".

@@ -0,0 +1,33 @@
Index,photocurrent,saturation_current,resistance_series,resistance_shunt,n,cells_in_series
1,1.0,5e-10,0.1,300,1.01,72
Copy link
Contributor

Choose a reason for hiding this comment

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

Because this is a Python repo, you might consider indexing from 0, not 1.

"cells_in_series": 72,
"IV Curves": [
{
"Index": 1,
Copy link
Contributor

Choose a reason for hiding this comment

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

Because this is a Python repo, you might consider indexing from 0, not 1.

Comment on lines 115 to 116
joined['Boltzman'] = 1.380649e-23
joined['Electron Charge'] = 1.60217663e-19
Copy link
Contributor

Choose a reason for hiding this comment

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

For better traceability, I would think that the choice of values for these constants should documented as part of the files containing the parameters used to precisely compute the curves.

For comparison, scipy==1.8.1 gives:

scipy.constants.value("Boltzmann constant") = 1.380649e-23 J/K
scipy.constants.value("elementary charge") = 1.602176634e-19 C

Copy link
Contributor

Choose a reason for hiding this comment

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

Also see #483

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I updated these constants to match The SI Brochure (https://www.bipm.org/en/publications/si-brochure) and cited that document in the docstring. In that docstring, I also added the precision cutoff of mpmath and more detail about the precision of the IV curve data. I avoided mentioning cwhanse/ivcurves, but maybe we should reference it. There is much more documentation and code that would help someone understand how the IV curve data was generated.

Also, if we use scipy.constants, pvlib may need to update its minimum SciPy version requirement because Boltzmann's constant changes depending on the SciPy version. The value for SciPy 1.9.3 is 1.602176634e-19 C, which matches the value hard-coded here; however, the value is 1.6021766208e-19 C for SciPy 1.2.0. It changes in SciPy 1.4.0, and pvlib's minimum version of SciPy is 1.2.0.

Copy link
Member

Choose a reason for hiding this comment

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

@pvlib/pvlib-maintainer I think we should advance scipy version and use the 2019 values, which are defined to be exact rather than with uncertainty.

Comment on lines 152 to 158
assert np.allclose(pc['i_sc'], outs['i_sc'], atol=1e-10, rtol=0)
assert np.allclose(pc['v_oc'], outs['v_oc'], atol=1e-10, rtol=0)
assert np.allclose(pc['i_mp'], outs['i_mp'], atol=5e-8, rtol=0)
assert np.allclose(pc['v_mp'], outs['v_mp'], atol=8e-7, rtol=0)
assert np.allclose(pc['p_mp'], outs['p_mp'], atol=1e-10, rtol=0)
assert np.allclose(pc['i_x'], outs['i_x'], atol=1e-10, rtol=0)
assert np.allclose(pc['i_xx'], outs['i_xx'], atol=8e-8, rtol=0)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm super curious how these tolerances might be tightened for 'lambertw', 'brentq', vs. 'newton'.

Copy link
Member

Choose a reason for hiding this comment

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

And I'm curious why there are test failures only on ubuntu and python <=3.9 for the 'lambertw' case. I suspect something buried fairly deep behind scipy.special.lambertw which we won't solve.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For this failed test, the 30th i_xx value differs by 1e-6. All of the tests related to this pull request pass with atol=1e-6 for the i_xx value.

Copy link
Member

Choose a reason for hiding this comment

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

@reepoi I think there's a mistake in the precise curve library somewhere.

@markcampanelli
Copy link
Contributor

Ready for review. @markcampanelli would appreciate your input if this closes #411

I think this addresses #411, so that can be closed once this merges.

I have closed #426, which this substitutes.

@kandersolar kandersolar mentioned this pull request Dec 9, 2022
9 tasks
@kandersolar kandersolar modified the milestones: 0.9.4, 0.9.5 Dec 14, 2022
@cwhanse cwhanse mentioned this pull request Dec 19, 2022
6 tasks
@kandersolar
Copy link
Member

The current test failures are only on linux, only occur for numpy>=1.22.0, and have to do with precision checks, so I suspect this is due to the increased SIMD functionality added in numpy 1.22.0.

In the past we have relaxed test tolerances to accommodate the slight numerical variation, but in this specific case that seems rather self-defeating :) It is possible to disable the relevant SIMD features by setting a magic environment variable when executing the tests (#1448 (comment)), but that would be a global change that affects all tests, which I'm not sure is desirable either. I'm not sure what to suggest here.

@cwhanse
Copy link
Member

cwhanse commented Jan 23, 2023

The current test failures are only on linux, only occur for numpy>=1.22.0, and have to do with precision checks, so I suspect this is due to the increased SIMD functionality added in numpy 1.22.0.

In the past we have relaxed test tolerances to accommodate the slight numerical variation, but in this specific case that seems rather self-defeating :)

My perspective is that the test tolerance is a measure of the pvlib functions' accuracy. Six digits (worst case) is at least useful for energy simulations and may also help provide context for other use cases. At least it establishes a benchmark from which we can measure improvements.

@kandersolar kandersolar mentioned this pull request Mar 2, 2023
12 tasks
@kandersolar
Copy link
Member

@cwhanse a lot has happened in the https://github.com/cwhanse/ivcurves repository in the last couple months. Are any corresponding updates required in this PR?

@cwhanse
Copy link
Member

cwhanse commented Mar 7, 2023

We may need to replace the json files

@reepoi
Copy link
Contributor Author

reepoi commented Mar 8, 2023

I regenerated the JSON files using the latest version of the https://github.com/cwhanse/ivcurves repository and there is no difference between them and the JSON files in this PR.

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.

A few minor docs suggestions but otherwise LGTM. Thanks @reepoi!

@kandersolar kandersolar merged commit 13744ca into pvlib:main Mar 15, 2023
@kandersolar
Copy link
Member

Thanks @reepoi for the contribution and @markcampanelli and @cwhanse for the reviews!

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.

Test singlediode() implementations using a "gold" function and data set
4 participants