QFLS and light-intensity dependant JV fits perovskite solar cell (real data)

This notebook is a demonstration of how to fit light-intensity dependent QFLS and JV curves with drift-diffusion models using the SIMsalabim package.

It uses real experimental data from perovskite solar cells taken from the following publication:
Grabowski, D., Liu, Z., Schöpe, G., Rau, U. and Kirchartz, T. (2022), Fill Factor Losses and Deviations from the Superposition Principle in Lead Halide Perovskite Solar Cells. Sol. RRL, 6: 2200507. https://doi.org/10.1002/solr.202200507
[1]:
# Import necessary libraries
import warnings, os, sys, shutil,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
import matplotlib
from itertools import combinations
from pySIMsalabim.experiments.JV_steady_state import *
from ax.utils.notebook.plotting import init_notebook_plotting
init_notebook_plotting() # for Jupyter notebooks

try:
    from optimpv import *
except Exception as e:
    sys.path.append('/home/lecorre/Desktop/optimPV') # add the path to the optimpv module
    from optimpv import *
[INFO 12-10 15:13:18] ax.utils.notebook.plotting: Injecting Plotly library into cell. Do not overwrite or delete cell.
[INFO 12-10 15:13:18] ax.utils.notebook.plotting: Please see
    (https://ax.dev/tutorials/visualizations.html#Fix-for-plots-that-are-not-rendering)
    if visualizations are not rendering.

Get the experimental data

[2]:
# Set the session path for the simulation and the input files
session_path = os.path.join(os.path.join(os.path.abspath('../'),'SIMsalabim','SimSS'))
input_path = os.path.join(os.path.join(os.path.join(os.path.abspath('../'),'Data','pero_JV_QFLS')))
simulation_setup_filename = 'simulation_setup_K.txt'
simulation_setup = os.path.join(session_path, simulation_setup_filename)
optical_files = ['nk_glass.txt','nk_ITO.txt','nk_PTAA.txt','nk_MAPI.txt','nk_C60_1.txt','nk_Ag.txt']
# path to the layer files defined in the simulation_setup file
l1 = 'PTAA_K.txt'
l2 = 'MAPI_K.txt'
l3 = 'C60_K.txt'
l1 = os.path.join(input_path, l1)
l2 = os.path.join(input_path, l2)
l3 = os.path.join(input_path, l3)

# copy this files to session_path
force_copy = True
if not os.path.exists(session_path):
    os.makedirs(session_path)
for file in [l1,l2,l3,simulation_setup_filename]:
    file = os.path.join(input_path, os.path.basename(file))
    if force_copy or not os.path.exists(os.path.join(session_path, os.path.basename(file))):
        shutil.copyfile(file, os.path.join(session_path, os.path.basename(file)))
    else:
        print('File already exists: ',file)
# copy the optical files to the session path
for file in optical_files:
    file = os.path.join(input_path, os.path.basename(file))
    if force_copy or not os.path.exists(os.path.join(session_path, os.path.basename(file))):
        shutil.copyfile(file, os.path.join(session_path, os.path.basename(file)))


# Show the device structure
fig = sim.plot_band_diagram(simulation_setup, session_path)
dev_par, layers = sim.load_device_parameters(session_path, simulation_setup, run_mode = False)
SIMsalabim_params  = {}
for layer in layers:
    SIMsalabim_params[layer[1]] = sim.ReadParameterFile(os.path.join(session_path,layer[2]))
L_active_Layer = float(SIMsalabim_params['l2']['L'])

# Load the JV data
X,X_QFLS = [],[]
y,y_QFLS = [],[]

JVs_exp = ['JV_0_279.txt','JV_0_466.txt','JV_0_737.txt','JV_1.txt']
QFLS_exp = ['QFLS_0_279.txt','QFLS_0_466.txt','QFLS_0_737.txt','QFLS_1.txt']
Gfracs = [0.279,0.466,0.737,1]

for i in range(len(JVs_exp)):
    df = pd.read_csv(os.path.join(input_path, JVs_exp[i]),delim_whitespace=True)
    df = df.dropna()
    df_qfls = pd.read_csv(os.path.join(input_path, QFLS_exp[i]),delim_whitespace=True)
    df_qfls = df_qfls.dropna()
    df['Gfrac'] = Gfracs[i]*np.ones(len(df))
    df_qfls['Gfrac'] = Gfracs[i]*np.ones(len(df_qfls))
    if i == 0:
        X = np.asarray(df[['Vext','Gfrac']])
        X_QFLS = np.asarray(df_qfls[['Vext','Gfrac']])
        y = np.asarray(df['Jext'].values*10)
        y_QFLS = np.asarray(df_qfls['QFLS'].values)
    else:
        X = np.vstack((X,df[['Vext','Gfrac']]))
        X_QFLS = np.vstack((X_QFLS,df_qfls[['Vext','Gfrac']]))
        y = np.hstack((y,df['Jext'].values*10))
        y_QFLS = np.hstack((y_QFLS,df_qfls['QFLS'].values))

X = np.asarray(X)
y = np.asarray(y)
X_QFLS = np.asarray(X_QFLS)
y_QFLS = np.asarray(y_QFLS)

# get 1sun Jsc as it will help narrow down the range for Gehp
Jsc_1sun = np.interp(0.0, X[X[:,1] == 1][:,0], y[X[:,1] == 1])
minJ = np.min(y)
q = constants.value(u'elementary charge')
G_ehp_calc = abs(Jsc_1sun/(q*L_active_Layer))
G_ehp_max = abs(minJ/(q*L_active_Layer))

# plot the data for each Gfrac
fig, axes = plt.subplots(1,2, figsize=(16,9))
viridis = plt.get_cmap('viridis', len(Gfracs))
for gfrac in Gfracs:
    axes[0].plot(X[X[:,1] == gfrac][:,0], y[X[:,1] == gfrac],'-',label=str(gfrac), color=viridis(Gfracs.index(gfrac)))

axes[0].legend(title='Gfrac')
axes[0].grid()
axes[0].set_xlabel('Voltage [V]')
axes[0].set_ylabel('Current density [A m$^{-2}$]')
# plt.show()

for gfrac in Gfracs:
    axes[1].plot(X_QFLS[X_QFLS[:,1] == gfrac][:,0], y_QFLS[X_QFLS[:,1] == gfrac],'-',label=str(gfrac), color=viridis(Gfracs.index(gfrac)))
axes[1].grid()
axes[1].set_xlabel('Voltage [V]')
axes[1].set_ylabel('QFLS [eV]')
plt.tight_layout()
plt.show()
../_images/examples_QFLS_JV_perovskite_MOO_pymoo_3_0.png
../_images/examples_QFLS_JV_perovskite_MOO_pymoo_3_1.png

Define the parameters for the simulation

[3]:
# Add Ions in TL
ionsinTLs = 1 # 1: ions can enter the transport layers, 0: ions cannot enter the transport layers
params = [] # list of parameters to be optimized

# Perovskite layer parameters
Nc = FitParam(name = 'l2.N_c', value = 3.15e24, bounds = [1e24,4e24], type='range', values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$N_c$', unit='m$^{-3}$', axis_type = 'log', std = 0,encoding = None,force_log = True,)
params.append(Nc)

mun = FitParam(name = 'l2.mu_n', value = 1.49e-5, bounds = [1e-6,1e-3], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\mu_n$', unit='m$^2$ V$^{-1}$s$^{-1}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(mun)

mup = FitParam(name = 'l2.mu_p', value = 1.905e-5, bounds = [1e-6,1e-3], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\mu_p$', unit='m$^2$ V$^{-1}$s$^{-1}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(mup)

bulk_tr = FitParam(name = 'l2.N_t_bulk', value = 1.3e17, bounds = [1e17,8e21], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$N_{T}$', unit='s', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(bulk_tr)

k_direct = FitParam(name = 'l2.k_direct', value = 2.5e-17, bounds = [1e-18,1e-15], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$k_{direct}$', unit='m$^{3}$ s$^{-1}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(k_direct)

Nions = FitParam(name = 'l2.C_cation', value = 2.77e23, bounds = [5e22,8e23], type='range', values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$N_{ions}$', unit='m$^{-3}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(Nions) # Note: C_cation is not defined in SIMsalabim here this sets the N_cation density and the N_A to the same value, this is the equivalent of having the cations being free to move but the anions are immobile.

Gehp = FitParam(name = 'l2.G_ehp', value = 3.98e27, bounds = [G_ehp_calc*0.8,G_ehp_max*1.2], type='range', values = None, start_value = None, log_scale = False, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$G_{ehp}$', unit='m$^{-3}$ s$^{-1}$', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(Gehp) #G_ehp_calc

eps_r = FitParam(name = 'l2.eps_r', value = 34, bounds = [30,40], type='range', values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\epsilon_r$', unit='-', axis_type = 'log', std = 0,encoding = None,force_log = False)
params.append(eps_r)

# HTL parameters
N_t_int_l1 = FitParam(name = 'l1.N_t_int', value = 1.23e10, bounds = [1e8,1e13], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$N_{T,int}^{HTL}$', unit='m$^{-2}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(N_t_int_l1)

offset_l2_l1 = FitParam(name = 'offset_l2_l1.E_v', value = 0.04, bounds = [0,0.1], values = None, start_value = None, log_scale = False, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\Delta E_{L2-L1}$', unit='eV', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(offset_l2_l1)

Egap_l1 = FitParam(name = 'Egap_l1.E_c', value = 2.15, bounds = [2.1,2.2], type='fixed', values = None, start_value = None, log_scale = False, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$E_{gap,L1}$', unit='eV', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(Egap_l1)

eps_r_l1 = FitParam(name = 'l1.eps_r', value = 3.5, bounds = [2.5,4], type='range', values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\epsilon_{r}^{HTL}$', unit='-', axis_type = 'log', std = 0,encoding = None,force_log = False)
params.append(eps_r_l1)

Nc_l1 = FitParam(name = 'l1.Nc', value = 5.44e26, bounds = [1e26,1e27], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$N_{c}^{HTL}$', unit='m$^{-3}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(Nc_l1)

mu_HTL = FitParam(name = 'l1.mu_p', value = 5e-10, bounds = [5e-10,1e-7], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\mu_{p}^{HTL}$', unit='m$^2$ V$^{-1}$s$^{-1}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(mu_HTL)

ionsMayEnter_HTL = FitParam(name = 'l1.ionsMayEnter', value = ionsinTLs, bounds = [0,1], type='fixed', values = None, start_value = None, log_scale = False, value_type = 'int', fscale = None, rescale = False, stepsize = None, display_name=r'Ions in HTL', unit='-', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(ionsMayEnter_HTL)

# ETL parameters
N_t_int_l2 = FitParam(name = 'l2.N_t_int', value = 1.27e12, bounds = [1e8,1e13], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$N_{T,int}^{ETL}$', unit='m$^{-2}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(N_t_int_l2)

offset_l2_l3 = FitParam(name = 'offset_l2_l3.E_c', value = -0.054, bounds = [-0.1,0], values = None, start_value = None, log_scale = False, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\Delta E_{L2-L3}$', unit='eV', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(offset_l2_l3)

Egap_l3 = FitParam(name = 'Egap_l3.E_v', value = 2.3, bounds = [2.25,2.35], type='fixed', values = None, start_value = None, log_scale = False, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$E_{gap,L3}$', unit='eV', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(Egap_l3)

eps_r_l3 = FitParam(name = 'l3.eps_r', value = 3.16, bounds = [3,6], type='range', values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\epsilon_{r}^{ETL}$', unit='-', axis_type = 'log', std = 0,encoding = None,force_log = False)
params.append(eps_r_l3)

Nc_l3 = FitParam(name = 'l3.Nc', value = 2.35e26, bounds = [1e26,1e27], type='range', values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$N_{c}^{ETL}$', unit='m$^{-3}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(Nc_l3)

mu_ETL = FitParam(name = 'l3.mu_n', value = 4.06e-7, bounds = [5e-9,1e-6], values = None, start_value = None, log_scale = True, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\mu_{n}^{ETL}$', unit='m$^2$ V$^{-1}$s$^{-1}$', axis_type = 'log', std = 0,encoding = None,force_log = True)
params.append(mu_ETL)

ionsMayEnter_ETL = FitParam(name = 'l3.ionsMayEnter', value = ionsinTLs, bounds = [0,1], type='fixed', values = None, start_value = None, log_scale = False, value_type = 'int', fscale = None, rescale = False, stepsize = None, display_name=r'Ions in ETL', unit='-', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(ionsMayEnter_ETL)

# Contact parameters
R_series = FitParam(name = 'R_series', value = 2.98e-4, bounds = [1e-6,1e-2], log_scale = True, value_type = 'float', fscale = None, rescale = False,  display_name=r'$R_{series}$', unit=r'$\Omega$ m$^2$', axis_type = 'log', force_log = True)
params.append(R_series)

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

offset_W_L = FitParam(name = 'offset_W_L.E_v', value = 0.0, bounds = [0,0.1], type='fixed', values = None, start_value = None, log_scale = False, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\Delta W_L$', unit='eV', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(offset_W_L)

offset_W_R = FitParam(name = 'offset_W_R.E_c', value = -0.0, bounds = [-0.1,0], type='fixed', values = None, start_value = None, log_scale = False, value_type = 'float', fscale = None, rescale = False, stepsize = None, display_name=r'$\Delta W_R$', unit='eV', axis_type = 'linear', std = 0,encoding = None,force_log = False)
params.append(offset_W_R)

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

print('Number of free parameters: ',num_free_params)
Number of free parameters:  20

Run the optimization

In the following, the JVAgent defines two objectives: the QFLS vs light intensity and the JV curves at different light intensities. The QFLS target here is specified as ‘K_QFLSL2’. The means that we are using the QFLS data from layer 2 (the perovskite layer) and we use the formula from the paper from T. Kirchartz’s group (hence the ‘K_’) to calculate the QFLS. The formula is: \begin{equation} QFLS(V) = kTln\left(\frac{\phi(V)}{\phi_{OC}}\right) + qV_{OC} \end{equation} where k is the Boltzmann constant, T is the temperature, q is the elementary charge, \(\phi(V)\) is the photoluminescence emission at voltage V, \(\phi_{OC}\) is the photoluminescence emission at open-circuit voltage and \(V_{OC}\) is the open-circuit voltage.

Note that one can also use QFLSL2 for the QFLS calculated directly from the quasi-Fermi levels in layer 2 (the perovskite layer) instead of using the formula from the paper.

[4]:
# Define the Agent and the target metric/loss function
from optimpv.DDfits.JVAgent import JVAgent
metric = 'nrmse' # can be 'nrmse', 'mse', 'mae'
loss = 'linear' # can be 'linear', 'huber', 'soft_l1'

jv = JVAgent(params, [X,X_QFLS], [y,y_QFLS], session_path, simulation_setup, parallel = True, max_jobs = 4, metric = [metric,metric], loss = [loss,loss], minimize= [True,True], threshold=[0.1,0.3], exp_format=['JV','K_QFLSL2'])
[5]:
# run the simulation with some previously obtained parameters
yfit = jv.run(parameters={},exp_format='JV') # get the JV fit
yfit_QFLS = jv.run(parameters={},X=X_QFLS,exp_format='K_QFLSL2') # get the QFLS fit

viridis = plt.get_cmap('viridis', len(Gfracs))
fig, axes = plt.subplots(1,2, figsize=(16,9))
linewidth = 2
for idx, Gfrac in enumerate(Gfracs[::-1]):
    axes[0].plot(X[X[:,1]==Gfrac,0],y[X[:,1]==Gfrac],label='Gfrac = '+str(Gfrac),color=viridis(idx),alpha=0.5,linewidth=linewidth)
    axes[0].plot(X[X[:,1]==Gfrac,0],yfit[X[:,1]==Gfrac],label='Gfrac = '+str(Gfrac)+' fit',linestyle='--',color=viridis(idx),linewidth=linewidth)
axes[0].set_xlabel('Voltage [V]')
axes[0].set_ylabel('Current density [A m$^{-2}$]')
axes[0].legend()
for idx, Gfrac in enumerate(Gfracs[::-1]):
    axes[1].plot(X_QFLS[X_QFLS[:,1]==Gfrac,0],y_QFLS[X_QFLS[:,1]==Gfrac],label='Gfrac = '+str(Gfrac),color=viridis(idx),alpha=0.5,linewidth=linewidth)
    axes[1].plot(X_QFLS[X_QFLS[:,1]==Gfrac,0],yfit_QFLS[X_QFLS[:,1]==Gfrac],label='Gfrac = '+str(Gfrac)+' fit',linestyle='--',color=viridis(idx),linewidth=linewidth)
axes[1].set_xlabel('Voltage [V]')
axes[1].set_ylabel('QFLS [eV]')
plt.tight_layout()
plt.show()
../_images/examples_QFLS_JV_perovskite_MOO_pymoo_8_0.png
[6]:
# Define the optimizer
from optimpv.pymooOpti.pymooOptimizer import PymooOptimizer
optimizer = PymooOptimizer(params=params, agents=jv, algorithm='NSGA2', pop_size=20, n_gen=300, name='pymoo_multi_obj', verbose_logging=True,max_parallelism=20, )
[7]:
res = optimizer.optimize() # run the optimization
[INFO 12-10 15:13:22] optimpv.pymooOptimizer: Starting optimization using NSGA2 algorithm
[INFO 12-10 15:13:22] optimpv.pymooOptimizer: Population size: 20, Generations: 300
[INFO 12-10 15:13:27] optimpv.pymooOptimizer: Generation 1: Best objective = 0.061527
==========================================================
n_gen  |  n_eval  | n_nds  |      eps      |   indicator
==========================================================
     1 |       20 |      4 |             - |             -
[INFO 12-10 15:13:34] optimpv.pymooOptimizer: Generation 2: Best objective = 0.061527
     2 |       40 |      6 |  0.1273595105 |             f
[INFO 12-10 15:13:38] optimpv.pymooOptimizer: Generation 3: Best objective = 0.035198
     3 |       60 |      8 |  0.2350321685 |         ideal
[INFO 12-10 15:13:42] optimpv.pymooOptimizer: Generation 4: Best objective = 0.032526
     4 |       80 |      9 |  0.0332544768 |         ideal
[INFO 12-10 15:13:46] optimpv.pymooOptimizer: Generation 5: Best objective = 0.018448
     5 |      100 |      3 |  0.4306108466 |         ideal
[INFO 12-10 15:13:49] optimpv.pymooOptimizer: Generation 6: Best objective = 0.018448
     6 |      120 |      2 |  0.2091794459 |         ideal
[INFO 12-10 15:13:54] optimpv.pymooOptimizer: Generation 7: Best objective = 0.018448
     7 |      140 |      3 |  0.2049547217 |             f
[INFO 12-10 15:13:58] optimpv.pymooOptimizer: Generation 8: Best objective = 0.018448
     8 |      160 |      5 |  0.0616744858 |         ideal
[INFO 12-10 15:14:08] optimpv.pymooOptimizer: Generation 9: Best objective = 0.016734
     9 |      180 |      6 |  0.1244693464 |         ideal
[INFO 12-10 15:14:18] optimpv.pymooOptimizer: Generation 10: Best objective = 0.015855
    10 |      200 |      8 |  0.0600082090 |         ideal
[INFO 12-10 15:14:22] optimpv.pymooOptimizer: Generation 11: Best objective = 0.015142
    11 |      220 |     10 |  0.0464441044 |         ideal
[INFO 12-10 15:14:26] optimpv.pymooOptimizer: Generation 12: Best objective = 0.015142
    12 |      240 |      9 |  0.0291949888 |         ideal
[INFO 12-10 15:14:29] optimpv.pymooOptimizer: Generation 13: Best objective = 0.015142
    13 |      260 |      6 |  0.0516673450 |         ideal
[INFO 12-10 15:14:32] optimpv.pymooOptimizer: Generation 14: Best objective = 0.014211
    14 |      280 |     11 |  0.0553446709 |         ideal
[INFO 12-10 15:14:34] optimpv.pymooOptimizer: Generation 15: Best objective = 0.012388
    15 |      300 |     12 |  0.0977773827 |         ideal
[INFO 12-10 15:14:40] optimpv.pymooOptimizer: Generation 16: Best objective = 0.012316
    16 |      320 |     12 |  0.0037989559 |         ideal
[INFO 12-10 15:14:43] optimpv.pymooOptimizer: Generation 17: Best objective = 0.012316
    17 |      340 |     15 |  0.0143546526 |         ideal
[INFO 12-10 15:14:45] optimpv.pymooOptimizer: Generation 18: Best objective = 0.012110
    18 |      360 |      9 |  0.0262953393 |         ideal
[INFO 12-10 15:14:47] optimpv.pymooOptimizer: Generation 19: Best objective = 0.011576
    19 |      380 |     13 |  0.0247507836 |         ideal
[INFO 12-10 15:14:50] optimpv.pymooOptimizer: Generation 20: Best objective = 0.011576
    20 |      400 |     14 |  0.0039824161 |             f
[INFO 12-10 15:14:52] optimpv.pymooOptimizer: Generation 21: Best objective = 0.011208
    21 |      420 |     16 |  0.0168073538 |         ideal
[INFO 12-10 15:14:55] optimpv.pymooOptimizer: Generation 22: Best objective = 0.009400
    22 |      440 |     19 |  0.0761055435 |         ideal
[INFO 12-10 15:14:57] optimpv.pymooOptimizer: Generation 23: Best objective = 0.009252
    23 |      460 |     20 |  0.0061871222 |         ideal
[INFO 12-10 15:14:59] optimpv.pymooOptimizer: Generation 24: Best objective = 0.009239
    24 |      480 |     16 |  0.1115738104 |         nadir
[INFO 12-10 15:15:02] optimpv.pymooOptimizer: Generation 25: Best objective = 0.008719
    25 |      500 |     17 |  0.0212835500 |         ideal
[INFO 12-10 15:15:07] optimpv.pymooOptimizer: Generation 26: Best objective = 0.008719
    26 |      520 |     20 |  0.0052864369 |             f
[INFO 12-10 15:15:09] optimpv.pymooOptimizer: Generation 27: Best objective = 0.008719
    27 |      540 |     10 |  0.0128390790 |         ideal
[INFO 12-10 15:15:12] optimpv.pymooOptimizer: Generation 28: Best objective = 0.006651
    28 |      560 |      9 |  0.1472150271 |         ideal
[INFO 12-10 15:15:14] optimpv.pymooOptimizer: Generation 29: Best objective = 0.006567
    29 |      580 |     10 |  0.0384451941 |         ideal
[INFO 12-10 15:15:17] optimpv.pymooOptimizer: Generation 30: Best objective = 0.006567
    30 |      600 |     15 |  0.0205848083 |             f
[INFO 12-10 15:15:20] optimpv.pymooOptimizer: Generation 31: Best objective = 0.006434
    31 |      620 |     18 |  0.0093948789 |         ideal
[INFO 12-10 15:15:22] optimpv.pymooOptimizer: Generation 32: Best objective = 0.006415
    32 |      640 |     20 |  0.0796221458 |         nadir
[INFO 12-10 15:15:25] optimpv.pymooOptimizer: Generation 33: Best objective = 0.006388
    33 |      660 |     20 |  0.1046710070 |         nadir
[INFO 12-10 15:15:27] optimpv.pymooOptimizer: Generation 34: Best objective = 0.006333
    34 |      680 |     20 |  0.0104413644 |         ideal
[INFO 12-10 15:15:29] optimpv.pymooOptimizer: Generation 35: Best objective = 0.006042
    35 |      700 |     19 |  0.0194761934 |         ideal
[INFO 12-10 15:15:32] optimpv.pymooOptimizer: Generation 36: Best objective = 0.006042
    36 |      720 |     17 |  0.0763926435 |         nadir
[INFO 12-10 15:15:35] optimpv.pymooOptimizer: Generation 37: Best objective = 0.006042
    37 |      740 |     19 |  0.0094419266 |         ideal
[INFO 12-10 15:15:37] optimpv.pymooOptimizer: Generation 38: Best objective = 0.006042
    38 |      760 |     19 |  0.0034609397 |         ideal
[INFO 12-10 15:15:40] optimpv.pymooOptimizer: Generation 39: Best objective = 0.006042
    39 |      780 |     20 |  0.0069627607 |             f
[INFO 12-10 15:15:42] optimpv.pymooOptimizer: Generation 40: Best objective = 0.006042
    40 |      800 |     20 |  0.0048949210 |         nadir
[INFO 12-10 15:15:45] optimpv.pymooOptimizer: Generation 41: Best objective = 0.006042
    41 |      820 |     20 |  0.0050216976 |         ideal
[INFO 12-10 15:15:47] optimpv.pymooOptimizer: Generation 42: Best objective = 0.006042
    42 |      840 |     20 |  0.0699903910 |         ideal
[INFO 12-10 15:15:50] optimpv.pymooOptimizer: Generation 43: Best objective = 0.006042
    43 |      860 |     19 |  0.0030240677 |             f
[INFO 12-10 15:15:52] optimpv.pymooOptimizer: Generation 44: Best objective = 0.006042
    44 |      880 |     19 |  0.0153845062 |             f
[INFO 12-10 15:15:54] optimpv.pymooOptimizer: Generation 45: Best objective = 0.005869
    45 |      900 |     20 |  0.0115519923 |         ideal
[INFO 12-10 15:15:57] optimpv.pymooOptimizer: Generation 46: Best objective = 0.005869
    46 |      920 |     20 |  0.0000645626 |             f
[INFO 12-10 15:15:59] optimpv.pymooOptimizer: Generation 47: Best objective = 0.005869
    47 |      940 |     20 |  0.0078552284 |             f
[INFO 12-10 15:16:01] optimpv.pymooOptimizer: Generation 48: Best objective = 0.005657
    48 |      960 |     20 |  0.0139504895 |         ideal
[INFO 12-10 15:16:04] optimpv.pymooOptimizer: Generation 49: Best objective = 0.005657
    49 |      980 |     20 |  0.0024059921 |             f
[INFO 12-10 15:16:06] optimpv.pymooOptimizer: Generation 50: Best objective = 0.005571
    50 |     1000 |     20 |  0.0056362456 |         ideal
[INFO 12-10 15:16:08] optimpv.pymooOptimizer: Generation 51: Best objective = 0.005571
    51 |     1020 |     20 |  0.0026480303 |             f
[INFO 12-10 15:16:11] optimpv.pymooOptimizer: Generation 52: Best objective = 0.005571
    52 |     1040 |     20 |  0.0033575850 |             f
[INFO 12-10 15:16:13] optimpv.pymooOptimizer: Generation 53: Best objective = 0.005557
    53 |     1060 |     20 |  0.0447252354 |         nadir
[INFO 12-10 15:16:18] optimpv.pymooOptimizer: Generation 54: Best objective = 0.005557
    54 |     1080 |     20 |  0.0100959024 |         ideal
[INFO 12-10 15:16:20] optimpv.pymooOptimizer: Generation 55: Best objective = 0.005557
    55 |     1100 |     20 |  0.000000E+00 |             f
[INFO 12-10 15:16:23] optimpv.pymooOptimizer: Generation 56: Best objective = 0.005557
    56 |     1120 |     20 |  0.0038240688 |         ideal
[INFO 12-10 15:16:25] optimpv.pymooOptimizer: Generation 57: Best objective = 0.005557
    57 |     1140 |     20 |  0.0058416021 |             f
[INFO 12-10 15:16:27] optimpv.pymooOptimizer: Generation 58: Best objective = 0.005557
    58 |     1160 |     20 |  0.0021221492 |             f
[INFO 12-10 15:16:30] optimpv.pymooOptimizer: Generation 59: Best objective = 0.005557
    59 |     1180 |     20 |  0.0336483673 |         ideal
[INFO 12-10 15:16:32] optimpv.pymooOptimizer: Generation 60: Best objective = 0.005557
    60 |     1200 |     20 |  0.0001132742 |             f
[INFO 12-10 15:16:37] optimpv.pymooOptimizer: Generation 61: Best objective = 0.005557
    61 |     1220 |     20 |  0.0060678568 |             f
[INFO 12-10 15:16:40] optimpv.pymooOptimizer: Generation 62: Best objective = 0.005557
    62 |     1240 |     20 |  0.0020843151 |             f
[INFO 12-10 15:16:42] optimpv.pymooOptimizer: Generation 63: Best objective = 0.005557
    63 |     1260 |     20 |  0.0041930822 |         ideal
[INFO 12-10 15:16:44] optimpv.pymooOptimizer: Generation 64: Best objective = 0.005523
    64 |     1280 |     20 |  0.0131154098 |         nadir
[INFO 12-10 15:16:47] optimpv.pymooOptimizer: Generation 65: Best objective = 0.005477
    65 |     1300 |     20 |  0.0027055938 |         ideal
[INFO 12-10 15:16:49] optimpv.pymooOptimizer: Generation 66: Best objective = 0.005477
    66 |     1320 |     20 |  0.0049675107 |             f
[INFO 12-10 15:16:51] optimpv.pymooOptimizer: Generation 67: Best objective = 0.005477
    67 |     1340 |     20 |  0.0043867142 |         ideal
[INFO 12-10 15:16:54] optimpv.pymooOptimizer: Generation 68: Best objective = 0.005477
    68 |     1360 |     20 |  0.0003359157 |             f
[INFO 12-10 15:16:56] optimpv.pymooOptimizer: Generation 69: Best objective = 0.005477
    69 |     1380 |     20 |  0.0022244821 |             f
[INFO 12-10 15:16:58] optimpv.pymooOptimizer: Generation 70: Best objective = 0.005454
    70 |     1400 |     20 |  0.0530085038 |         nadir
[INFO 12-10 15:17:00] optimpv.pymooOptimizer: Generation 71: Best objective = 0.005454
    71 |     1420 |     20 |  0.0021283673 |             f
[INFO 12-10 15:17:03] optimpv.pymooOptimizer: Generation 72: Best objective = 0.005397
    72 |     1440 |     19 |  0.0033679921 |         ideal
[INFO 12-10 15:17:05] optimpv.pymooOptimizer: Generation 73: Best objective = 0.005397
    73 |     1460 |     20 |  0.0020315739 |             f
[INFO 12-10 15:17:08] optimpv.pymooOptimizer: Generation 74: Best objective = 0.005397
    74 |     1480 |     20 |  0.0076285662 |             f
[INFO 12-10 15:17:10] optimpv.pymooOptimizer: Generation 75: Best objective = 0.005397
    75 |     1500 |     20 |  0.0061337778 |         ideal
[INFO 12-10 15:17:12] optimpv.pymooOptimizer: Generation 76: Best objective = 0.005397
    76 |     1520 |     20 |  0.0040506981 |             f
[INFO 12-10 15:17:14] optimpv.pymooOptimizer: Generation 77: Best objective = 0.005320
    77 |     1540 |     20 |  0.0044429808 |         ideal
[INFO 12-10 15:17:17] optimpv.pymooOptimizer: Generation 78: Best objective = 0.005320
    78 |     1560 |     20 |  0.0039903942 |             f
[INFO 12-10 15:17:19] optimpv.pymooOptimizer: Generation 79: Best objective = 0.005320
    79 |     1580 |     20 |  0.0033919759 |             f
[INFO 12-10 15:17:25] optimpv.pymooOptimizer: Generation 80: Best objective = 0.005320
    80 |     1600 |     20 |  0.0111577503 |             f
[INFO 12-10 15:17:27] optimpv.pymooOptimizer: Generation 81: Best objective = 0.005320
    81 |     1620 |     20 |  0.0063653283 |             f
[INFO 12-10 15:17:29] optimpv.pymooOptimizer: Generation 82: Best objective = 0.005320
    82 |     1640 |     20 |  0.0050045629 |             f
[INFO 12-10 15:17:32] optimpv.pymooOptimizer: Generation 83: Best objective = 0.005320
    83 |     1660 |     20 |  0.0081958079 |             f
[INFO 12-10 15:17:34] optimpv.pymooOptimizer: Generation 84: Best objective = 0.005320
    84 |     1680 |     20 |  0.0002305835 |             f
[INFO 12-10 15:17:36] optimpv.pymooOptimizer: Generation 85: Best objective = 0.005311
    85 |     1700 |     20 |  0.0015825790 |             f
[INFO 12-10 15:17:39] optimpv.pymooOptimizer: Generation 86: Best objective = 0.005311
    86 |     1720 |     20 |  0.0050147924 |             f
[INFO 12-10 15:17:41] optimpv.pymooOptimizer: Generation 87: Best objective = 0.005311
    87 |     1740 |     20 |  0.0009309333 |             f
[INFO 12-10 15:17:43] optimpv.pymooOptimizer: Generation 88: Best objective = 0.005311
    88 |     1760 |     20 |  0.0008610503 |             f
[INFO 12-10 15:17:46] optimpv.pymooOptimizer: Generation 89: Best objective = 0.005311
    89 |     1780 |     20 |  0.0025946220 |             f
[INFO 12-10 15:17:48] optimpv.pymooOptimizer: Generation 90: Best objective = 0.005311
    90 |     1800 |     20 |  0.0032047523 |             f
[INFO 12-10 15:17:51] optimpv.pymooOptimizer: Generation 91: Best objective = 0.005311
    91 |     1820 |     20 |  0.0027131224 |             f
[INFO 12-10 15:17:53] optimpv.pymooOptimizer: Generation 92: Best objective = 0.005311
    92 |     1840 |     20 |  0.0135615897 |         nadir
[INFO 12-10 15:17:55] optimpv.pymooOptimizer: Generation 93: Best objective = 0.005311
    93 |     1860 |     20 |  0.0014386801 |             f
[INFO 12-10 15:17:57] optimpv.pymooOptimizer: Generation 94: Best objective = 0.005311
    94 |     1880 |     20 |  0.0084021276 |             f
[INFO 12-10 15:18:11] optimpv.pymooOptimizer: Generation 95: Best objective = 0.005311
    95 |     1900 |     20 |  0.0028547415 |             f
[INFO 12-10 15:18:13] optimpv.pymooOptimizer: Generation 96: Best objective = 0.005311
    96 |     1920 |     20 |  0.0063426420 |             f
[INFO 12-10 15:18:16] optimpv.pymooOptimizer: Generation 97: Best objective = 0.005311
    97 |     1940 |     20 |  0.0008226224 |             f
[INFO 12-10 15:18:18] optimpv.pymooOptimizer: Generation 98: Best objective = 0.005311
    98 |     1960 |     20 |  0.0014833234 |             f
[INFO 12-10 15:18:20] optimpv.pymooOptimizer: Generation 99: Best objective = 0.005311
    99 |     1980 |     20 |  0.0059813228 |             f
[INFO 12-10 15:18:23] optimpv.pymooOptimizer: Generation 100: Best objective = 0.005311
   100 |     2000 |     20 |  0.0017269875 |             f
[INFO 12-10 15:18:25] optimpv.pymooOptimizer: Generation 101: Best objective = 0.005311
   101 |     2020 |     20 |  0.0606034638 |         nadir
[INFO 12-10 15:18:39] optimpv.pymooOptimizer: Generation 102: Best objective = 0.005311
   102 |     2040 |     20 |  0.0034069028 |             f
[INFO 12-10 15:18:46] optimpv.pymooOptimizer: Generation 103: Best objective = 0.005311
   103 |     2060 |     20 |  0.0041966431 |             f
[INFO 12-10 15:18:48] optimpv.pymooOptimizer: Generation 104: Best objective = 0.005311
   104 |     2080 |     20 |  0.0040216667 |             f
[INFO 12-10 15:18:51] optimpv.pymooOptimizer: Generation 105: Best objective = 0.005311
   105 |     2100 |     20 |  0.0086705689 |             f
[INFO 12-10 15:18:53] optimpv.pymooOptimizer: Generation 106: Best objective = 0.005311
   106 |     2120 |     20 |  0.0008971291 |             f
[INFO 12-10 15:18:55] optimpv.pymooOptimizer: Generation 107: Best objective = 0.005264
   107 |     2140 |     20 |  0.0027898519 |         ideal
[INFO 12-10 15:18:58] optimpv.pymooOptimizer: Generation 108: Best objective = 0.005264
   108 |     2160 |     20 |  0.0030565366 |             f
[INFO 12-10 15:19:00] optimpv.pymooOptimizer: Generation 109: Best objective = 0.005264
   109 |     2180 |     20 |  0.0032939468 |             f
[INFO 12-10 15:19:02] optimpv.pymooOptimizer: Generation 110: Best objective = 0.005030
   110 |     2200 |     20 |  0.0139112867 |         ideal
[INFO 12-10 15:19:05] optimpv.pymooOptimizer: Generation 111: Best objective = 0.005030
   111 |     2220 |     20 |  0.0086986755 |             f
[INFO 12-10 15:19:07] optimpv.pymooOptimizer: Generation 112: Best objective = 0.005029
   112 |     2240 |     20 |  0.0037227417 |             f
[INFO 12-10 15:19:09] optimpv.pymooOptimizer: Generation 113: Best objective = 0.005029
   113 |     2260 |     20 |  0.0012861491 |             f
[INFO 12-10 15:19:11] optimpv.pymooOptimizer: Generation 114: Best objective = 0.005021
   114 |     2280 |     19 |  0.2123867209 |         nadir
[INFO 12-10 15:19:14] optimpv.pymooOptimizer: Generation 115: Best objective = 0.005021
   115 |     2300 |     20 |  0.0079763986 |             f
[INFO 12-10 15:19:16] optimpv.pymooOptimizer: Generation 116: Best objective = 0.004988
   116 |     2320 |     18 |  0.0568415012 |         nadir
[INFO 12-10 15:19:19] optimpv.pymooOptimizer: Generation 117: Best objective = 0.004988
   117 |     2340 |     20 |  0.0016899363 |             f
[INFO 12-10 15:19:21] optimpv.pymooOptimizer: Generation 118: Best objective = 0.004983
   118 |     2360 |     20 |  0.0048059985 |         nadir
[INFO 12-10 15:19:24] optimpv.pymooOptimizer: Generation 119: Best objective = 0.004983
   119 |     2380 |     20 |  0.0006689204 |             f
[INFO 12-10 15:19:27] optimpv.pymooOptimizer: Generation 120: Best objective = 0.004983
   120 |     2400 |     20 |  0.0025743803 |             f
[INFO 12-10 15:19:29] optimpv.pymooOptimizer: Generation 121: Best objective = 0.004983
   121 |     2420 |     20 |  0.0032443280 |             f
[INFO 12-10 15:19:31] optimpv.pymooOptimizer: Generation 122: Best objective = 0.004982
   122 |     2440 |     20 |  0.0043808270 |         nadir
[INFO 12-10 15:19:39] optimpv.pymooOptimizer: Generation 123: Best objective = 0.004982
   123 |     2460 |     20 |  0.0020901316 |             f
[INFO 12-10 15:19:42] optimpv.pymooOptimizer: Generation 124: Best objective = 0.004982
   124 |     2480 |     20 |  0.0045996068 |             f
[INFO 12-10 15:19:44] optimpv.pymooOptimizer: Generation 125: Best objective = 0.004982
   125 |     2500 |     20 |  0.0843555605 |         nadir
[INFO 12-10 15:19:46] optimpv.pymooOptimizer: Generation 126: Best objective = 0.004982
   126 |     2520 |     20 |  0.0047614035 |             f
[INFO 12-10 15:19:49] optimpv.pymooOptimizer: Generation 127: Best objective = 0.004982
   127 |     2540 |     20 |  0.0028611625 |             f
[INFO 12-10 15:19:51] optimpv.pymooOptimizer: Generation 128: Best objective = 0.004982
   128 |     2560 |     20 |  0.0024932797 |             f
[INFO 12-10 15:19:54] optimpv.pymooOptimizer: Generation 129: Best objective = 0.004982
   129 |     2580 |     20 |  0.0024932797 |             f
[INFO 12-10 15:19:56] optimpv.pymooOptimizer: Generation 130: Best objective = 0.004982
   130 |     2600 |     20 |  0.0030200854 |             f
[INFO 12-10 15:19:58] optimpv.pymooOptimizer: Generation 131: Best objective = 0.004982
   131 |     2620 |     20 |  0.0021039369 |             f
[INFO 12-10 15:20:01] optimpv.pymooOptimizer: Generation 132: Best objective = 0.004982
   132 |     2640 |     20 |  0.0049948735 |             f
[INFO 12-10 15:20:03] optimpv.pymooOptimizer: Generation 133: Best objective = 0.004982
   133 |     2660 |     20 |  0.0001845828 |             f
[INFO 12-10 15:20:06] optimpv.pymooOptimizer: Generation 134: Best objective = 0.004982
   134 |     2680 |     20 |  0.0049843131 |             f
[INFO 12-10 15:20:08] optimpv.pymooOptimizer: Generation 135: Best objective = 0.004978
   135 |     2700 |     20 |  0.0232738966 |         nadir
[INFO 12-10 15:20:10] optimpv.pymooOptimizer: Generation 136: Best objective = 0.004978
   136 |     2720 |     20 |  0.000000E+00 |             f
[INFO 12-10 15:20:13] optimpv.pymooOptimizer: Generation 137: Best objective = 0.004978
   137 |     2740 |     20 |  0.0149134239 |         ideal
[INFO 12-10 15:20:27] optimpv.pymooOptimizer: Generation 138: Best objective = 0.004976
   138 |     2760 |     20 |  0.0103238480 |         ideal
[INFO 12-10 15:20:29] optimpv.pymooOptimizer: Generation 139: Best objective = 0.004906
   139 |     2780 |     20 |  0.0041833832 |         ideal
[INFO 12-10 15:20:32] optimpv.pymooOptimizer: Generation 140: Best objective = 0.004906
   140 |     2800 |     20 |  0.0238691484 |         nadir
[INFO 12-10 15:20:34] optimpv.pymooOptimizer: Generation 141: Best objective = 0.004906
   141 |     2820 |     20 |  0.0008653748 |             f
[INFO 12-10 15:20:36] optimpv.pymooOptimizer: Generation 142: Best objective = 0.004906
   142 |     2840 |     20 |  0.0044397445 |             f
[INFO 12-10 15:20:38] optimpv.pymooOptimizer: Generation 143: Best objective = 0.004870
   143 |     2860 |     20 |  0.0352165275 |         nadir
[INFO 12-10 15:20:42] optimpv.pymooOptimizer: Generation 144: Best objective = 0.004870
   144 |     2880 |     20 |  0.0022077673 |             f
[INFO 12-10 15:20:44] optimpv.pymooOptimizer: Generation 145: Best objective = 0.004870
   145 |     2900 |     20 |  0.0052413638 |             f
[INFO 12-10 15:20:49] optimpv.pymooOptimizer: Generation 146: Best objective = 0.004870
   146 |     2920 |     20 |  0.0022513829 |             f
[INFO 12-10 15:20:51] optimpv.pymooOptimizer: Generation 147: Best objective = 0.004870
   147 |     2940 |     20 |  0.0033170676 |             f
[INFO 12-10 15:20:53] optimpv.pymooOptimizer: Generation 148: Best objective = 0.004758
   148 |     2960 |     20 |  0.0064947482 |         ideal
[INFO 12-10 15:20:55] optimpv.pymooOptimizer: Generation 149: Best objective = 0.004758
   149 |     2980 |     20 |  0.0003752557 |             f
[INFO 12-10 15:20:58] optimpv.pymooOptimizer: Generation 150: Best objective = 0.004758
   150 |     3000 |     20 |  0.0055154274 |             f
[INFO 12-10 15:21:00] optimpv.pymooOptimizer: Generation 151: Best objective = 0.004758
   151 |     3020 |     20 |  0.0038522921 |             f
[INFO 12-10 15:21:02] optimpv.pymooOptimizer: Generation 152: Best objective = 0.004758
   152 |     3040 |     20 |  0.0015671839 |             f
[INFO 12-10 15:21:05] optimpv.pymooOptimizer: Generation 153: Best objective = 0.004758
   153 |     3060 |     20 |  0.0043430572 |             f
[INFO 12-10 15:21:07] optimpv.pymooOptimizer: Generation 154: Best objective = 0.004758
   154 |     3080 |     20 |  0.0027533560 |             f
[INFO 12-10 15:21:09] optimpv.pymooOptimizer: Generation 155: Best objective = 0.004758
   155 |     3100 |     20 |  0.0053719283 |             f
[INFO 12-10 15:21:12] optimpv.pymooOptimizer: Generation 156: Best objective = 0.004758
   156 |     3120 |     20 |  0.0054483337 |             f
[INFO 12-10 15:21:14] optimpv.pymooOptimizer: Generation 157: Best objective = 0.004758
   157 |     3140 |     20 |  0.0016516725 |             f
[INFO 12-10 15:21:16] optimpv.pymooOptimizer: Generation 158: Best objective = 0.004758
   158 |     3160 |     20 |  0.0026247259 |             f
[INFO 12-10 15:21:19] optimpv.pymooOptimizer: Generation 159: Best objective = 0.004758
   159 |     3180 |     20 |  0.0054369939 |             f
[INFO 12-10 15:21:21] optimpv.pymooOptimizer: Generation 160: Best objective = 0.004758
   160 |     3200 |     20 |  0.0014814972 |             f
[INFO 12-10 15:21:23] optimpv.pymooOptimizer: Generation 161: Best objective = 0.004758
   161 |     3220 |     20 |  0.0068749486 |             f
[INFO 12-10 15:21:25] optimpv.pymooOptimizer: Generation 162: Best objective = 0.004758
   162 |     3240 |     20 |  0.0046361747 |             f
[INFO 12-10 15:21:28] optimpv.pymooOptimizer: Generation 163: Best objective = 0.004758
   163 |     3260 |     20 |  0.0053016411 |             f
[INFO 12-10 15:21:30] optimpv.pymooOptimizer: Generation 164: Best objective = 0.004758
   164 |     3280 |     20 |  0.0061878065 |             f
[INFO 12-10 15:21:33] optimpv.pymooOptimizer: Generation 165: Best objective = 0.004758
   165 |     3300 |     20 |  0.0041181892 |             f
[INFO 12-10 15:21:35] optimpv.pymooOptimizer: Generation 166: Best objective = 0.004758
   166 |     3320 |     20 |  0.000000E+00 |             f
[INFO 12-10 15:21:37] optimpv.pymooOptimizer: Generation 167: Best objective = 0.004747
   167 |     3340 |     20 |  0.0235813972 |         nadir
[INFO 12-10 15:21:40] optimpv.pymooOptimizer: Generation 168: Best objective = 0.004747
   168 |     3360 |     20 |  0.0022181500 |             f
[INFO 12-10 15:21:42] optimpv.pymooOptimizer: Generation 169: Best objective = 0.004747
   169 |     3380 |     20 |  0.0039967414 |         ideal
[INFO 12-10 15:21:44] optimpv.pymooOptimizer: Generation 170: Best objective = 0.004747
   170 |     3400 |     20 |  0.0042242491 |             f
[INFO 12-10 15:21:46] optimpv.pymooOptimizer: Generation 171: Best objective = 0.004720
   171 |     3420 |     20 |  0.2815585066 |         nadir
[INFO 12-10 15:21:49] optimpv.pymooOptimizer: Generation 172: Best objective = 0.004720
   172 |     3440 |     20 |  0.0067616069 |             f
[INFO 12-10 15:21:51] optimpv.pymooOptimizer: Generation 173: Best objective = 0.004720
   173 |     3460 |     20 |  0.0059718181 |             f
[INFO 12-10 15:21:53] optimpv.pymooOptimizer: Generation 174: Best objective = 0.004720
   174 |     3480 |     20 |  0.0152903681 |         ideal
[INFO 12-10 15:21:56] optimpv.pymooOptimizer: Generation 175: Best objective = 0.004720
   175 |     3500 |     20 |  0.0128491193 |             f
[INFO 12-10 15:21:58] optimpv.pymooOptimizer: Generation 176: Best objective = 0.004720
   176 |     3520 |     20 |  0.0138084432 |         nadir
[INFO 12-10 15:22:00] optimpv.pymooOptimizer: Generation 177: Best objective = 0.004720
   177 |     3540 |     20 |  0.0031870990 |             f
[INFO 12-10 15:22:03] optimpv.pymooOptimizer: Generation 178: Best objective = 0.004720
   178 |     3560 |     20 |  0.0064912092 |             f
[INFO 12-10 15:22:05] optimpv.pymooOptimizer: Generation 179: Best objective = 0.004720
   179 |     3580 |     20 |  0.0050141614 |             f
[INFO 12-10 15:22:07] optimpv.pymooOptimizer: Generation 180: Best objective = 0.004720
   180 |     3600 |     20 |  0.0077635020 |             f
[INFO 12-10 15:22:10] optimpv.pymooOptimizer: Generation 181: Best objective = 0.004707
   181 |     3620 |     20 |  0.0588785997 |         nadir
[INFO 12-10 15:22:12] optimpv.pymooOptimizer: Generation 182: Best objective = 0.004707
   182 |     3640 |     20 |  0.0050857311 |             f
[INFO 12-10 15:22:15] optimpv.pymooOptimizer: Generation 183: Best objective = 0.004707
   183 |     3660 |     20 |  0.0034475454 |             f
[INFO 12-10 15:22:17] optimpv.pymooOptimizer: Generation 184: Best objective = 0.004707
   184 |     3680 |     20 |  0.0033316063 |             f
[INFO 12-10 15:22:20] optimpv.pymooOptimizer: Generation 185: Best objective = 0.004707
   185 |     3700 |     20 |  0.0023419062 |             f
[INFO 12-10 15:22:22] optimpv.pymooOptimizer: Generation 186: Best objective = 0.004707
   186 |     3720 |     20 |  0.0313120209 |         ideal
[INFO 12-10 15:22:25] optimpv.pymooOptimizer: Generation 187: Best objective = 0.004707
   187 |     3740 |     20 |  0.0024152177 |             f
[INFO 12-10 15:22:27] optimpv.pymooOptimizer: Generation 188: Best objective = 0.004707
   188 |     3760 |     20 |  0.0057437752 |             f
[INFO 12-10 15:22:30] optimpv.pymooOptimizer: Generation 189: Best objective = 0.004707
   189 |     3780 |     20 |  0.0023376144 |             f
[INFO 12-10 15:22:32] optimpv.pymooOptimizer: Generation 190: Best objective = 0.004707
   190 |     3800 |     20 |  0.0053462444 |             f
[INFO 12-10 15:22:35] optimpv.pymooOptimizer: Generation 191: Best objective = 0.004704
   191 |     3820 |     20 |  0.0067809241 |         ideal
[INFO 12-10 15:22:37] optimpv.pymooOptimizer: Generation 192: Best objective = 0.004704
   192 |     3840 |     20 |  0.0016834574 |             f
[INFO 12-10 15:22:40] optimpv.pymooOptimizer: Generation 193: Best objective = 0.004704
   193 |     3860 |     20 |  0.0034616219 |             f
[INFO 12-10 15:22:42] optimpv.pymooOptimizer: Generation 194: Best objective = 0.004704
   194 |     3880 |     20 |  0.0035274375 |             f
[INFO 12-10 15:22:45] optimpv.pymooOptimizer: Generation 195: Best objective = 0.004704
   195 |     3900 |     20 |  0.0058773863 |             f
[INFO 12-10 15:22:48] optimpv.pymooOptimizer: Generation 196: Best objective = 0.004704
   196 |     3920 |     20 |  0.0013997133 |             f
[INFO 12-10 15:22:51] optimpv.pymooOptimizer: Generation 197: Best objective = 0.004704
   197 |     3940 |     20 |  0.0014278841 |             f
[INFO 12-10 15:22:53] optimpv.pymooOptimizer: Generation 198: Best objective = 0.004704
   198 |     3960 |     20 |  0.0020576322 |             f
[INFO 12-10 15:22:56] optimpv.pymooOptimizer: Generation 199: Best objective = 0.004704
   199 |     3980 |     20 |  0.0052415324 |             f
[INFO 12-10 15:22:58] optimpv.pymooOptimizer: Generation 200: Best objective = 0.004704
   200 |     4000 |     20 |  0.0009839253 |             f
[INFO 12-10 15:23:01] optimpv.pymooOptimizer: Generation 201: Best objective = 0.004704
   201 |     4020 |     20 |  0.0044620509 |             f
[INFO 12-10 15:23:03] optimpv.pymooOptimizer: Generation 202: Best objective = 0.004703
   202 |     4040 |     20 |  0.0077349824 |             f
[INFO 12-10 15:23:06] optimpv.pymooOptimizer: Generation 203: Best objective = 0.004700
   203 |     4060 |     20 |  0.2913080588 |         nadir
[INFO 12-10 15:23:08] optimpv.pymooOptimizer: Generation 204: Best objective = 0.004700
   204 |     4080 |     20 |  0.0037303409 |             f
[INFO 12-10 15:23:11] optimpv.pymooOptimizer: Generation 205: Best objective = 0.004700
   205 |     4100 |     20 |  0.0010354355 |             f
[INFO 12-10 15:23:13] optimpv.pymooOptimizer: Generation 206: Best objective = 0.004700
   206 |     4120 |     20 |  0.0074655336 |             f
[INFO 12-10 15:23:16] optimpv.pymooOptimizer: Generation 207: Best objective = 0.004700
   207 |     4140 |     20 |  0.0022493880 |             f
[INFO 12-10 15:23:18] optimpv.pymooOptimizer: Generation 208: Best objective = 0.004700
   208 |     4160 |     20 |  0.0028530530 |             f
[INFO 12-10 15:23:21] optimpv.pymooOptimizer: Generation 209: Best objective = 0.004700
   209 |     4180 |     20 |  0.000000E+00 |             f
[INFO 12-10 15:23:23] optimpv.pymooOptimizer: Generation 210: Best objective = 0.004700
   210 |     4200 |     20 |  0.0360000112 |         nadir
[INFO 12-10 15:23:26] optimpv.pymooOptimizer: Generation 211: Best objective = 0.004700
   211 |     4220 |     20 |  0.0016302410 |             f
[INFO 12-10 15:23:29] optimpv.pymooOptimizer: Generation 212: Best objective = 0.004700
   212 |     4240 |     20 |  0.0032421985 |             f
[INFO 12-10 15:23:31] optimpv.pymooOptimizer: Generation 213: Best objective = 0.004699
   213 |     4260 |     20 |  0.0108997183 |         nadir
[INFO 12-10 15:23:34] optimpv.pymooOptimizer: Generation 214: Best objective = 0.004699
   214 |     4280 |     20 |  0.0053707493 |             f
[INFO 12-10 15:23:36] optimpv.pymooOptimizer: Generation 215: Best objective = 0.004699
   215 |     4300 |     20 |  0.0029185048 |             f
[INFO 12-10 15:23:39] optimpv.pymooOptimizer: Generation 216: Best objective = 0.004699
   216 |     4320 |     20 |  0.0025592527 |             f
[INFO 12-10 15:23:42] optimpv.pymooOptimizer: Generation 217: Best objective = 0.004699
   217 |     4340 |     20 |  0.0235572284 |         nadir
[INFO 12-10 15:23:44] optimpv.pymooOptimizer: Generation 218: Best objective = 0.004699
   218 |     4360 |     20 |  0.0015888488 |             f
[INFO 12-10 15:23:47] optimpv.pymooOptimizer: Generation 219: Best objective = 0.004699
   219 |     4380 |     20 |  0.0031110611 |             f
[INFO 12-10 15:23:49] optimpv.pymooOptimizer: Generation 220: Best objective = 0.004699
   220 |     4400 |     20 |  0.0030939749 |             f
[INFO 12-10 15:23:52] optimpv.pymooOptimizer: Generation 221: Best objective = 0.004699
   221 |     4420 |     20 |  0.0032923119 |             f
[INFO 12-10 15:23:55] optimpv.pymooOptimizer: Generation 222: Best objective = 0.004699
   222 |     4440 |     20 |  0.0057441335 |             f
[INFO 12-10 15:23:57] optimpv.pymooOptimizer: Generation 223: Best objective = 0.004699
   223 |     4460 |     20 |  0.0003780160 |             f
[INFO 12-10 15:24:00] optimpv.pymooOptimizer: Generation 224: Best objective = 0.004699
   224 |     4480 |     20 |  0.0059055221 |             f
[INFO 12-10 15:24:02] optimpv.pymooOptimizer: Generation 225: Best objective = 0.004699
   225 |     4500 |     20 |  0.0042822348 |             f
[INFO 12-10 15:24:05] optimpv.pymooOptimizer: Generation 226: Best objective = 0.004699
   226 |     4520 |     20 |  0.0032294834 |             f
[INFO 12-10 15:24:08] optimpv.pymooOptimizer: Generation 227: Best objective = 0.004699
   227 |     4540 |     20 |  0.0032176645 |             f
[INFO 12-10 15:24:10] optimpv.pymooOptimizer: Generation 228: Best objective = 0.004699
   228 |     4560 |     20 |  0.0020327846 |             f
[INFO 12-10 15:24:15] optimpv.pymooOptimizer: Generation 229: Best objective = 0.004699
   229 |     4580 |     20 |  0.0039544122 |             f
[INFO 12-10 15:24:18] optimpv.pymooOptimizer: Generation 230: Best objective = 0.004699
   230 |     4600 |     20 |  0.0003659405 |             f
[INFO 12-10 15:24:20] optimpv.pymooOptimizer: Generation 231: Best objective = 0.004699
   231 |     4620 |     20 |  0.0036995952 |             f
[INFO 12-10 15:24:23] optimpv.pymooOptimizer: Generation 232: Best objective = 0.004698
   232 |     4640 |     20 |  0.1808647347 |         nadir
[INFO 12-10 15:24:26] optimpv.pymooOptimizer: Generation 233: Best objective = 0.004698
   233 |     4660 |     20 |  0.0003253962 |             f
[INFO 12-10 15:24:28] optimpv.pymooOptimizer: Generation 234: Best objective = 0.004698
   234 |     4680 |     20 |  0.0046576689 |             f
[INFO 12-10 15:24:31] optimpv.pymooOptimizer: Generation 235: Best objective = 0.004698
   235 |     4700 |     20 |  0.0012981022 |             f
[INFO 12-10 15:24:33] optimpv.pymooOptimizer: Generation 236: Best objective = 0.004687
   236 |     4720 |     20 |  0.0093762635 |         nadir
[INFO 12-10 15:24:35] optimpv.pymooOptimizer: Generation 237: Best objective = 0.004687
   237 |     4740 |     20 |  0.0055607268 |             f
[INFO 12-10 15:24:38] optimpv.pymooOptimizer: Generation 238: Best objective = 0.004687
   238 |     4760 |     20 |  0.0029983649 |             f
[INFO 12-10 15:24:40] optimpv.pymooOptimizer: Generation 239: Best objective = 0.004687
   239 |     4780 |     20 |  0.0025136774 |             f
[INFO 12-10 15:24:42] optimpv.pymooOptimizer: Generation 240: Best objective = 0.004687
   240 |     4800 |     20 |  0.0021662737 |             f
[INFO 12-10 15:24:44] optimpv.pymooOptimizer: Generation 241: Best objective = 0.004687
   241 |     4820 |     20 |  0.0049218394 |             f
[INFO 12-10 15:24:47] optimpv.pymooOptimizer: Generation 242: Best objective = 0.004687
   242 |     4840 |     20 |  0.0013683407 |             f
[INFO 12-10 15:24:49] optimpv.pymooOptimizer: Generation 243: Best objective = 0.004687
   243 |     4860 |     20 |  0.0043969810 |             f
[INFO 12-10 15:24:52] optimpv.pymooOptimizer: Generation 244: Best objective = 0.004687
   244 |     4880 |     20 |  0.0037973727 |         ideal
[INFO 12-10 15:24:55] optimpv.pymooOptimizer: Generation 245: Best objective = 0.004687
   245 |     4900 |     20 |  0.0025528338 |             f
[INFO 12-10 15:24:57] optimpv.pymooOptimizer: Generation 246: Best objective = 0.004687
   246 |     4920 |     20 |  0.0003184244 |             f
[INFO 12-10 15:24:59] optimpv.pymooOptimizer: Generation 247: Best objective = 0.004685
   247 |     4940 |     20 |  0.0069135880 |         nadir
[INFO 12-10 15:25:02] optimpv.pymooOptimizer: Generation 248: Best objective = 0.004682
   248 |     4960 |     20 |  0.0072507266 |         nadir
[INFO 12-10 15:25:10] optimpv.pymooOptimizer: Generation 249: Best objective = 0.004682
   249 |     4980 |     20 |  0.0011856982 |             f
[INFO 12-10 15:25:12] optimpv.pymooOptimizer: Generation 250: Best objective = 0.004682
   250 |     5000 |     20 |  0.0045097168 |             f
[INFO 12-10 15:25:15] optimpv.pymooOptimizer: Generation 251: Best objective = 0.004682
   251 |     5020 |     20 |  0.0007065779 |             f
[INFO 12-10 15:25:17] optimpv.pymooOptimizer: Generation 252: Best objective = 0.004682
   252 |     5040 |     20 |  0.0039582612 |             f
[INFO 12-10 15:25:19] optimpv.pymooOptimizer: Generation 253: Best objective = 0.004682
   253 |     5060 |     20 |  0.0012835734 |             f
[INFO 12-10 15:25:22] optimpv.pymooOptimizer: Generation 254: Best objective = 0.004682
   254 |     5080 |     20 |  0.0032297950 |             f
[INFO 12-10 15:25:24] optimpv.pymooOptimizer: Generation 255: Best objective = 0.004682
   255 |     5100 |     20 |  0.0011031904 |             f
[INFO 12-10 15:25:26] optimpv.pymooOptimizer: Generation 256: Best objective = 0.004682
   256 |     5120 |     20 |  0.0011370784 |             f
[INFO 12-10 15:25:29] optimpv.pymooOptimizer: Generation 257: Best objective = 0.004682
   257 |     5140 |     20 |  0.0009623637 |             f
[INFO 12-10 15:25:31] optimpv.pymooOptimizer: Generation 258: Best objective = 0.004682
   258 |     5160 |     20 |  0.0017339645 |             f
[INFO 12-10 15:25:33] optimpv.pymooOptimizer: Generation 259: Best objective = 0.004682
   259 |     5180 |     20 |  0.0050451604 |             f
[INFO 12-10 15:25:35] optimpv.pymooOptimizer: Generation 260: Best objective = 0.004682
   260 |     5200 |     20 |  0.0022780892 |             f
[INFO 12-10 15:25:39] optimpv.pymooOptimizer: Generation 261: Best objective = 0.004682
   261 |     5220 |     20 |  0.0043500393 |             f
[INFO 12-10 15:25:41] optimpv.pymooOptimizer: Generation 262: Best objective = 0.004682
   262 |     5240 |     20 |  0.000000E+00 |             f
[INFO 12-10 15:25:43] optimpv.pymooOptimizer: Generation 263: Best objective = 0.004682
   263 |     5260 |     20 |  0.0014050884 |             f
[INFO 12-10 15:25:45] optimpv.pymooOptimizer: Generation 264: Best objective = 0.004682
   264 |     5280 |     20 |  0.0059660825 |             f
[INFO 12-10 15:25:48] optimpv.pymooOptimizer: Generation 265: Best objective = 0.004682
   265 |     5300 |     20 |  0.0042954628 |             f
[INFO 12-10 15:25:50] optimpv.pymooOptimizer: Generation 266: Best objective = 0.004682
   266 |     5320 |     20 |  0.0005143862 |             f
[INFO 12-10 15:25:52] optimpv.pymooOptimizer: Generation 267: Best objective = 0.004682
   267 |     5340 |     20 |  0.0041420555 |             f
[INFO 12-10 15:25:54] optimpv.pymooOptimizer: Generation 268: Best objective = 0.004682
   268 |     5360 |     20 |  0.0036482087 |             f
[INFO 12-10 15:25:57] optimpv.pymooOptimizer: Generation 269: Best objective = 0.004682
   269 |     5380 |     20 |  0.0005576906 |             f
[INFO 12-10 15:25:59] optimpv.pymooOptimizer: Generation 270: Best objective = 0.004682
   270 |     5400 |     20 |  0.0015817990 |             f
[INFO 12-10 15:26:01] optimpv.pymooOptimizer: Generation 271: Best objective = 0.004656
   271 |     5420 |     19 |  0.1461575062 |         nadir
[INFO 12-10 15:26:03] optimpv.pymooOptimizer: Generation 272: Best objective = 0.004656
   272 |     5440 |     20 |  0.0028373188 |             f
[INFO 12-10 15:26:06] optimpv.pymooOptimizer: Generation 273: Best objective = 0.004656
   273 |     5460 |     20 |  0.0001232806 |             f
[INFO 12-10 15:26:08] optimpv.pymooOptimizer: Generation 274: Best objective = 0.004656
   274 |     5480 |     20 |  0.0049694547 |             f
[INFO 12-10 15:26:11] optimpv.pymooOptimizer: Generation 275: Best objective = 0.004656
   275 |     5500 |     20 |  0.0004371670 |             f
[INFO 12-10 15:26:13] optimpv.pymooOptimizer: Generation 276: Best objective = 0.004656
   276 |     5520 |     20 |  0.0048582380 |             f
[INFO 12-10 15:26:16] optimpv.pymooOptimizer: Generation 277: Best objective = 0.004656
   277 |     5540 |     20 |  0.0051835526 |         nadir
[INFO 12-10 15:26:18] optimpv.pymooOptimizer: Generation 278: Best objective = 0.004656
   278 |     5560 |     20 |  0.0008658544 |             f
[INFO 12-10 15:26:20] optimpv.pymooOptimizer: Generation 279: Best objective = 0.004656
   279 |     5580 |     20 |  0.0038945716 |             f
[INFO 12-10 15:26:23] optimpv.pymooOptimizer: Generation 280: Best objective = 0.004656
   280 |     5600 |     20 |  0.0034531219 |             f
[INFO 12-10 15:26:25] optimpv.pymooOptimizer: Generation 281: Best objective = 0.004645
   281 |     5620 |     20 |  0.0318256277 |         nadir
[INFO 12-10 15:26:28] optimpv.pymooOptimizer: Generation 282: Best objective = 0.004639
   282 |     5640 |     20 |  0.0107194072 |         nadir
[INFO 12-10 15:26:30] optimpv.pymooOptimizer: Generation 283: Best objective = 0.004639
   283 |     5660 |     20 |  0.0025500707 |             f
[INFO 12-10 15:26:32] optimpv.pymooOptimizer: Generation 284: Best objective = 0.004639
   284 |     5680 |     20 |  0.0406251710 |         nadir
[INFO 12-10 15:26:35] optimpv.pymooOptimizer: Generation 285: Best objective = 0.004639
   285 |     5700 |     20 |  0.0026570769 |             f
[INFO 12-10 15:26:37] optimpv.pymooOptimizer: Generation 286: Best objective = 0.004639
   286 |     5720 |     20 |  0.0024668066 |             f
[INFO 12-10 15:26:39] optimpv.pymooOptimizer: Generation 287: Best objective = 0.004639
   287 |     5740 |     20 |  0.0053905552 |             f
[INFO 12-10 15:26:41] optimpv.pymooOptimizer: Generation 288: Best objective = 0.004639
   288 |     5760 |     20 |  0.0058925036 |             f
[INFO 12-10 15:26:44] optimpv.pymooOptimizer: Generation 289: Best objective = 0.004639
   289 |     5780 |     20 |  0.0041895518 |             f
[INFO 12-10 15:26:46] optimpv.pymooOptimizer: Generation 290: Best objective = 0.004639
   290 |     5800 |     20 |  0.0052915944 |         ideal
[INFO 12-10 15:26:49] optimpv.pymooOptimizer: Generation 291: Best objective = 0.004639
   291 |     5820 |     20 |  0.0006976219 |             f
[INFO 12-10 15:26:51] optimpv.pymooOptimizer: Generation 292: Best objective = 0.004639
   292 |     5840 |     20 |  0.0028895071 |             f
[INFO 12-10 15:26:53] optimpv.pymooOptimizer: Generation 293: Best objective = 0.004639
   293 |     5860 |     20 |  0.0024610983 |             f
[INFO 12-10 15:26:55] optimpv.pymooOptimizer: Generation 294: Best objective = 0.004639
   294 |     5880 |     20 |  0.0054960184 |             f
[INFO 12-10 15:26:58] optimpv.pymooOptimizer: Generation 295: Best objective = 0.004639
   295 |     5900 |     20 |  0.0020832230 |             f
[INFO 12-10 15:27:00] optimpv.pymooOptimizer: Generation 296: Best objective = 0.004638
   296 |     5920 |     20 |  0.0030483907 |         nadir
[INFO 12-10 15:27:02] optimpv.pymooOptimizer: Generation 297: Best objective = 0.004638
   297 |     5940 |     20 |  0.0036917828 |             f
[INFO 12-10 15:27:05] optimpv.pymooOptimizer: Generation 298: Best objective = 0.004638
   298 |     5960 |     20 |  0.0068334332 |             f
[INFO 12-10 15:27:07] optimpv.pymooOptimizer: Generation 299: Best objective = 0.004638
   299 |     5980 |     20 |  0.0039362106 |             f
[INFO 12-10 15:27:09] optimpv.pymooOptimizer: Generation 300: Best objective = 0.004638
[INFO 12-10 15:27:09] optimpv.pymooOptimizer: Optimization completed after 301 generations
[INFO 12-10 15:27:09] optimpv.pymooOptimizer: Number of function evaluations: 6000
[INFO 12-10 15:27:09] optimpv.pymooOptimizer: Final population size: 20
[INFO 12-10 15:27:09] optimpv.pymooOptimizer: Pareto front size: 20
   300 |     6000 |     20 |  0.0045536190 |             f
[8]:
# get the best parameters and update the params list in the optimizer and the agent
optimizer.update_params_with_best_balance() # update the params list in the optimizer with the best parameters
jv.params = optimizer.params # update the params list in the agent with the best parameters

# print the best parameters
print('Best parameters:')
for p in optimizer.params:
    if p.axis_type == 'log' or (p.value>1e4 or p.value<1e-4):
        print(f'{p.name}, fitted value: {p.value:.4e}')
    else:
        print(f'{p.name}, fitted value: {p.value:.4f}')

print('\nSimSS command line:')
print(jv.get_SIMsalabim_clean_cmd(jv.params)) # print the simss command line with the best parameters

Best parameters:
l2.N_c, fitted value: 2.5678e+24
l2.mu_n, fitted value: 7.2137e-05
l2.mu_p, fitted value: 1.0030e-06
l2.N_t_bulk, fitted value: 2.6543e+20
l2.k_direct, fitted value: 4.8279e-18
l2.C_cation, fitted value: 5.1234e+23
l2.G_ehp, fitted value: 4.1298e+27
l2.eps_r, fitted value: 3.2832e+01
l1.N_t_int, fitted value: 1.2365e+10
offset_l2_l1.E_v, fitted value: 0.0044
Egap_l1.E_c, fitted value: 2.1500
l1.eps_r, fitted value: 3.6339e+00
l1.Nc, fitted value: 9.9252e+26
l1.mu_p, fitted value: 3.6344e-08
l1.ionsMayEnter, fitted value: 1.0000
l2.N_t_int, fitted value: 7.3365e+11
offset_l2_l3.E_c, fitted value: -8.8316e-02
Egap_l3.E_v, fitted value: 2.3000
l3.eps_r, fitted value: 4.3775e+00
l3.Nc, fitted value: 4.3585e+26
l3.mu_n, fitted value: 1.4053e-08
l3.ionsMayEnter, fitted value: 1.0000
R_series, fitted value: 2.5056e-04
R_shunt, fitted value: 4.3506e+01
offset_W_L.E_v, fitted value: 0.0000e+00
offset_W_R.E_c, fitted value: -0.0000e+00

SimSS command line:
./simss -l2.N_c 2.56776498605863e+24 -l2.mu_n 7.21372787783067e-05 -l2.mu_p 1.0029625525690294e-06 -l2.N_t_bulk 2.6543244059740894e+20 -l2.k_direct 4.82787523491415e-18 -l2.N_cation 5.123400191731074e+23 -l2.N_A 5.123400191731074e+23 -l2.G_ehp 4.129761728726564e+27 -l2.eps_r 32.83166381279246 -l1.N_t_int 12365245783.194468 -l1.eps_r 3.633894003646212 -l1.mu_p 3.63435750481879e-08 -l1.ionsMayEnter 1 -l2.N_t_int 733653967911.3058 -l3.eps_r 4.377512498850031 -l3.mu_n 1.405258677807112e-08 -l3.ionsMayEnter 1 -R_series 0.0002505618901349245 -R_shunt 43.50605724256587 -l3.E_c 4.0883156507303635 -l1.E_v 5.545640605160449 -l1.E_c 3.3956406051604495 -l3.E_v 6.388315650730363 -W_L 5.545640605160449 -W_R 4.0883156507303635
[9]:
# rerun the simulation with the best parameters
yfit = jv.run(parameters={}) # run the simulation with the best parameters

viridis = plt.get_cmap('viridis', len(Gfracs))
plt.figure(figsize=(10,10))
linewidth = 2
for idx, Gfrac in enumerate(Gfracs[::-1]):
    plt.plot(X[X[:,1]==Gfrac,0],y[X[:,1]==Gfrac],label='Gfrac = '+str(Gfrac),color=viridis(idx),alpha=0.5,linewidth=linewidth)
    plt.plot(X[X[:,1]==Gfrac,0],yfit[X[:,1]==Gfrac],label='Gfrac = '+str(Gfrac)+' fit',linestyle='--',color=viridis(idx),linewidth=linewidth)
plt.xlabel('Voltage [V]')
plt.ylabel('Current density [A m$^{-2}$]')
plt.legend()
plt.show()

from optimpv.general.general import *
# calculate target
nrmse = calc_metric(y,yfit,metric_name='nrmse')
print('Final NRMSE: ',nrmse)
../_images/examples_QFLS_JV_perovskite_MOO_pymoo_12_0.png
Final NRMSE:  0.012416489322556878
[10]:
# rerun the simulation with the best parameters
yfit_QFLS = jv.run(parameters={},X=X_QFLS,exp_format='K_QFLSL2') # run the simulation with the best parameters

viridis = plt.get_cmap('viridis', len(Gfracs))
plt.figure(figsize=(10,10))
linewidth = 2
for idx, Gfrac in enumerate(Gfracs[::-1]):
    plt.plot(X_QFLS[X_QFLS[:,1]==Gfrac,0],y_QFLS[X_QFLS[:,1]==Gfrac],label='Gfrac = '+str(Gfrac),color=viridis(idx),alpha=0.5,linewidth=linewidth)
    plt.plot(X_QFLS[X_QFLS[:,1]==Gfrac,0],yfit_QFLS[X_QFLS[:,1]==Gfrac],label='Gfrac = '+str(Gfrac)+' fit',linestyle='--',color=viridis(idx),linewidth=linewidth)
plt.xlabel('Voltage [V]')
plt.ylabel('Current density [A m$^{-2}$]')
plt.legend()
plt.show()

from optimpv.general.general import *
# calculate target
nrmse = calc_metric(y_QFLS,yfit_QFLS,metric_name='nrmse')
print('Final NRMSE: ',nrmse)
../_images/examples_QFLS_JV_perovskite_MOO_pymoo_13_0.png
Final NRMSE:  0.018508008647164675
[13]:
import matplotlib
# import itertools
from itertools import combinations
comb = list(combinations(optimizer.all_metrics, 2))
threshold_list = []
for i in range(len(optimizer.agents)):
    for j in range(len(optimizer.agents[i].threshold)):
        threshold_list.append(optimizer.agents[i].threshold[j])
threshold_comb = list(combinations(threshold_list, 2))
pareto = np.asarray(res.F)

cm = matplotlib.colormaps.get_cmap('viridis')
df = optimizer.get_df_from_pymoo() # get the dataframe from the optimizer
# create pareto df
dum_dic = {}

for i , metr in enumerate(optimizer.all_metrics):
    if i not in df.keys():
        dum_dic[metr] = pareto[:, i]

df_pareto = pd.DataFrame(dum_dic)
dum_dic = jv.run_Ax(parameters={})
best_balanced = [ dum_dic[metr] for metr in optimizer.all_metrics]

for c,t_c in zip(comb,threshold_comb):
    plt.figure(figsize=(10, 10))
    plt.scatter(df[c[0]],df[c[1]],c=df.index, cmap=cm, marker='o', s=100) # plot the points with color according to the iteration
    cbar = plt.colorbar()
    cbar.set_label('Iteration')
    sorted_df = df_pareto.sort_values(by=c[0])
    plt.plot(sorted_df[c[0]],sorted_df[c[1]],'r')
    plt.scatter(t_c[0],t_c[1],c='r', marker='x', s=100) # plot the threshold
    plt.scatter(best_balanced[0],best_balanced[1],c='k', marker='*', s=200, label='Best balanced') # plot the best balanced point
    plt.xlabel('nrmse JV')
    plt.ylabel('nrmse QFLS')
    plt.xscale('log')
    plt.yscale('log')


    plt.show()
../_images/examples_QFLS_JV_perovskite_MOO_pymoo_14_0.png
[ ]:
# Clean up the output files (comment out if you want to keep the output files)
sim.clean_all_output(session_path)
sim.delete_folders('tmp',session_path)
# uncomment the following lines to delete specific files
sim.clean_up_output('PTAA',session_path)
sim.clean_up_output('perovskite',session_path)
sim.clean_up_output('C60',session_path)
sim.clean_up_output('simulation_setup_realPerovskite.txt',session_path)