Fit non ideal diode equation to dark or light JV-curve

This notebook was written to fit dark JV-curves with the non-ideal diode equation below:
For dark:
\[J = J_0\left[\exp\left(-\frac{V-R_s J}{n k_b T}\right)-1\right] + \frac{V-R_s J}{R_{sh}}\]

using the solving method described in Solid-State Electronics 44 (2000) 1861-1864.

For light:

\[J = J_{ph} - J_0\left[\exp\left(-\frac{V-R_s J}{n k_b T}\right)-1\right] - \frac{V-R_s J}{R_{sh}}\]

using the solving method described in Solar Energy Materials & Solar Cells 81 (2004) 269–277.

[1]:
# Import necessary libraries
import warnings, os, sys, torch, copy
# remove warnings from the output
os.environ["PYTHONWARNINGS"] = "ignore"
warnings.filterwarnings(action='ignore', category=FutureWarning)
warnings.filterwarnings(action='ignore', category=UserWarning)
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from copy import deepcopy

import ax, logging
from ax.utils.notebook.plotting import init_notebook_plotting
init_notebook_plotting() # for Jupyter notebooks

try:
    from optimpv import *
    from optimpv.axBOtorch.axUtils import *
    from optimpv.Diodefits.DiodeAgent import DiodeAgent
    from optimpv.Diodefits.DiodeModel import *
except Exception as e:
    sys.path.append('../') # add the path to the optimpv module
    from optimpv import *
    from optimpv.axBOtorch.axUtils import *
    from optimpv.Diodefits.DiodeAgent import DiodeAgent
    from optimpv.Diodefits.DiodeModel import *

[INFO 12-08 10:01:53] ax.utils.notebook.plotting: Injecting Plotly library into cell. Do not overwrite or delete cell.
[INFO 12-08 10:01:53] ax.utils.notebook.plotting: Please see
    (https://ax.dev/tutorials/visualizations.html#Fix-for-plots-that-are-not-rendering)
    if visualizations are not rendering.

Define the parameters for the simulation

[2]:
params = []

J0 = FitParam(name = 'J0', value = 1e-5, bounds = [1e-6,1e-3], log_scale = True, rescale = False, value_type = 'float', type='range', display_name=r'$J_0$', unit='A m$^{-2}$', axis_type = 'log',force_log=True)
params.append(J0)

n = FitParam(name = 'n', value = 1.5, bounds = [1,2], log_scale = False, value_type = 'float', type='range', display_name=r'$n$', unit='', axis_type = 'linear')
params.append(n)

R_series = FitParam(name = 'R_series', value = 1e-4, bounds = [1e-5,1e-3], log_scale = True, rescale = False, value_type = 'float', type='range', display_name=r'$R_{\text{series}}$', unit=r'$\Omega$ m$^2$', axis_type = 'log',force_log=True)
params.append(R_series)

R_shunt = FitParam(name = 'R_shunt', value = 1e-1, bounds = [1e-2,1e2], log_scale = True, rescale = False, value_type = 'float', type='range', display_name=r'$R_{\text{shunt}}$', unit=r'$\Omega$ m$^2$', axis_type = 'log',force_log=True)
params.append(R_shunt)

# original values
params_orig = copy.deepcopy(params)
num_free_params = len([p for p in params if p.type != 'fixed'])

Generate some fake data for the dark JV

[3]:
# Create JV to fit
X = np.linspace(0.001,1,100)
y = NonIdealDiode_dark(X, J0.value, n.value, R_series.value, R_shunt.value)

plt.figure(figsize=(10,6))
plt.semilogy(X,y)
plt.xlabel('Voltage [V]')
plt.ylabel('Current density [A m$^{-2}$]')
plt.grid()
plt.show()

../_images/examples_diode_5_0.png

Run the optimization

While very inefficient we first try to fit the data using Bayesian optimization, then we use scipy.optimize.minize to demonstrate the difference in speed and accuracy.

[4]:
# Define the Agent and the target metric/loss function
metric = 'mse' # can be 'nrmse', 'mse', 'mae'
loss = 'soft_l1' # can be 'linear', 'huber', 'soft_l1'
exp_format = 'dark' # can be 'dark', 'light' depending on the type of data you have
use_pvlib = False # if True, use pvlib to calculate the diode model if not use the implementation in DiodeModel.py
diode = DiodeAgent(params, X, y, metric = metric, loss = loss, minimize=True,exp_format=exp_format,use_pvlib=use_pvlib,transforms='log')

First with BO

[5]:
from optimpv.axBOtorch.axBOtorchOptimizer import axBOtorchOptimizer
from optimpv.axBOtorch.axUtils import get_VMLC_default_model_kwargs_list

# Define the optimizer
optimizer = axBOtorchOptimizer(params = params, agents = diode, models = ['SOBOL','BOTORCH_MODULAR'],n_batches = [1,20], batch_size = [10,2], model_kwargs_list = get_VMLC_default_model_kwargs_list(num_free_params))
[6]:
optimizer.optimize() # run the optimization with ax
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 0 with parameters: {'J0': -5.856603188440204, 'n': 1.331971007399261, 'R_series': -4.67643416300416, 'R_shunt': -1.4512066803872585}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 1 with parameters: {'J0': -4.181836182251573, 'n': 1.658044039271772, 'R_series': -3.9460126478224993, 'R_shunt': 1.798087116330862}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 2 with parameters: {'J0': -3.432492616586387, 'n': 1.205568258650601, 'R_series': -4.486195294186473, 'R_shunt': -0.12963542714715004}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 3 with parameters: {'J0': -5.109242334030569, 'n': 1.7818832779303193, 'R_series': -3.1384336948394775, 'R_shunt': 0.6206494309008121}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 4 with parameters: {'J0': -4.5762119852006435, 'n': 1.0223882962018251, 'R_series': -3.6890041287988424, 'R_shunt': 0.3339753895998001}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 5 with parameters: {'J0': -3.206269808113575, 'n': 1.9734289031475782, 'R_series': -4.9351460710167885, 'R_shunt': -0.9167824611067772}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 6 with parameters: {'J0': -3.9567433604970574, 'n': 1.3980588354170322, 'R_series': -3.3798686526715755, 'R_shunt': 1.0305618718266487}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 7 with parameters: {'J0': -5.329034459777176, 'n': 1.5993452444672585, 'R_series': -4.243045503273606, 'R_shunt': -1.7192353755235672}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 8 with parameters: {'J0': -5.558104273863137, 'n': 1.133142993785441, 'R_series': -3.318066820502281, 'R_shunt': -0.6809273138642311}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 9 with parameters: {'J0': -3.90601943526417, 'n': 1.8695711763575673, 'R_series': -4.056335164234042, 'R_shunt': 0.06879284977912903}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 0 completed with results: {'diode_dark_mse_soft_l1': 0.1796572216984429} and parameters: {'J0': -5.856603188440204, 'n': 1.331971007399261, 'R_series': -4.67643416300416, 'R_shunt': -1.4512066803872585}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 1 completed with results: {'diode_dark_mse_soft_l1': 1.4282859752406862} and parameters: {'J0': -4.181836182251573, 'n': 1.658044039271772, 'R_series': -3.9460126478224993, 'R_shunt': 1.798087116330862}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 2 completed with results: {'diode_dark_mse_soft_l1': 1.137198445601932} and parameters: {'J0': -3.432492616586387, 'n': 1.205568258650601, 'R_series': -4.486195294186473, 'R_shunt': -0.12963542714715004}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 3 completed with results: {'diode_dark_mse_soft_l1': 1.3510522915387706} and parameters: {'J0': -5.109242334030569, 'n': 1.7818832779303193, 'R_series': -3.1384336948394775, 'R_shunt': 0.6206494309008121}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 4 completed with results: {'diode_dark_mse_soft_l1': 0.7884447035467916} and parameters: {'J0': -4.5762119852006435, 'n': 1.0223882962018251, 'R_series': -3.6890041287988424, 'R_shunt': 0.3339753895998001}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 5 completed with results: {'diode_dark_mse_soft_l1': 0.09145232923282487} and parameters: {'J0': -3.206269808113575, 'n': 1.9734289031475782, 'R_series': -4.9351460710167885, 'R_shunt': -0.9167824611067772}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 6 completed with results: {'diode_dark_mse_soft_l1': 0.8640742009333531} and parameters: {'J0': -3.9567433604970574, 'n': 1.3980588354170322, 'R_series': -3.3798686526715755, 'R_shunt': 1.0305618718266487}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 7 completed with results: {'diode_dark_mse_soft_l1': 0.25525964745524155} and parameters: {'J0': -5.329034459777176, 'n': 1.5993452444672585, 'R_series': -4.243045503273606, 'R_shunt': -1.7192353755235672}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 8 completed with results: {'diode_dark_mse_soft_l1': 0.12688693711089494} and parameters: {'J0': -5.558104273863137, 'n': 1.133142993785441, 'R_series': -3.318066820502281, 'R_shunt': -0.6809273138642311}
[INFO 12-08 10:01:54] optimpv.axBOtorchOptimizer: Trial 9 completed with results: {'diode_dark_mse_soft_l1': 0.4114536644915656} and parameters: {'J0': -3.90601943526417, 'n': 1.8695711763575673, 'R_series': -4.056335164234042, 'R_shunt': 0.06879284977912903}
[INFO 12-08 10:01:56] optimpv.axBOtorchOptimizer: Trial 10 with parameters: {'J0': -3.904805586095646, 'n': 1.9213090757540459, 'R_series': -4.197045511883492, 'R_shunt': -1.470877411638504}
[INFO 12-08 10:01:56] optimpv.axBOtorchOptimizer: Trial 11 with parameters: {'J0': -6.0, 'n': 1.0, 'R_series': -3.199575007881209, 'R_shunt': -1.358093431538213}
[INFO 12-08 10:01:56] optimpv.axBOtorchOptimizer: Trial 10 completed with results: {'diode_dark_mse_soft_l1': 0.11767040364495562} and parameters: {'J0': -3.904805586095646, 'n': 1.9213090757540459, 'R_series': -4.197045511883492, 'R_shunt': -1.470877411638504}
[INFO 12-08 10:01:56] optimpv.axBOtorchOptimizer: Trial 11 completed with results: {'diode_dark_mse_soft_l1': 0.19903044849753604} and parameters: {'J0': -6.0, 'n': 1.0, 'R_series': -3.199575007881209, 'R_shunt': -1.358093431538213}
[INFO 12-08 10:01:57] optimpv.axBOtorchOptimizer: Trial 12 with parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -3.183433276049465, 'R_shunt': -2.0}
[INFO 12-08 10:01:57] optimpv.axBOtorchOptimizer: Trial 13 with parameters: {'J0': -5.146812325474376, 'n': 1.2032770150858325, 'R_series': -3.5148547054203823, 'R_shunt': -2.0}
[INFO 12-08 10:01:57] optimpv.axBOtorchOptimizer: Trial 12 completed with results: {'diode_dark_mse_soft_l1': 0.5256904933958824} and parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -3.183433276049465, 'R_shunt': -2.0}
[INFO 12-08 10:01:57] optimpv.axBOtorchOptimizer: Trial 13 completed with results: {'diode_dark_mse_soft_l1': 0.5126970887578874} and parameters: {'J0': -5.146812325474376, 'n': 1.2032770150858325, 'R_series': -3.5148547054203823, 'R_shunt': -2.0}
[INFO 12-08 10:01:58] optimpv.axBOtorchOptimizer: Trial 14 with parameters: {'J0': -3.834657750785285, 'n': 2.0, 'R_series': -4.648309207865186, 'R_shunt': -0.8647906789785229}
[INFO 12-08 10:01:58] optimpv.axBOtorchOptimizer: Trial 15 with parameters: {'J0': -3.6503868117927003, 'n': 1.8013928448953949, 'R_series': -4.850949961201469, 'R_shunt': -0.9636714700216009}
[INFO 12-08 10:01:58] optimpv.axBOtorchOptimizer: Trial 14 completed with results: {'diode_dark_mse_soft_l1': 0.0543393399363139} and parameters: {'J0': -3.834657750785285, 'n': 2.0, 'R_series': -4.648309207865186, 'R_shunt': -0.8647906789785229}
[INFO 12-08 10:01:58] optimpv.axBOtorchOptimizer: Trial 15 completed with results: {'diode_dark_mse_soft_l1': 0.10451446963773359} and parameters: {'J0': -3.6503868117927003, 'n': 1.8013928448953949, 'R_series': -4.850949961201469, 'R_shunt': -0.9636714700216009}
[INFO 12-08 10:01:59] optimpv.axBOtorchOptimizer: Trial 16 with parameters: {'J0': -6.0, 'n': 1.1345633146183516, 'R_series': -5.0, 'R_shunt': -0.6647374834166924}
[INFO 12-08 10:01:59] optimpv.axBOtorchOptimizer: Trial 17 with parameters: {'J0': -6.0, 'n': 2.0, 'R_series': -5.0, 'R_shunt': -2.0}
[INFO 12-08 10:01:59] optimpv.axBOtorchOptimizer: Trial 16 completed with results: {'diode_dark_mse_soft_l1': 0.5482486367158836} and parameters: {'J0': -6.0, 'n': 1.1345633146183516, 'R_series': -5.0, 'R_shunt': -0.6647374834166924}
[INFO 12-08 10:01:59] optimpv.axBOtorchOptimizer: Trial 17 completed with results: {'diode_dark_mse_soft_l1': 0.696445115470206} and parameters: {'J0': -6.0, 'n': 2.0, 'R_series': -5.0, 'R_shunt': -2.0}
[INFO 12-08 10:01:59] optimpv.axBOtorchOptimizer: Trial 18 with parameters: {'J0': -6.0, 'n': 1.2968608450418397, 'R_series': -3.2575459500661723, 'R_shunt': -1.0952456648090667}
[INFO 12-08 10:01:59] optimpv.axBOtorchOptimizer: Trial 19 with parameters: {'J0': -3.4380429218099557, 'n': 1.9274949732864544, 'R_series': -4.023647210016816, 'R_shunt': -0.8367323089803802}
[INFO 12-08 10:01:59] optimpv.axBOtorchOptimizer: Trial 18 completed with results: {'diode_dark_mse_soft_l1': 0.09920165652870994} and parameters: {'J0': -6.0, 'n': 1.2968608450418397, 'R_series': -3.2575459500661723, 'R_shunt': -1.0952456648090667}
[INFO 12-08 10:01:59] optimpv.axBOtorchOptimizer: Trial 19 completed with results: {'diode_dark_mse_soft_l1': 0.01106879891453083} and parameters: {'J0': -3.4380429218099557, 'n': 1.9274949732864544, 'R_series': -4.023647210016816, 'R_shunt': -0.8367323089803802}
[INFO 12-08 10:02:00] optimpv.axBOtorchOptimizer: Trial 20 with parameters: {'J0': -4.104711637285448, 'n': 1.8340266999239438, 'R_series': -3.093905541941233, 'R_shunt': -0.9953993373278287}
[INFO 12-08 10:02:00] optimpv.axBOtorchOptimizer: Trial 21 with parameters: {'J0': -5.293707663942541, 'n': 1.331274184151106, 'R_series': -3.0, 'R_shunt': -1.0739821416427926}
[INFO 12-08 10:02:00] optimpv.axBOtorchOptimizer: Trial 20 completed with results: {'diode_dark_mse_soft_l1': 0.2167798916337298} and parameters: {'J0': -4.104711637285448, 'n': 1.8340266999239438, 'R_series': -3.093905541941233, 'R_shunt': -0.9953993373278287}
[INFO 12-08 10:02:00] optimpv.axBOtorchOptimizer: Trial 21 completed with results: {'diode_dark_mse_soft_l1': 0.1534359129528866} and parameters: {'J0': -5.293707663942541, 'n': 1.331274184151106, 'R_series': -3.0, 'R_shunt': -1.0739821416427926}
[INFO 12-08 10:02:01] optimpv.axBOtorchOptimizer: Trial 22 with parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -3.711250016793966, 'R_shunt': -0.48810524878429495}
[INFO 12-08 10:02:01] optimpv.axBOtorchOptimizer: Trial 23 with parameters: {'J0': -3.648879808943512, 'n': 1.9244879217194661, 'R_series': -4.290502010750994, 'R_shunt': -0.9508693786972047}
[INFO 12-08 10:02:01] optimpv.axBOtorchOptimizer: Trial 22 completed with results: {'diode_dark_mse_soft_l1': 0.0986745708554091} and parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -3.711250016793966, 'R_shunt': -0.48810524878429495}
[INFO 12-08 10:02:01] optimpv.axBOtorchOptimizer: Trial 23 completed with results: {'diode_dark_mse_soft_l1': 0.004892675677911296} and parameters: {'J0': -3.648879808943512, 'n': 1.9244879217194661, 'R_series': -4.290502010750994, 'R_shunt': -0.9508693786972047}
[INFO 12-08 10:02:02] optimpv.axBOtorchOptimizer: Trial 24 with parameters: {'J0': -3.4923947749370106, 'n': 2.0, 'R_series': -4.082051458454549, 'R_shunt': -0.9001456389502378}
[INFO 12-08 10:02:02] optimpv.axBOtorchOptimizer: Trial 25 with parameters: {'J0': -6.0, 'n': 1.0, 'R_series': -3.0, 'R_shunt': -0.5357359582889256}
[INFO 12-08 10:02:02] optimpv.axBOtorchOptimizer: Trial 24 completed with results: {'diode_dark_mse_soft_l1': 0.013574244153109483} and parameters: {'J0': -3.4923947749370106, 'n': 2.0, 'R_series': -4.082051458454549, 'R_shunt': -0.9001456389502378}
[INFO 12-08 10:02:02] optimpv.axBOtorchOptimizer: Trial 25 completed with results: {'diode_dark_mse_soft_l1': 0.21869231750002127} and parameters: {'J0': -6.0, 'n': 1.0, 'R_series': -3.0, 'R_shunt': -0.5357359582889256}
[INFO 12-08 10:02:02] optimpv.axBOtorchOptimizer: Trial 26 with parameters: {'J0': -4.732535019139654, 'n': 1.7476072581636428, 'R_series': -5.0, 'R_shunt': -1.1051641863544008}
[INFO 12-08 10:02:02] optimpv.axBOtorchOptimizer: Trial 27 with parameters: {'J0': -3.444744192040062, 'n': 1.964870669997924, 'R_series': -4.3477554047165725, 'R_shunt': -0.6806458021449608}
[INFO 12-08 10:02:03] optimpv.axBOtorchOptimizer: Trial 26 completed with results: {'diode_dark_mse_soft_l1': 0.07462514383908969} and parameters: {'J0': -4.732535019139654, 'n': 1.7476072581636428, 'R_series': -5.0, 'R_shunt': -1.1051641863544008}
[INFO 12-08 10:02:03] optimpv.axBOtorchOptimizer: Trial 27 completed with results: {'diode_dark_mse_soft_l1': 0.04035654199767791} and parameters: {'J0': -3.444744192040062, 'n': 1.964870669997924, 'R_series': -4.3477554047165725, 'R_shunt': -0.6806458021449608}
[INFO 12-08 10:02:03] optimpv.axBOtorchOptimizer: Trial 28 with parameters: {'J0': -4.304914423304761, 'n': 1.8052902409420475, 'R_series': -4.298437921849314, 'R_shunt': -0.9963221893769174}
[INFO 12-08 10:02:03] optimpv.axBOtorchOptimizer: Trial 29 with parameters: {'J0': -5.329279075918768, 'n': 1.5277944269044261, 'R_series': -4.228993636080501, 'R_shunt': -0.9981675017785445}
[INFO 12-08 10:02:03] optimpv.axBOtorchOptimizer: Trial 28 completed with results: {'diode_dark_mse_soft_l1': 0.024567604262187626} and parameters: {'J0': -4.304914423304761, 'n': 1.8052902409420475, 'R_series': -4.298437921849314, 'R_shunt': -0.9963221893769174}
[INFO 12-08 10:02:03] optimpv.axBOtorchOptimizer: Trial 29 completed with results: {'diode_dark_mse_soft_l1': 0.019855318618794193} and parameters: {'J0': -5.329279075918768, 'n': 1.5277944269044261, 'R_series': -4.228993636080501, 'R_shunt': -0.9981675017785445}
[INFO 12-08 10:02:04] optimpv.axBOtorchOptimizer: Trial 30 with parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -4.108078342758169, 'R_shunt': -1.0058734664009137}
[INFO 12-08 10:02:04] optimpv.axBOtorchOptimizer: Trial 31 with parameters: {'J0': -5.988683037436657, 'n': 1.5845613609479774, 'R_series': -4.4545690081649125, 'R_shunt': -1.0473067494930137}
[INFO 12-08 10:02:04] optimpv.axBOtorchOptimizer: Trial 30 completed with results: {'diode_dark_mse_soft_l1': 0.026558605481546316} and parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -4.108078342758169, 'R_shunt': -1.0058734664009137}
[INFO 12-08 10:02:04] optimpv.axBOtorchOptimizer: Trial 31 completed with results: {'diode_dark_mse_soft_l1': 0.17678233702005475} and parameters: {'J0': -5.988683037436657, 'n': 1.5845613609479774, 'R_series': -4.4545690081649125, 'R_shunt': -1.0473067494930137}
[INFO 12-08 10:02:05] optimpv.axBOtorchOptimizer: Trial 32 with parameters: {'J0': -4.784931902552721, 'n': 1.5959150537120077, 'R_series': -4.232082280555219, 'R_shunt': -1.050847042119294}
[INFO 12-08 10:02:05] optimpv.axBOtorchOptimizer: Trial 33 with parameters: {'J0': -5.454938523646865, 'n': 1.3762045880279155, 'R_series': -3.9464442177475583, 'R_shunt': -1.0744213165811254}
[INFO 12-08 10:02:05] optimpv.axBOtorchOptimizer: Trial 32 completed with results: {'diode_dark_mse_soft_l1': 0.006051051245111516} and parameters: {'J0': -4.784931902552721, 'n': 1.5959150537120077, 'R_series': -4.232082280555219, 'R_shunt': -1.050847042119294}
[INFO 12-08 10:02:05] optimpv.axBOtorchOptimizer: Trial 33 completed with results: {'diode_dark_mse_soft_l1': 0.004649976044920567} and parameters: {'J0': -5.454938523646865, 'n': 1.3762045880279155, 'R_series': -3.9464442177475583, 'R_shunt': -1.0744213165811254}
[INFO 12-08 10:02:05] optimpv.axBOtorchOptimizer: Trial 34 with parameters: {'J0': -5.1033251762725165, 'n': 1.4783184017624382, 'R_series': -3.989690169387727, 'R_shunt': -1.0374121259709426}
[INFO 12-08 10:02:05] optimpv.axBOtorchOptimizer: Trial 35 with parameters: {'J0': -5.126770976096094, 'n': 1.4821971330769983, 'R_series': -4.262244118123534, 'R_shunt': -1.1233002393312035}
[INFO 12-08 10:02:05] optimpv.axBOtorchOptimizer: Trial 34 completed with results: {'diode_dark_mse_soft_l1': 0.0006115248309050969} and parameters: {'J0': -5.1033251762725165, 'n': 1.4783184017624382, 'R_series': -3.989690169387727, 'R_shunt': -1.0374121259709426}
[INFO 12-08 10:02:05] optimpv.axBOtorchOptimizer: Trial 35 completed with results: {'diode_dark_mse_soft_l1': 0.017080775890807143} and parameters: {'J0': -5.126770976096094, 'n': 1.4821971330769983, 'R_series': -4.262244118123534, 'R_shunt': -1.1233002393312035}
[INFO 12-08 10:02:06] optimpv.axBOtorchOptimizer: Trial 36 with parameters: {'J0': -5.2218719177629715, 'n': 1.4432937354832718, 'R_series': -3.955860924977439, 'R_shunt': -0.9249389373195767}
[INFO 12-08 10:02:06] optimpv.axBOtorchOptimizer: Trial 37 with parameters: {'J0': -3.0, 'n': 1.0, 'R_series': -3.0, 'R_shunt': 2.0}
[INFO 12-08 10:02:06] optimpv.axBOtorchOptimizer: Trial 36 completed with results: {'diode_dark_mse_soft_l1': 0.0028055720094433134} and parameters: {'J0': -5.2218719177629715, 'n': 1.4432937354832718, 'R_series': -3.955860924977439, 'R_shunt': -0.9249389373195767}
[INFO 12-08 10:02:06] optimpv.axBOtorchOptimizer: Trial 37 completed with results: {'diode_dark_mse_soft_l1': 0.8279350597702431} and parameters: {'J0': -3.0, 'n': 1.0, 'R_series': -3.0, 'R_shunt': 2.0}
[INFO 12-08 10:02:07] optimpv.axBOtorchOptimizer: Trial 38 with parameters: {'J0': -3.817377055339664, 'n': 1.7723770068242883, 'R_series': -3.9872848626952386, 'R_shunt': -0.9703262811057263}
[INFO 12-08 10:02:07] optimpv.axBOtorchOptimizer: Trial 39 with parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -5.0, 'R_shunt': -2.0}
[INFO 12-08 10:02:07] optimpv.axBOtorchOptimizer: Trial 38 completed with results: {'diode_dark_mse_soft_l1': 0.004527017070911743} and parameters: {'J0': -3.817377055339664, 'n': 1.7723770068242883, 'R_series': -3.9872848626952386, 'R_shunt': -0.9703262811057263}
[INFO 12-08 10:02:07] optimpv.axBOtorchOptimizer: Trial 39 completed with results: {'diode_dark_mse_soft_l1': 0.5817277854445164} and parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -5.0, 'R_shunt': -2.0}
[INFO 12-08 10:02:08] optimpv.axBOtorchOptimizer: Trial 40 with parameters: {'J0': -3.5694536158214474, 'n': 1.8788853329780701, 'R_series': -4.070710407098016, 'R_shunt': -0.9907716103672244}
[INFO 12-08 10:02:08] optimpv.axBOtorchOptimizer: Trial 41 with parameters: {'J0': -4.516173116420073, 'n': 1.6173443953456306, 'R_series': -4.031564959963397, 'R_shunt': -0.9601318912373906}
[INFO 12-08 10:02:08] optimpv.axBOtorchOptimizer: Trial 40 completed with results: {'diode_dark_mse_soft_l1': 0.0034032353517647884} and parameters: {'J0': -3.5694536158214474, 'n': 1.8788853329780701, 'R_series': -4.070710407098016, 'R_shunt': -0.9907716103672244}
[INFO 12-08 10:02:08] optimpv.axBOtorchOptimizer: Trial 41 completed with results: {'diode_dark_mse_soft_l1': 0.0006669158396328534} and parameters: {'J0': -4.516173116420073, 'n': 1.6173443953456306, 'R_series': -4.031564959963397, 'R_shunt': -0.9601318912373906}
[INFO 12-08 10:02:09] optimpv.axBOtorchOptimizer: Trial 42 with parameters: {'J0': -4.876860677645713, 'n': 1.520466725234367, 'R_series': -4.048168954561357, 'R_shunt': -0.9558185840883124}
[INFO 12-08 10:02:09] optimpv.axBOtorchOptimizer: Trial 43 with parameters: {'J0': -6.0, 'n': 1.0, 'R_series': -3.0, 'R_shunt': 2.0}
[INFO 12-08 10:02:09] optimpv.axBOtorchOptimizer: Trial 42 completed with results: {'diode_dark_mse_soft_l1': 0.0013951834148722142} and parameters: {'J0': -4.876860677645713, 'n': 1.520466725234367, 'R_series': -4.048168954561357, 'R_shunt': -0.9558185840883124}
[INFO 12-08 10:02:09] optimpv.axBOtorchOptimizer: Trial 43 completed with results: {'diode_dark_mse_soft_l1': 1.7002818616719466} and parameters: {'J0': -6.0, 'n': 1.0, 'R_series': -3.0, 'R_shunt': 2.0}
[INFO 12-08 10:02:10] optimpv.axBOtorchOptimizer: Trial 44 with parameters: {'J0': -4.275817658767518, 'n': 1.6885496158965885, 'R_series': -4.110978248530864, 'R_shunt': -1.034478658956087}
[INFO 12-08 10:02:10] optimpv.axBOtorchOptimizer: Trial 45 with parameters: {'J0': -4.917172432782519, 'n': 1.5394366921390525, 'R_series': -3.949103183957739, 'R_shunt': -1.0094679013862096}
[INFO 12-08 10:02:10] optimpv.axBOtorchOptimizer: Trial 44 completed with results: {'diode_dark_mse_soft_l1': 0.0015849143857584735} and parameters: {'J0': -4.275817658767518, 'n': 1.6885496158965885, 'R_series': -4.110978248530864, 'R_shunt': -1.034478658956087}
[INFO 12-08 10:02:10] optimpv.axBOtorchOptimizer: Trial 45 completed with results: {'diode_dark_mse_soft_l1': 0.002443510292194695} and parameters: {'J0': -4.917172432782519, 'n': 1.5394366921390525, 'R_series': -3.949103183957739, 'R_shunt': -1.0094679013862096}
[INFO 12-08 10:02:11] optimpv.axBOtorchOptimizer: Trial 46 with parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -3.0, 'R_shunt': 2.0}
[INFO 12-08 10:02:11] optimpv.axBOtorchOptimizer: Trial 47 with parameters: {'J0': -4.461369016706359, 'n': 1.6547418028825862, 'R_series': -4.187325029800215, 'R_shunt': -0.9354733632786709}
[INFO 12-08 10:02:11] optimpv.axBOtorchOptimizer: Trial 46 completed with results: {'diode_dark_mse_soft_l1': 1.0546565833258126} and parameters: {'J0': -3.0, 'n': 2.0, 'R_series': -3.0, 'R_shunt': 2.0}
[INFO 12-08 10:02:11] optimpv.axBOtorchOptimizer: Trial 47 completed with results: {'diode_dark_mse_soft_l1': 0.004043318324771228} and parameters: {'J0': -4.461369016706359, 'n': 1.6547418028825862, 'R_series': -4.187325029800215, 'R_shunt': -0.9354733632786709}
[INFO 12-08 10:02:12] optimpv.axBOtorchOptimizer: Trial 48 with parameters: {'J0': -3.95166607052374, 'n': 1.7889984317083631, 'R_series': -4.107266485592855, 'R_shunt': -0.9662669394990984}
[INFO 12-08 10:02:12] optimpv.axBOtorchOptimizer: Trial 49 with parameters: {'J0': -5.259642795675458, 'n': 1.4266377480034915, 'R_series': -3.904556019823467, 'R_shunt': -0.9988932598173752}
[INFO 12-08 10:02:12] optimpv.axBOtorchOptimizer: Trial 48 completed with results: {'diode_dark_mse_soft_l1': 0.0012062920955426826} and parameters: {'J0': -3.95166607052374, 'n': 1.7889984317083631, 'R_series': -4.107266485592855, 'R_shunt': -0.9662669394990984}
[INFO 12-08 10:02:12] optimpv.axBOtorchOptimizer: Trial 49 completed with results: {'diode_dark_mse_soft_l1': 0.0008318511472911183} and parameters: {'J0': -5.259642795675458, 'n': 1.4266377480034915, 'R_series': -3.904556019823467, 'R_shunt': -0.9988932598173752}
[7]:
# get the best parameters and update the params list in the optimizer and the agent
ax_client = optimizer.ax_client # get the ax client
optimizer.update_params_with_best_balance() # update the params list in the optimizer with the best parameters
diode.params = optimizer.params # update the params list in the agent with the best parameters

# print the best parameters
print('Best parameters:')
for p,po in zip(optimizer.params, params_orig):
    print(p.name, 'fitted value:', p.value, 'original value:', po.value)
Best parameters:
J0 fitted value: 7.882696828016435e-06 original value: 1e-05
n fitted value: 1.4783184017624382 original value: 1.5
R_series fitted value: 0.00010240232815823409 original value: 0.0001
R_shunt fitted value: 0.0917461553422673 original value: 0.1
[8]:
# Plot optimization results
data = ax_client.summarize()
all_metrics = optimizer.all_metrics
tracking_metrics = optimizer.all_tracking_metrics
plt.figure()
plt.plot(np.minimum.accumulate(data[all_metrics]), label="Best value seen so far")
plt.yscale("log")
plt.xlabel("Iteration")
plt.ylabel("Target metric: " + metric + " with " + loss + " loss")
plt.legend()
plt.title("Best value seen so far")

print("Best value seen so far is ", min(data[all_metrics[0]]), "at iteration ", int(data[all_metrics].idxmin()))
plt.show()
Best value seen so far is  0.0006115248309050969 at iteration  34
../_images/examples_diode_12_1.png
[9]:
# rerun the simulation with the best parameters
yfit = diode.run(parameters={})

plt.figure(figsize=(10,10))
plt.plot(X,y,label='data')
plt.plot(X,yfit,label='fit',linestyle='--')
plt.xscale('linear')
plt.yscale('log')
plt.xlabel('Applied voltage [V]')
plt.ylabel('Current density [A m$^{-2}$]')
plt.legend()
plt.show()
../_images/examples_diode_13_0.png
[10]:
cards = ax_client.compute_analyses(display=True)
Overview of the Entire Optimization Process

This analysis provides an overview of the entire optimization process. It includes visualizations of the results obtained so far, insights into the parameter and metric relationships learned by the Ax model, diagnostics such as model fit, and health checks to assess the overall health of the experiment.

Results Analysis

Result Analyses provide a high-level overview of the results of the optimization process so far with respect to the metrics specified in experiment design.

Metric Effects: Predicted and observed effects for all arms in the experiment

These pair of plots visualize the metric effects for each arm, with the Ax model predictions on the left and the raw observed data on the right. The predicted effects apply shrinkage for noise and adjust for non-stationarity in the data, so they are more representative of the reproducible effects that will manifest in a long-term validation experiment.

Metric Effects Pair for diode_dark_mse_soft_l1

Modeled Arm Effects on diode_dark_mse_soft_l1

Modeled effects on diode_dark_mse_soft_l1. This plot visualizes predictions of the true metric changes for each arm based on Ax's model. This is the expected delta you would expect if you (re-)ran that arm. This plot helps in anticipating the outcomes and performance of arms based on the model's predictions. Note, flat predictions across arms indicate that the model predicts that there is no effect, meaning if you were to re-run the experiment, the delta you would see would be small and fall within the confidence interval indicated in the plot.

Observed Arm Effects on diode_dark_mse_soft_l1

Observed effects on diode_dark_mse_soft_l1. This plot visualizes the effects from previously-run arms on a specific metric, providing insights into their performance. This plot allows one to compare and contrast the effectiveness of different arms, highlighting which configurations have yielded the most favorable outcomes.

Summary for ax_opti

High-level summary of the `Trial`-s in this `Experiment`

trial_index arm_name trial_status generation_node diode_dark_mse_soft_l1 J0 n R_series R_shunt
0 0 0_0 COMPLETED SOBOL 0.179657 -5.856603 1.331971 -4.676434 -1.451207
1 1 1_0 COMPLETED SOBOL 1.428286 -4.181836 1.658044 -3.946013 1.798087
2 2 2_0 COMPLETED SOBOL 1.137198 -3.432493 1.205568 -4.486195 -0.129635
3 3 3_0 COMPLETED SOBOL 1.351052 -5.109242 1.781883 -3.138434 0.620649
4 4 4_0 COMPLETED SOBOL 0.788445 -4.576212 1.022388 -3.689004 0.333975
5 5 5_0 COMPLETED SOBOL 0.091452 -3.206270 1.973429 -4.935146 -0.916782
6 6 6_0 COMPLETED SOBOL 0.864074 -3.956743 1.398059 -3.379869 1.030562
7 7 7_0 COMPLETED SOBOL 0.255260 -5.329034 1.599345 -4.243046 -1.719235
8 8 8_0 COMPLETED SOBOL 0.126887 -5.558104 1.133143 -3.318067 -0.680927
9 9 9_0 COMPLETED SOBOL 0.411454 -3.906019 1.869571 -4.056335 0.068793
10 10 10_0 COMPLETED BOTORCH_MODULAR 0.117670 -3.904806 1.921309 -4.197046 -1.470877
11 11 11_0 COMPLETED BOTORCH_MODULAR 0.199030 -6.000000 1.000000 -3.199575 -1.358093
12 12 12_0 COMPLETED BOTORCH_MODULAR 0.525690 -3.000000 2.000000 -3.183433 -2.000000
13 13 13_0 COMPLETED BOTORCH_MODULAR 0.512697 -5.146812 1.203277 -3.514855 -2.000000
14 14 14_0 COMPLETED BOTORCH_MODULAR 0.054339 -3.834658 2.000000 -4.648309 -0.864791
15 15 15_0 COMPLETED BOTORCH_MODULAR 0.104514 -3.650387 1.801393 -4.850950 -0.963671
16 16 16_0 COMPLETED BOTORCH_MODULAR 0.548249 -6.000000 1.134563 -5.000000 -0.664737
17 17 17_0 COMPLETED BOTORCH_MODULAR 0.696445 -6.000000 2.000000 -5.000000 -2.000000
18 18 18_0 COMPLETED BOTORCH_MODULAR 0.099202 -6.000000 1.296861 -3.257546 -1.095246
19 19 19_0 COMPLETED BOTORCH_MODULAR 0.011069 -3.438043 1.927495 -4.023647 -0.836732
20 20 20_0 COMPLETED BOTORCH_MODULAR 0.216780 -4.104712 1.834027 -3.093906 -0.995399
21 21 21_0 COMPLETED BOTORCH_MODULAR 0.153436 -5.293708 1.331274 -3.000000 -1.073982
22 22 22_0 COMPLETED BOTORCH_MODULAR 0.098675 -3.000000 2.000000 -3.711250 -0.488105
23 23 23_0 COMPLETED BOTORCH_MODULAR 0.004893 -3.648880 1.924488 -4.290502 -0.950869
24 24 24_0 COMPLETED BOTORCH_MODULAR 0.013574 -3.492395 2.000000 -4.082051 -0.900146
25 25 25_0 COMPLETED BOTORCH_MODULAR 0.218692 -6.000000 1.000000 -3.000000 -0.535736
26 26 26_0 COMPLETED BOTORCH_MODULAR 0.074625 -4.732535 1.747607 -5.000000 -1.105164
27 27 27_0 COMPLETED BOTORCH_MODULAR 0.040357 -3.444744 1.964871 -4.347755 -0.680646
28 28 28_0 COMPLETED BOTORCH_MODULAR 0.024568 -4.304914 1.805290 -4.298438 -0.996322
29 29 29_0 COMPLETED BOTORCH_MODULAR 0.019855 -5.329279 1.527794 -4.228994 -0.998168
30 30 30_0 COMPLETED BOTORCH_MODULAR 0.026559 -3.000000 2.000000 -4.108078 -1.005873
31 31 31_0 COMPLETED BOTORCH_MODULAR 0.176782 -5.988683 1.584561 -4.454569 -1.047307
32 32 32_0 COMPLETED BOTORCH_MODULAR 0.006051 -4.784932 1.595915 -4.232082 -1.050847
33 33 33_0 COMPLETED BOTORCH_MODULAR 0.004650 -5.454939 1.376205 -3.946444 -1.074421
34 34 34_0 COMPLETED BOTORCH_MODULAR 0.000612 -5.103325 1.478318 -3.989690 -1.037412
35 35 35_0 COMPLETED BOTORCH_MODULAR 0.017081 -5.126771 1.482197 -4.262244 -1.123300
36 36 36_0 COMPLETED BOTORCH_MODULAR 0.002806 -5.221872 1.443294 -3.955861 -0.924939
37 37 37_0 COMPLETED BOTORCH_MODULAR 0.827935 -3.000000 1.000000 -3.000000 2.000000
38 38 38_0 COMPLETED BOTORCH_MODULAR 0.004527 -3.817377 1.772377 -3.987285 -0.970326
39 39 39_0 COMPLETED BOTORCH_MODULAR 0.581728 -3.000000 2.000000 -5.000000 -2.000000
40 40 40_0 COMPLETED BOTORCH_MODULAR 0.003403 -3.569454 1.878885 -4.070710 -0.990772
41 41 41_0 COMPLETED BOTORCH_MODULAR 0.000667 -4.516173 1.617344 -4.031565 -0.960132
42 42 42_0 COMPLETED BOTORCH_MODULAR 0.001395 -4.876861 1.520467 -4.048169 -0.955819
43 43 43_0 COMPLETED BOTORCH_MODULAR 1.700282 -6.000000 1.000000 -3.000000 2.000000
44 44 44_0 COMPLETED BOTORCH_MODULAR 0.001585 -4.275818 1.688550 -4.110978 -1.034479
45 45 45_0 COMPLETED BOTORCH_MODULAR 0.002444 -4.917172 1.539437 -3.949103 -1.009468
46 46 46_0 COMPLETED BOTORCH_MODULAR 1.054657 -3.000000 2.000000 -3.000000 2.000000
47 47 47_0 COMPLETED BOTORCH_MODULAR 0.004043 -4.461369 1.654742 -4.187325 -0.935473
48 48 48_0 COMPLETED BOTORCH_MODULAR 0.001206 -3.951666 1.788998 -4.107266 -0.966267
49 49 49_0 COMPLETED BOTORCH_MODULAR 0.000832 -5.259643 1.426638 -3.904556 -0.998893
Insights Analysis

Insight Analyses display information to help understand the underlying experiment i.e parameter and metric relationships learned by the Ax model.Use this information to better understand your experiment space and users.

Top Surfaces Analysis: Parameter sensitivity, slice, and contour plots

The top surfaces analysis displays three analyses in one. First, it shows parameter sensitivities, which shows the sensitivity of the metrics in the experiment to the most important parameters. Subsetting to only the most important parameters, it then shows slice plots and contour plots for each metric in the experiment, displaying the relationship between the metric and the most important parameters.

Sensitivity Analysis for diode_dark_mse_so...

Understand how each parameter affects diode_dark_mse_so... according to a second-order sensitivity analysis.

Slice Plots: Metric effects by parameter value

These plots show the relationship between a metric and a parameter. They show the predicted values of the metric on the y-axis as a function of the parameter on the x-axis while keeping all other parameters fixed at their status_quo value (or mean value if status_quo is unavailable).

diode_dark_mse_soft_l1 vs. R_shunt

The slice plot provides a one-dimensional view of predicted outcomes for diode_dark_mse_soft_l1 as a function of a single parameter, while keeping all other parameters fixed at their status_quo value (or mean value if status_quo is unavailable). This visualization helps in understanding the sensitivity and impact of changes in the selected parameter on the predicted metric outcomes.

Contour Plots: Metric effects by parameter values

These plots show the relationship between a metric and two parameters. They show the predicted values of the metric (indicated by color) as a function of the two parameters on the x- and y-axes while keeping all other parameters fixed at their status_quo value (or mean value if status_quo is unavailable).

diode_dark_mse_soft_l1 vs. J0, R_shunt

The contour plot visualizes the predicted outcomes for diode_dark_mse_soft_l1 across a two-dimensional parameter space, with other parameters held fixed at their status_quo value (or mean value if status_quo is unavailable). This plot helps in identifying regions of optimal performance and understanding how changes in the selected parameters influence the predicted outcomes. Contour lines represent levels of constant predicted values, providing insights into the gradient and potential optima within the parameter space.

diode_dark_mse_soft_l1 vs. J0, n

The contour plot visualizes the predicted outcomes for diode_dark_mse_soft_l1 across a two-dimensional parameter space, with other parameters held fixed at their status_quo value (or mean value if status_quo is unavailable). This plot helps in identifying regions of optimal performance and understanding how changes in the selected parameters influence the predicted outcomes. Contour lines represent levels of constant predicted values, providing insights into the gradient and potential optima within the parameter space.

Diagnostic Analysis

Diagnostic Analyses provide information about the optimization process and the quality of the model fit. You can use this information to understand if the experimental design should be adjusted to improve optimization quality.

Cross Validation: Assessing model fit

Cross-validation plots display the model fit for each metric in the experiment. The model is trained on a subset of the data and then predicts the outcome for the remaining subset. The plots show the predicted outcome for the validation set on the y-axis against its actual value on the x-axis. Points that align closely with the dotted diagonal line indicate a strong model fit, signifying accurate predictions. Additionally, the plots include confidence intervals that provide insight into the noise in observations and the uncertainty in model predictions.

NOTE: A horizontal, flat line of predictions indicates that the model has not picked up on sufficient signal in the data, and instead is just predicting the mean.

Cross Validation for diode_dark_mse_soft_l1

The cross-validation plot displays the model fit for each metric in the experiment. It employs a leave-one-out approach, where the model is trained on all data except one sample, which is used for validation. The plot shows the predicted outcome for the validation set on the y-axis against its actual value on the x-axis. Points that align closely with the dotted diagonal line indicate a strong model fit, signifying accurate predictions. Additionally, the plot includes 95% confidence intervals that provide insight into the noise in observations and the uncertainty in model predictions. A horizontal, flat line of predictions indicates that the model has not picked up on sufficient signal in the data, and instead is just predicting the mean.

Moving on to the scipy optimizer

[11]:
params_scipy = deepcopy(diode.params) # make copies of the parameters
# change the values of params scipy by a random value between the bounds
for param in params_scipy:
    param.value = np.random.uniform(param.bounds[0], param.bounds[1])
    print(f'param: {param.name}, value: {param.value}, bounds: {param.bounds}')

# Create a new agent with the new parameters
# this is needed as the scipy optimizer uses the parameters values as the initial guess for the optimization
diode2 = deepcopy(diode) # make a copy of the agent
diode2.params = params_scipy # set the new parameters

from optimpv.scipyOpti.scipyOptimizer import ScipyOptimizer
scipyOpti = ScipyOptimizer(params=params_scipy, agents=diode2, method='dogbox', options={'max_nfev': 10000}, name='scipy_opti', parallel_agents=True, max_parallelism=os.cpu_count()-1, verbose_logging=True)
param: J0, value: 8.036573551708972e-05, bounds: [1e-06, 0.001]
param: n, value: 1.9066552982120157, bounds: [1, 2]
param: R_series, value: 0.00048733165966512014, bounds: [1e-05, 0.001]
param: R_shunt, value: 12.381636434556007, bounds: [0.01, 100.0]
[12]:
scipyOpti.optimize_least_squares() # run the optimization with scipy least squares
Starting optimization using dogbox method
Optimization completed with status: `gtol` termination condition is satisfied.
Final objective value: [3.66849524e-05]
[12]:
     message: `gtol` termination condition is satisfied.
     success: True
      status: 1
         fun: [ 3.668e-05]
           x: [-4.770e+00  1.554e+00 -4.018e+00 -9.969e-01]
        cost: 6.728928649043011e-10
         jac: [[ 2.712e-04  2.403e-04  5.044e-07  1.583e-05]]
        grad: [ 9.948e-09  8.816e-09  1.850e-11  5.805e-10]
  optimality: 9.948111575291883e-09
 active_mask: [0 0 0 0]
        nfev: 2589
        njev: 2520
[13]:
# get the best parameters and update the params list in the optimizer and the agent
diode2.params = scipyOpti.params # update the params list in the agent with the best parameters.append
# print the best parameters
print('Best parameters:')
for p,po in zip(scipyOpti.params, params_orig):
    if p.axis_type == 'log':
        print(p.name, 'fitted value:', '{:.2e}'.format(p.value), 'original value:', '{:.2e}'.format(po.value))
    else:
        print(p.name, 'fitted value:', p.value, 'original value:', po.value)
Best parameters:
J0 fitted value: 1.70e-05 original value: 1.00e-05
n fitted value: 1.5541131429362978 original value: 1.5
R_series fitted value: 9.59e-05 original value: 1.00e-04
R_shunt fitted value: 1.01e-01 original value: 1.00e-01
[14]:
# rerun the simulation with the best parameters
yfit = diode2.run(parameters={})

plt.figure(figsize=(10,10))
plt.plot(X,y,label='data')
plt.plot(X,yfit,label='fit',linestyle='--')
plt.xscale('linear')
plt.yscale('log')
plt.xlabel('Applied voltage [V]')
plt.ylabel('Current density [A m$^{-2}$]')
plt.legend()
plt.show()
../_images/examples_diode_19_0.png

Define the parameters for the simulation for light JV

Now we run only the scipy optimization to fit the light JV-curve.

[15]:
##############################################################################################
# Define the parameters to be fitted
params = []

J0 = FitParam(name = 'J0', value = 1e-6, bounds = [1e-7,1e-4], log_scale = True, rescale = False, value_type = 'float', type='range', display_name=r'$J_0$', unit='A m$^{-2}$', axis_type = 'log',force_log=True)
params.append(J0)

n = FitParam(name = 'n', value = 1.5, bounds = [1,2], log_scale = False, value_type = 'float', type='range', display_name=r'$n$', unit='', axis_type = 'linear')
params.append(n)

R_series = FitParam(name = 'R_series', value = 1e-4, bounds = [1e-5,1e-3], log_scale = True, rescale = False, value_type = 'float', type='range', display_name=r'$R_{\text{series}}$', unit=r'$\Omega$ m$^2$', axis_type = 'log',force_log=True)
params.append(R_series)

R_shunt = FitParam(name = 'R_shunt', value = 1e-1, bounds = [1e-2,1e2], log_scale = True, rescale = False, value_type = 'float', type='range', display_name=r'$R_{\text{shunt}}$', unit=r'$\Omega$ m$^2$', axis_type = 'log',force_log=True)
params.append(R_shunt)

Jph = FitParam(name = 'Jph', value = 200, bounds = [150,250], log_scale = False, rescale = False, value_type = 'float', type='range', display_name=r'$J_{\text{ph}}$', unit='A m$^{-2}$', axis_type = 'linear')
params.append(Jph)

# original values
params_orig_light = copy.deepcopy(params)
num_free_params = len([p for p in params if p.type != 'fixed'])
[16]:
# Create JV to fit
X_light = np.linspace(0.001,0.8,100)
y_light = NonIdealDiode_light(X_light, J0.value, n.value, R_series.value, R_shunt.value, Jph.value)

plt.figure(figsize=(10,6))
plt.plot(X_light,y_light)
plt.xlabel('Voltage [V]')
plt.ylabel('Current density [A m$^{-2}$]')

[16]:
Text(0, 0.5, 'Current density [A m$^{-2}$]')
../_images/examples_diode_22_1.png

Run the optimization

[17]:
# Define the agents
metric = 'nrmse' # can be 'nrmse', 'mse', 'mae'
loss = 'linear' # can be 'linear', 'huber', 'soft_l1'
exp_format = 'light' # can be 'dark', 'light' depending on the type of data you have
use_pvlib = False # if True, use pvlib to calculate the diode model if not use the implementation in DiodeModel.py

diode_light = DiodeAgent(params, X_light, y_light, metric = metric, loss = loss, minimize=True,exp_format=exp_format,use_pvlib=False)
[18]:
params_scipy_light = deepcopy(diode_light.params) # make copies of the parameters
# change the values of params scipy by a random value between the bounds
for param in params_scipy_light:
    param.value = np.random.uniform(param.bounds[0], param.bounds[1])
    print(f'param: {param.name}, value: {param.value}, bounds: {param.bounds}')

# Create a new agent with the new parameters
# this is needed as the scipy optimizer uses the parameters values as the initial guess for the optimization
diode2_light = deepcopy(diode_light) # make a copy of the agent
diode2_light.params = params_scipy_light # set the new parameters

from optimpv.scipyOpti.scipyOptimizer import ScipyOptimizer
scipyOpti_light = ScipyOptimizer(params=params_scipy_light, agents=diode2_light, method='L-BFGS-B', options={'maxiter':int(1e5),'ftol':1e-13,'xtol':1e-10}, name='scipy_opti', parallel_agents=True, max_parallelism=os.cpu_count()-1, verbose_logging=True)
param: J0, value: 7.481455936137577e-05, bounds: [1e-07, 0.0001]
param: n, value: 1.5587378769269615, bounds: [1, 2]
param: R_series, value: 5.107735337763866e-05, bounds: [1e-05, 0.001]
param: R_shunt, value: 10.933383303854264, bounds: [0.01, 100.0]
param: Jph, value: 216.78241067733728, bounds: [150, 250]
[19]:
scipyOpti_light.optimize() # run the optimization with scipy
Starting optimization using L-BFGS-B method
Optimization completed with status: CONVERGENCE: RELATIVE REDUCTION OF F <= FACTR*EPSMCH
Final objective value: 6.065044300991583e-07
[19]:
  message: CONVERGENCE: RELATIVE REDUCTION OF F <= FACTR*EPSMCH
  success: True
   status: 0
      fun: 6.065044300991583e-07
        x: [-6.000e+00  1.500e+00 -4.000e+00 -1.000e+00  2.000e+02]
      nit: 131
      jac: [ 3.458e-03 -8.959e-03 -2.904e-04  6.950e-04 -6.070e-05]
     nfev: 1434
     njev: 239
 hess_inv: <5x5 LbfgsInvHessProduct with dtype=float64>
[20]:
# get the best parameters and update the params list in the optimizer and the agent
diode2_light.params = scipyOpti_light.params # update the params list in the agent with the best parameters.append
# print the best parameters
print('Best parameters:')
for p,po in zip(scipyOpti_light.params, params_orig_light):
    if p.axis_type == 'log':
        print(p.name, 'fitted value:', '{:.2e}'.format(p.value), 'original value:', '{:.2e}'.format(po.value))
    else:
        print(p.name, 'fitted value:', p.value, 'original value:', po.value)
Best parameters:
J0 fitted value: 9.99e-07 original value: 1.00e-06
n fitted value: 1.4999507103789609 original value: 1.5
R_series fitted value: 1.00e-04 original value: 1.00e-04
R_shunt fitted value: 1.00e-01 original value: 1.00e-01
Jph fitted value: 200.00016099383743 original value: 200
[21]:
# rerun the simulation with the best parameters
yfit_light = diode2_light.run(parameters={})

plt.figure(figsize=(10,10))
plt.plot(X_light,y_light,label='data')
plt.plot(X_light,yfit_light,label='fit',linestyle='--')
plt.xscale('linear')
# plt.yscale('log')
plt.xlabel('Applied voltage [V]')
plt.ylabel('Current density [A m$^{-2}$]')
plt.legend()
plt.show()
../_images/examples_diode_28_0.png