diff --git a/docs/sphinx/source/whatsnew/v0.10.0.rst b/docs/sphinx/source/whatsnew/v0.10.0.rst index ab58828653..c5e02ffbc3 100644 --- a/docs/sphinx/source/whatsnew/v0.10.0.rst +++ b/docs/sphinx/source/whatsnew/v0.10.0.rst @@ -49,6 +49,9 @@ Enhancements Bug fixes ~~~~~~~~~ +* Prevent small negative values of `v_oc` in :py:func:`pvlib.singlediode._lambertw` + which result from accumulated roundoff error. (:issue:`1780`, :issue:`1673`, :pull:`1782`) + Testing ~~~~~~~ @@ -71,3 +74,5 @@ Contributors * Adam R. Jensen (:ghuser:`AdamRJensen`) * Echedey Luis (:ghuser:`echedey-ls`) * Cliff Hansen (:ghuser:`cwhanse`) +* Cédric Leroy (:ghuser:`cedricleroy`) +* Jean-Baptiste Pasquier (:ghuser:`pasquierjb`) diff --git a/pvlib/singlediode.py b/pvlib/singlediode.py index a4a760f1b9..cfc63f3591 100644 --- a/pvlib/singlediode.py +++ b/pvlib/singlediode.py @@ -794,6 +794,13 @@ def _lambertw(photocurrent, saturation_current, resistance_series, # Compute open circuit voltage v_oc = _lambertw_v_from_i(0., **params) + # Set small elements <0 in v_oc to 0 + if isinstance(v_oc, np.ndarray): + v_oc[(v_oc < 0) & (v_oc > -1e-12)] = 0. + elif isinstance(v_oc, (float, int)): + if v_oc < 0 and v_oc > -1e-12: + v_oc = 0. + # Find the voltage, v_mp, where the power is maximized. # Start the golden section search at v_oc * 1.14 p_mp, v_mp = _golden_sect_DataFrame(params, 0., v_oc * 1.14, _pwr_optfcn) diff --git a/pvlib/tests/test_singlediode.py b/pvlib/tests/test_singlediode.py index 1223e73e8e..16b93cbf77 100644 --- a/pvlib/tests/test_singlediode.py +++ b/pvlib/tests/test_singlediode.py @@ -168,6 +168,19 @@ def test_singlediode_precision(method, precise_iv_curves): assert np.allclose(pc['i_xx'], outs['i_xx'], atol=1e-6, rtol=0) +def test_singlediode_lambert_negative_voc(): + + # Those values result in a negative v_oc out of `_lambertw_v_from_i` + x = np.array([0., 1.480501e-11, 0.178, 8000., 1.797559]) + outs = pvsystem.singlediode(*x, method='lambertw') + assert outs['v_oc'] == 0 + + # Testing for an array + x = np.array([x, x]).T + outs = pvsystem.singlediode(*x, method='lambertw') + assert np.array_equal(outs['v_oc'], [0, 0]) + + @pytest.mark.parametrize('method', ['lambertw']) def test_ivcurve_pnts_precision(method, precise_iv_curves): """