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

RuntimeError while using the fit_desoto function, caused by optimize.root (SciPy) #1226

Closed
MariusBartkowski opened this issue May 11, 2021 · 5 comments

Comments

@MariusBartkowski
Copy link

MariusBartkowski commented May 11, 2021

Hello everyone,

while using the fit_desoto function to estimate parameters for further solar module calculations, I received the following error:

RuntimeError: Parameter estimation failed: The iteration is not making good progress, as measured by the improvement from the last five Jacobian evaluations.

The error comes from the optimize.root function from the SciPy library, which is used within the fit_desoto function.

Even if I use only 1s for the initial values of the fit_desoto function, I get this error.

The code for the function call in the main programm:

self.mp_desoto_fit = pvlib.ivtools.sdm.fit_desoto(v_mp=module['Vmpo'], i_mp=module['Impo'], v_oc=module['Voco'], i_sc=module['Isco'], alpha_sc=module['Aisc'], beta_voc=module['Bvoco'], cells_in_series=module['Cells_in_Series'], EgRef=1.121, dEgdT=-0.0002677, temp_ref=25, irrad_ref=1000, root_kwargs={'options': {'col_deriv': 0, 'xtol': 1.49012e-05, 'maxfev': 0, 'band': None, 'eps': None, 'factor': 100, 'diag': None}})
The root_kwargs in the function call of the fit_desoto function influence the solver of the root function, but different properties for the solver don't fix the problem.

To Reproduce the error
You can easily reproduce the error by simply using the fit_desoto function. It doesn't make a difference if you use concrete values of a photovoltaic cell or just 1s. All values after cells in series (8) are default values.

mp_desoto_fit_num = pvlib.ivtools.sdm.fit_desoto(4.568, 3.3, 5.36, 3.5, 0.0010, -0.0158, 8, EgRef=1.121, dEgdT=-0.0002677, temp_ref=25, irrad_ref=1000, root_kwargs={})

or

mp_desoto_fit_ones = pvlib.ivtools.sdm.fit_desoto(1, 1, 1, 1, 1, 1, 1, EgRef=1.121, dEgdT=-0.0002677, temp_ref=25, irrad_ref=1000, root_kwargs={})

When using those code examples the error message changes to:

RuntimeError: Parameter estimation failed:
The iteration is not making good progress, as measured by the
improvement from the last ten iterations.

Do you have any ideas on this issue?

What I already tried:

  • Checked all types of initial values for the fit_desoto function (temperature coefficients are handed over in [A/K]).

  • Choosed different options for the root function solver with the method 'hybr'

  • Code debugged and checked the variables inside the root_function. No NaN values or similar arise while the function is calculating

Suggestions
perhaps the problem could be solved by choosing a different method for the root function via the function call of fit_desoto. The kwargs of the fit_desoto function itself can only change the options of the solver, but not which method is used. The default method is "hybr" which is only one of several.

Thanks in advance!


Versions:
numpy 1.20.2
pandas 1.2.4
pvlib 0.8.1
scipy 1.6.3
python 3.9.0

I am using Spyder and/or PyCharm

@cwhanse
Copy link
Member

cwhanse commented May 11, 2021

I'm not opposed to adding a kwarg to ivtools.sdm.fit_desoto to switch the optimization method. In this instance, I suspect the trouble lies with the built-in initial guess (which follows the text in Duffie and Beckman). Fitting the diode equation to data is mathematically challenging, and I'm not surprised that the fit_desoto function struggles.

You could use ivtools.sdm.fit_cec_sam, which fits almost the same model as Desoto (the CEC model has one additional parameter that "adjusts" the temperature coefficients to match a target coefficient for power). This code works:

import pvlib

gamma_pmp = (0.001 * 4.568 + -0.0158 * 3.3) / (4.568 * 3.3) * 100

result = pvlib.ivtools.sdm.fit_cec_sam(
    celltype='monoSi', v_mp=4.568, i_mp=3.3, v_oc=5.36, i_sc=3.5,
    alpha_sc=0.001, beta_voc=-0.0158, gamma_pmp=-0.3156, cells_in_series=8,
    temp_ref=25)

print(result)

(3.5024746819107855, 2.3470813166776665e-12, 0.05508415040943549, 77.90679113571254, 0.1913501211018485, -10.655716001701359)

fit_cec_sam requires installing NREL's python wrapper for the SAM SDK (the SDK is installed with the python package, you don't have to install SAM also):

pip install NREL-PySAM

Here, I estimated the temperature coefficient of power by assuming that the temperature coefficients for current and voltage at max power are the same as at Isc and Voc, but of course the proper value should be used. The cell_type kwarg selects the bandgap terms EgRef and dEgdT, which happens in the pysam code.

The optimization routines accessed by the pysam package have some built-in intelligence for initial guesses and updating parameters, and are more likely to converge.

@mikofski
Copy link
Member

I agree with Cliff, it may be the initial guess, not the solver. But I don't think root_kwargs lets a user overwrite the initial guess x0 in scipy.optimize.root which is set internally as param_i and is probably following some logic that DeSoto and Duffie & Beckman reported. Sorry I haven't read their work. 😮

# initial guesses of variables for computing convergence:
# Values are taken from [2], p753
Rsh_0 = 100.0
a_0 = 1.5*k*Tref*cells_in_series
IL_0 = i_sc
Io_0 = i_sc * np.exp(-v_oc/a_0)
Rs_0 = (a_0*np.log1p((IL_0-i_mp)/Io_0) - v_mp)/i_mp
# params_i : initial values vector
params_i = np.array([IL_0, Io_0, Rs_0, Rsh_0, a_0])

Sometimes I find that restarting the solver with the exit conditions from the last run or with slightly modified initial guess will converge. For example see this discussion: SunPower/PVMismatch#143

I would recommend letting the user override x0 with root_kwargs if possible.

@adriesse
Copy link
Member

I think the first problem in fit_desoto is that it raises an error and swallows the optimize_result. That makes it much harder to investigate. At most it should produce a warning.

@mikofski
Copy link
Member

At most it should produce a warning.

similar dialogue over at scipy on similar issue, scipy/scipy#8904 (comment), is it runtime error or warning?

I think the reason to issue a warning versus an error is so that the final result is returned. If you raise an error then you'll know the solver terminated early, but not why. Note, when the warning is raised, the solver terminates and returns the last guess, it does not continue to iterate.

They opted for display=True & full_output=True to return warning and the reasons why, vs. False which raises error. AFAICT scipy.optimize.root(method='hybr') uses the MINPACK HYBR or HYBRJ solver depending on if the Jacobian is provided or not, and always returns an OptimizedResult with full output regardless of whether it converged or not. It's up to the user to look at the condition of the result, which is what fit_desoto does here:

if optimize_result.success:
sdm_params = optimize_result.x
else:
raise RuntimeError(
'Parameter estimation failed:\n' + optimize_result.message)

so if we change this, then we can get the output of the OptimizedResults

@MariusBartkowski
Copy link
Author

@ cwhanse:

Thanks a lot for your contribution. I choosed to go around the fit_desoto function by using the fit_cec_sam_function and it worked out well!

@mikofski:

Yes, exactly. the problem in the fit desoto function is occuring because optimize_result.success is delivered as false.

& Yes, the console gives out a runtime error which causes the programm to cancel, not a warning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants