55import numpy as np
66import pandas as pd
77from pvlib .tools import _golden_sect_DataFrame
8+ from pvlib .ivtools .utils import _lambertw_pvlib , _log_lambertw
89
910from scipy .optimize import brentq , newton
10- from scipy .special import lambertw
11+ # from scipy.special import lambertw
1112
1213# newton method default parameters for this module
1314NEWTON_DEFAULT_PARAMS = {
@@ -801,12 +802,10 @@ def _lambertw_v_from_i(current, photocurrent, saturation_current,
801802 with np .errstate (over = 'ignore' ):
802803 argW = I0 / (Gsh * a ) * np .exp ((- I + IL + I0 ) / (Gsh * a ))
803804
804- # lambertw typically returns complex value with zero imaginary part
805- # may overflow to np.inf
806- lambertwterm = lambertw (argW ).real
805+ # Record indices where lambertw input overflowed
806+ idx_inf = np .isinf (argW )
807807
808- # Record indices where lambertw input overflowed output
809- idx_inf = np .isinf (lambertwterm )
808+ lambertwterm = _lambertw_pvlib (argW )
810809
811810 # Only re-compute LambertW if it overflowed
812811 if np .any (idx_inf ):
@@ -815,15 +814,8 @@ def _lambertw_v_from_i(current, photocurrent, saturation_current,
815814 np .log (a [idx_inf ]) +
816815 (- I [idx_inf ] + IL [idx_inf ] + I0 [idx_inf ]) /
817816 (Gsh [idx_inf ] * a [idx_inf ]))
817+ lambertwterm [idx_inf ] = _log_lambertw (logargW )
818818
819- # Three iterations of Newton-Raphson method to solve
820- # w+log(w)=logargW. The initial guess is w=logargW. Where direct
821- # evaluation (above) results in NaN from overflow, 3 iterations
822- # of Newton's method gives approximately 8 digits of precision.
823- w = logargW
824- for _ in range (0 , 3 ):
825- w = w * (1. - np .log (w ) + logargW ) / (1. + w )
826- lambertwterm [idx_inf ] = w
827819
828820 # Eqn. 3 in Jain and Kapoor, 2004
829821 # V = -I*(Rs + Rsh) + IL*Rsh - a*lambertwterm + I0*Rsh
@@ -879,7 +871,7 @@ def _lambertw_i_from_v(voltage, photocurrent, saturation_current,
879871
880872 # lambertw typically returns complex value with zero imaginary part
881873 # may overflow to np.inf
882- lambertwterm = lambertw (argW ). real
874+ lambertwterm = _lambertw_pvlib (argW )
883875
884876 # Eqn. 2 in Jain and Kapoor, 2004
885877 # I = -V/(Rs + Rsh) - (a/Rs)*lambertwterm + Rsh*(IL + I0)/(Rs + Rsh)
@@ -1031,7 +1023,7 @@ def batzelis(photocurrent, saturation_current, resistance_series,
10311023 voc = a * np .log (Iph / Is )
10321024
10331025 # Eqs 5-8
1034- w = np . real ( lambertw ( np .e * Iph / Is ) )
1026+ w = _lambertw_pvlib ( np .e * Iph / Is )
10351027 # vmp = (1 + Rs/Rsh) * a * (w - 1) - Rs * Iph * (1 - 1/w) # not needed
10361028 with np .errstate (divide = 'ignore' , invalid = 'ignore' ): # zero Iph -> zero w
10371029 imp = Iph * (1 - 1 / w ) - a * (w - 1 ) / Rsh
0 commit comments