Skip to content

6-parameter Single Diode Model Solver#195

Open
dguittet wants to merge 25 commits intomainfrom
6parsolve
Open

6-parameter Single Diode Model Solver#195
dguittet wants to merge 25 commits intomainfrom
6parsolve

Conversation

@dguittet
Copy link
Copy Markdown
Collaborator

@dguittet dguittet commented May 27, 2025

Run time for Mac w/ 14 processes

2026-03-16 12:18:50: Solving for 21598 Modules
2026-03-16 12:18:50: Starting First Pass Solve
2026-03-16 12:34:37: Solved 21054. 544 remaining.
2026-03-16 12:34:37: Starting Second Pass Solve
2026-03-16 12:34:58: Solved 21577. 21 remaining.
2026-03-16 12:34:58: Starting Final Pass Solve
2026-03-16 12:35:00: Solved 21577. 21 unsolved.

See docs/tools/SixParSolve.rst for information

A change to SSC's solver to reflect the reduced temperature sampling space for off-STC MPP modeling:
NatLabRockies/ssc#1373

The short explanation for the difference is that the 6-parameter module model makes some simplifications regarding temperature-independent resistances that make the model hard to extend for finding MPPs at extreme temperature ranges (outside of STC). The SSC and Python implementation both tried to model MPPs at a temperature range from -10 to 50 C. When there are some modules that don’t fit the mold for the low temperatures, the two solvers prioritize differently— the SSC one tended to not care about the low temperature curves and did a good job fitting the IV curves for the majority of the other temperatures. On the other hand, the Python one tried to fit everything equally and ended up not fitting any of them particularly well, and in some cases pushed the MPPs significantly enough that the annual production was very different from the SSC solution.

Since this is a limitation of the 6-parameter module model, I just narrowed the lowest temperature to solve for from -10 to 10. This removed some of the inconsistent constraints on the solver and the IV curves are more similar. This effectively fixed the module that had experienced the largest reduction in annual production moving from SSC to Python, the change went from -65% to +1%.

Comment thread files/SixParSolve.py
iv_diff_cols = ['d_Isc', 'd_Imp', 'd_Vmp', 'd_Pmp']

# 6par_solve.h L 423
def current_at_voltage_cec(Vmodule, IL_ref, IO_ref, RS, A_ref, RSH_ref, I_mp_ref):
Copy link
Copy Markdown
Contributor

@cwhanse cwhanse May 27, 2025

Choose a reason for hiding this comment

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

wondering if pvlib.pvsystem.i_from_v() would be suitable here. This solver iterates using a Newton's method, risking numerical overflow from the exponential term at high voltages, and exiting at rather low precision. The default solver behind pvlib's i_from_v should return 10 digits of precision and handles overflow.

And i_from_v is vectorized, if that doesn't conflict with what pyomo needs.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Hi Cliff, thanks for the suggestion. This current_at_voltage_cec function is only for plotting purposes and isn't used in the actual solving. I'm looking at i_from_v() and will run a comparison

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I've updated the doc string on the function:

    Solve for the current at the voltage Vmodule, given the single diode parameters which could have been modified for non-STC condition

    Used for plotting only, so numerical precision is only 1e-4. Adapted from ssc/shared/6par_solve.h L 423

    For better stability and precision, use pvlib.pvsystem.i_from_v(v, IL_oper, IO_oper, Rs, Rsh_oper, A_oper)

Comment thread files/SixParSolve.py Outdated

def cec_model_params_at_condition(model, Irr, T_cell_K):
"""
Get the single diode parameters at a given condition
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The pvlib equivalent is pvlib.pvsystem.calcparams_cec. I'm guessing that casting to pyomo objects is necessary, though.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'll take a look, but this function is again just for plotting purposes. Everything for the solve is via pyomo objects in create_model

Copy link
Copy Markdown
Collaborator Author

@dguittet dguittet May 28, 2025

Choose a reason for hiding this comment

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

There are two differences I noticed:

  1. The calculation of IL in SAM has a modification using Adjust to the alpha coefficient that's not present in pvlib.
# pvlib L 1695
IL = effective_irradiance / irrad_ref * (I_L_ref + alpha_sc * (Tcell_K - Tref_K))
# sam
IL_oper = Irr/I_ref *( Il + alpha * (1-Adj/100)*(T_cell_K-Tc_ref) )
  1. The calculation of IO. SAM's plotting function had simplified the coefficients (probably to deal with numerical issues in LK), so I switched it back to the version using the Boltzmann coefficient in both the plotting function and in pyomo. The numerical impact was small, but in the precision requirement for pyomo, potentially impactful.
# b.Io_Tc = pyo.Expression(expr=m.par.Io* ( b.Tc/m.Tref)**3 * pyo.exp( 11600 * (m.Egref/m.Tref - b.Eg_Tc/b.Tc)))
b.Io_Tc = pyo.Expression(expr=m.par.Io* ( b.Tc/m.Tref)**3 * pyo.exp(b.Eg_Tc / (m.k*(m.Tref)) - (m.Egref / (m.k*(b.Tc)))))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

calcparams_cec calls calcparams_desoto with the modification to alpha_sc in the passed parameters: alpha_sc*(1.0 - Adjust/100)

The CEC and De Soto models only differ by the Adjust parameter so we re-use code here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Ah, I'd missed that! Thanks for pointing it out. Makes sense now

@dguittet
Copy link
Copy Markdown
Collaborator Author

@cwhanse Thanks for the review! I've addressed your comments, please let me know if you have other feedback

@cwhanse
Copy link
Copy Markdown
Contributor

cwhanse commented May 28, 2025

@cwhanse Thanks for the review! I've addressed your comments, please let me know if you have other feedback

Curious what solver is being used? Its been some time since I looked at pyomo but I recall that it isn't distributed with a solver.

@dguittet
Copy link
Copy Markdown
Collaborator Author

dguittet commented May 28, 2025

Curious what solver is being used? Its been some time since I looked at pyomo but I recall that it isn't distributed with a solver.

It's using IPOPT: conda install -c conda-forge ipopt. I'll add that information to the top of the file

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

Successfully merging this pull request may close these issues.

4 participants