pymoo GA: OPV light-intensity dependant JV fits with SIMsalabim (fake data)

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

[1]:
# Import necessary libraries
import warnings, os, sys, shutil
# 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 numpy.random import default_rng
import torch, copy, uuid
import pySIMsalabim as sim
from pySIMsalabim.experiments.JV_steady_state import *
import ax, logging
from ax.utils.notebook.plotting import init_notebook_plotting, render
init_notebook_plotting() # for Jupyter notebooks

try:
    from optimpv import *
    from optimpv.optimizers.pymooOpti.pymooOptimizer import PymooOptimizer
except Exception as e:
    sys.path.append('../') # add the path to the optimpv module
    from optimpv import *
    from optimpv.optimizers.pymooOpti.pymooOptimizer import PymooOptimizer
[INFO 01-20 10:51:08] ax.utils.notebook.plotting: Injecting Plotly library into cell. Do not overwrite or delete cell.
[INFO 01-20 10:51:08] 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 = [] # list of parameters to be optimized

mun = FitParam(name = 'l2.mu_n', value = 7e-8, bounds = [1e-9,1e-6], log_scale = True, value_type = 'float', fscale = None, rescale = False, display_name=r'$\mu_n$', unit='m$^2$ V$^{-1}$s$^{-1}$', axis_type = 'log', force_log = True)
params.append(mun)

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

bulk_tr = FitParam(name = 'l2.N_t_bulk', value = 1e20, bounds = [1e19,1e22], log_scale = True, value_type = 'float', fscale = None, rescale = False,  display_name=r'$N_{T}$', unit=r'm$^{-3}$', axis_type = 'log', force_log = False)
params.append(bulk_tr)

preLangevin = FitParam(name = 'l2.preLangevin', value = 1e-2, bounds = [0.005,1], log_scale = True, value_type = 'float', fscale = None, rescale = False, display_name=r'$\gamma_{pre}$', unit=r'', axis_type = 'log', force_log = False)
params.append(preLangevin)

R_series = FitParam(name = 'R_series', value = 1e-4, bounds = [1e-5,1e-3], 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 = False)
params.append(R_series)

# save the original parameters for later
params_orig = copy.deepcopy(params)

Generate some fake data

Here we generate some fake data to fit. The data is generated using the same model as the one used for the fitting, so it is a good test of the fitting procedure. For more information on how to run SIMsalabim from python see the pySIMsalabim package.

[3]:
# 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','simsalabim_test_inputs','fakeOPV')))
simulation_setup_filename = 'simulation_setup_fakeOPV.txt'
simulation_setup = os.path.join(session_path, simulation_setup_filename)

# path to the layer files defined in the simulation_setup file
l1 = 'ZnO.txt'
l2 = 'ActiveLayer.txt'
l3 = 'BM_HTL.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)

# Show the device structure
fig = sim.plot_band_diagram(simulation_setup, session_path)

# reset simss
# Set the JV parameters
Gfracs = [0.1,0.5,1.0] # Fractions of the generation rate to simulate (None if you want only one light intensity as define in the simulation_setup file)
UUID = str(uuid.uuid4()) # random UUID to avoid overwriting files

cmd_pars = [] # see pySIMsalabim documentation for the command line parameters
# Add the parameters to the command line arguments
for param in params:
    cmd_pars.append({'par':param.name, 'val':str(param.value)})
# Add the layer files to the command line arguments
# cmd_pars.append({'par':'l1', 'val':l1})
# cmd_pars.append({'par':'l2', 'val':l2})
# cmd_pars.append({'par':'l3', 'val':l3})

# Run the JV simulation
ret, mess = run_SS_JV(simulation_setup, session_path, JV_file_name = 'JV.dat', G_fracs = Gfracs, parallel = True, max_jobs = 3, UUID=UUID, cmd_pars=cmd_pars)

# save data for fitting
X,y = [],[]
X_orig,y_orig = [],[]
if Gfracs is None:
    data = pd.read_csv(os.path.join(session_path, 'JV_'+UUID+'.dat'), sep=r'\s+') # Load the data
    Vext = np.asarray(data['Vext'].values)
    Jext = np.asarray(data['Jext'].values)
    G = np.ones_like(Vext)
    rng = default_rng()#
    noise = rng.standard_normal(Jext.shape) * 0.01 * Jext
    Jext = Jext + noise
    X = Vext
    y = Jext

    plt.figure()
    plt.plot(X,y)
    plt.show()
else:
    for Gfrac in Gfracs:
        data = pd.read_csv(os.path.join(session_path, 'JV_Gfrac_'+str(Gfrac)+'_'+UUID+'.dat'), sep=r'\s+') # Load the data
        Vext = np.asarray(data['Vext'].values)
        Jext = np.asarray(data['Jext'].values)
        G = np.ones_like(Vext)*Gfrac
        rng = default_rng()#
        noise = rng.standard_normal(Jext.shape) * 0.005 * Jext

        if len(X) == 0:
            X = np.vstack((Vext,G)).T
            y = Jext + noise
            y_orig = Jext
        else:
            X = np.vstack((X,np.vstack((Vext,G)).T))
            y = np.hstack((y,Jext+ noise))
            y_orig = np.hstack((y_orig,Jext))

    # remove all the current where Jext is higher than a given value
    X = X[y<200]
    X_orig = copy.deepcopy(X)
    y_orig = y_orig[y<200]
    y = y[y<200]



    plt.figure()
    for Gfrac in Gfracs:
        plt.plot(X[X[:,1]==Gfrac,0],y[X[:,1]==Gfrac],label='Gfrac = '+str(Gfrac))
    plt.xlabel('Voltage [V]')
    plt.ylabel('Current density [A/m$^2$]')
    plt.legend()
    plt.show()


../_images/examples_JV_fakeOPV_pymoo_5_0.png
../_images/examples_JV_fakeOPV_pymoo_5_1.png

Run the optimization

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

jv = JVAgent(params, X, y, session_path, simulation_setup, parallel = True, max_jobs = 3, metric = metric, loss = loss)

# Calulate the target metric for the original parameters
best_fit_possible = loss_function(calc_metric(y,y_orig, metric_name = metric),loss)
print('Best fit: ',best_fit_possible)
Best fit:  0.0019756765515358777
[5]:
# Define the optimizer
optimizer = PymooOptimizer(params=params, agents=jv, algorithm='GA', pop_size=20, n_gen=100, name='pymoo_single_obj', verbose_logging=True,max_parallelism=20, )
[6]:
optimizer.optimize() # run the optimization
[INFO 01-20 10:51:08] optimpv.pymooOptimizer: Starting optimization using GA algorithm
[INFO 01-20 10:51:08] optimpv.pymooOptimizer: Population size: 20, Generations: 100
[INFO 01-20 10:51:09] optimpv.pymooOptimizer: Generation 1: Best objective = 0.131506
=================================================
n_gen  |  n_eval  |     f_avg     |     f_min
=================================================
     1 |       20 |  0.2101623524 |  0.1315058712
[INFO 01-20 10:51:10] optimpv.pymooOptimizer: Generation 2: Best objective = 0.114552
     2 |       40 |  0.1601799521 |  0.1145522371
[INFO 01-20 10:51:10] optimpv.pymooOptimizer: Generation 3: Best objective = 0.102320
     3 |       60 |  0.1321878768 |  0.1023200372
[INFO 01-20 10:51:11] optimpv.pymooOptimizer: Generation 4: Best objective = 0.089051
     4 |       80 |  0.1135910031 |  0.0890509079
[INFO 01-20 10:51:11] optimpv.pymooOptimizer: Generation 5: Best objective = 0.061026
     5 |      100 |  0.0991453340 |  0.0610258186
[INFO 01-20 10:51:11] optimpv.pymooOptimizer: Generation 6: Best objective = 0.021096
     6 |      120 |  0.0771031928 |  0.0210964328
[INFO 01-20 10:51:12] optimpv.pymooOptimizer: Generation 7: Best objective = 0.003019
     7 |      140 |  0.0514150920 |  0.0030189215
[INFO 01-20 10:51:12] optimpv.pymooOptimizer: Generation 8: Best objective = 0.003019
     8 |      160 |  0.0315865794 |  0.0030189215
[INFO 01-20 10:51:12] optimpv.pymooOptimizer: Generation 9: Best objective = 0.003019
     9 |      180 |  0.0174407955 |  0.0030189215
[INFO 01-20 10:51:13] optimpv.pymooOptimizer: Generation 10: Best objective = 0.003019
    10 |      200 |  0.0099064861 |  0.0030189215
[INFO 01-20 10:51:13] optimpv.pymooOptimizer: Generation 11: Best objective = 0.003019
    11 |      220 |  0.0061857056 |  0.0030189215
[INFO 01-20 10:51:13] optimpv.pymooOptimizer: Generation 12: Best objective = 0.002971
    12 |      240 |  0.0044101990 |  0.0029706458
[INFO 01-20 10:51:14] optimpv.pymooOptimizer: Generation 13: Best objective = 0.002701
    13 |      260 |  0.0036953850 |  0.0027006345
[INFO 01-20 10:51:14] optimpv.pymooOptimizer: Generation 14: Best objective = 0.002701
    14 |      280 |  0.0033598072 |  0.0027006345
[INFO 01-20 10:51:15] optimpv.pymooOptimizer: Generation 15: Best objective = 0.002701
    15 |      300 |  0.0031378033 |  0.0027006345
[INFO 01-20 10:51:15] optimpv.pymooOptimizer: Generation 16: Best objective = 0.002693
    16 |      320 |  0.0030204312 |  0.0026934629
[INFO 01-20 10:51:15] optimpv.pymooOptimizer: Generation 17: Best objective = 0.002693
    17 |      340 |  0.0029735572 |  0.0026934629
[INFO 01-20 10:51:16] optimpv.pymooOptimizer: Generation 18: Best objective = 0.002693
    18 |      360 |  0.0029236571 |  0.0026934629
[INFO 01-20 10:51:16] optimpv.pymooOptimizer: Generation 19: Best objective = 0.002600
    19 |      380 |  0.0028688493 |  0.0026000345
[INFO 01-20 10:51:16] optimpv.pymooOptimizer: Generation 20: Best objective = 0.002600
    20 |      400 |  0.0028280617 |  0.0026000345
[INFO 01-20 10:51:17] optimpv.pymooOptimizer: Generation 21: Best objective = 0.002600
    21 |      420 |  0.0027251421 |  0.0026000345
[INFO 01-20 10:51:17] optimpv.pymooOptimizer: Generation 22: Best objective = 0.002600
    22 |      440 |  0.0027016588 |  0.0026000345
[INFO 01-20 10:51:17] optimpv.pymooOptimizer: Generation 23: Best objective = 0.002600
    23 |      460 |  0.0026891073 |  0.0026000345
[INFO 01-20 10:51:18] optimpv.pymooOptimizer: Generation 24: Best objective = 0.002600
    24 |      480 |  0.0026785830 |  0.0026000345
[INFO 01-20 10:51:18] optimpv.pymooOptimizer: Generation 25: Best objective = 0.002600
    25 |      500 |  0.0026724630 |  0.0026000345
[INFO 01-20 10:51:18] optimpv.pymooOptimizer: Generation 26: Best objective = 0.002600
    26 |      520 |  0.0026645424 |  0.0026000345
[INFO 01-20 10:51:19] optimpv.pymooOptimizer: Generation 27: Best objective = 0.002558
    27 |      540 |  0.0026461194 |  0.0025581455
[INFO 01-20 10:51:19] optimpv.pymooOptimizer: Generation 28: Best objective = 0.002558
    28 |      560 |  0.0026396146 |  0.0025581455
[INFO 01-20 10:51:20] optimpv.pymooOptimizer: Generation 29: Best objective = 0.002558
    29 |      580 |  0.0026307772 |  0.0025581455
[INFO 01-20 10:51:20] optimpv.pymooOptimizer: Generation 30: Best objective = 0.002558
    30 |      600 |  0.0026194269 |  0.0025581455
[INFO 01-20 10:51:20] optimpv.pymooOptimizer: Generation 31: Best objective = 0.002558
    31 |      620 |  0.0026075303 |  0.0025581455
[INFO 01-20 10:51:21] optimpv.pymooOptimizer: Generation 32: Best objective = 0.002558
    32 |      640 |  0.0025838699 |  0.0025581449
[INFO 01-20 10:51:21] optimpv.pymooOptimizer: Generation 33: Best objective = 0.002558
    33 |      660 |  0.0025701709 |  0.0025581449
[INFO 01-20 10:51:21] optimpv.pymooOptimizer: Generation 34: Best objective = 0.002558
    34 |      680 |  0.0025610516 |  0.0025581449
[INFO 01-20 10:51:22] optimpv.pymooOptimizer: Generation 35: Best objective = 0.002557
    35 |      700 |  0.0025585712 |  0.0025574595
[INFO 01-20 10:51:22] optimpv.pymooOptimizer: Generation 36: Best objective = 0.002557
    36 |      720 |  0.0025582008 |  0.0025574021
[INFO 01-20 10:51:22] optimpv.pymooOptimizer: Generation 37: Best objective = 0.002557
    37 |      740 |  0.0025578902 |  0.0025573861
[INFO 01-20 10:51:23] optimpv.pymooOptimizer: Generation 38: Best objective = 0.002557
    38 |      760 |  0.0025576404 |  0.0025573820
[INFO 01-20 10:51:23] optimpv.pymooOptimizer: Generation 39: Best objective = 0.002542
    39 |      780 |  0.0025566575 |  0.0025422219
[INFO 01-20 10:51:23] optimpv.pymooOptimizer: Generation 40: Best objective = 0.002542
    40 |      800 |  0.0025551349 |  0.0025422217
[INFO 01-20 10:51:24] optimpv.pymooOptimizer: Generation 41: Best objective = 0.002542
    41 |      820 |  0.0025543563 |  0.0025418575
[INFO 01-20 10:51:24] optimpv.pymooOptimizer: Generation 42: Best objective = 0.002542
    42 |      840 |  0.0025498505 |  0.0025418575
[INFO 01-20 10:51:25] optimpv.pymooOptimizer: Generation 43: Best objective = 0.002542
    43 |      860 |  0.0025463847 |  0.0025418575
[INFO 01-20 10:51:25] optimpv.pymooOptimizer: Generation 44: Best objective = 0.002542
    44 |      880 |  0.0025433191 |  0.0025418575
[INFO 01-20 10:51:25] optimpv.pymooOptimizer: Generation 45: Best objective = 0.002542
    45 |      900 |  0.0025420756 |  0.0025418575
[INFO 01-20 10:51:26] optimpv.pymooOptimizer: Generation 46: Best objective = 0.002466
    46 |      920 |  0.0025382138 |  0.0024660771
[INFO 01-20 10:51:26] optimpv.pymooOptimizer: Generation 47: Best objective = 0.002434
    47 |      940 |  0.0025327622 |  0.0024340962
[INFO 01-20 10:51:26] optimpv.pymooOptimizer: Generation 48: Best objective = 0.002434
    48 |      960 |  0.0025235252 |  0.0024340962
[INFO 01-20 10:51:27] optimpv.pymooOptimizer: Generation 49: Best objective = 0.002433
    49 |      980 |  0.0025127591 |  0.0024333327
[INFO 01-20 10:51:27] optimpv.pymooOptimizer: Generation 50: Best objective = 0.002433
    50 |     1000 |  0.0024995586 |  0.0024333327
[INFO 01-20 10:51:27] optimpv.pymooOptimizer: Generation 51: Best objective = 0.002423
    51 |     1020 |  0.0024605686 |  0.0024232198
[INFO 01-20 10:51:28] optimpv.pymooOptimizer: Generation 52: Best objective = 0.002423
    52 |     1040 |  0.0024376829 |  0.0024232198
[INFO 01-20 10:51:28] optimpv.pymooOptimizer: Generation 53: Best objective = 0.002422
    53 |     1060 |  0.0024324949 |  0.0024224633
[INFO 01-20 10:51:29] optimpv.pymooOptimizer: Generation 54: Best objective = 0.002422
    54 |     1080 |  0.0024312014 |  0.0024224376
[INFO 01-20 10:51:29] optimpv.pymooOptimizer: Generation 55: Best objective = 0.002422
    55 |     1100 |  0.0024306561 |  0.0024224334
[INFO 01-20 10:51:29] optimpv.pymooOptimizer: Generation 56: Best objective = 0.002422
    56 |     1120 |  0.0024285082 |  0.0024224308
[INFO 01-20 10:51:30] optimpv.pymooOptimizer: Generation 57: Best objective = 0.002422
    57 |     1140 |  0.0024253145 |  0.0024223012
[INFO 01-20 10:51:30] optimpv.pymooOptimizer: Generation 58: Best objective = 0.002421
    58 |     1160 |  0.0024224734 |  0.0024212447
[INFO 01-20 10:51:30] optimpv.pymooOptimizer: Generation 59: Best objective = 0.002405
    59 |     1180 |  0.0024209597 |  0.0024049921
[INFO 01-20 10:51:31] optimpv.pymooOptimizer: Generation 60: Best objective = 0.002405
    60 |     1200 |  0.0024205578 |  0.0024049921
[INFO 01-20 10:51:31] optimpv.pymooOptimizer: Generation 61: Best objective = 0.002405
    61 |     1220 |  0.0024190683 |  0.0024049921
[INFO 01-20 10:51:31] optimpv.pymooOptimizer: Generation 62: Best objective = 0.002405
    62 |     1240 |  0.0024169204 |  0.0024049921
[INFO 01-20 10:51:32] optimpv.pymooOptimizer: Generation 63: Best objective = 0.002405
    63 |     1260 |  0.0024135431 |  0.0024049921
[INFO 01-20 10:51:32] optimpv.pymooOptimizer: Generation 64: Best objective = 0.002400
    64 |     1280 |  0.0024094779 |  0.0024004520
[INFO 01-20 10:51:32] optimpv.pymooOptimizer: Generation 65: Best objective = 0.002400
    65 |     1300 |  0.0024076029 |  0.0024004520
[INFO 01-20 10:51:33] optimpv.pymooOptimizer: Generation 66: Best objective = 0.002400
    66 |     1320 |  0.0024057666 |  0.0024004517
[INFO 01-20 10:51:33] optimpv.pymooOptimizer: Generation 67: Best objective = 0.002400
    67 |     1340 |  0.0024041949 |  0.0024004517
[INFO 01-20 10:51:34] optimpv.pymooOptimizer: Generation 68: Best objective = 0.002400
    68 |     1360 |  0.0024034219 |  0.0024004517
[INFO 01-20 10:51:34] optimpv.pymooOptimizer: Generation 69: Best objective = 0.002400
    69 |     1380 |  0.0024024350 |  0.0024000941
[INFO 01-20 10:51:34] optimpv.pymooOptimizer: Generation 70: Best objective = 0.002400
    70 |     1400 |  0.0024007751 |  0.0024000941
[INFO 01-20 10:51:35] optimpv.pymooOptimizer: Generation 71: Best objective = 0.002400
    71 |     1420 |  0.0024004136 |  0.0024000941
[INFO 01-20 10:51:35] optimpv.pymooOptimizer: Generation 72: Best objective = 0.002400
    72 |     1440 |  0.0024003903 |  0.0024000941
[INFO 01-20 10:51:35] optimpv.pymooOptimizer: Generation 73: Best objective = 0.002400
    73 |     1460 |  0.0024003742 |  0.0024000941
[INFO 01-20 10:51:36] optimpv.pymooOptimizer: Generation 74: Best objective = 0.002400
    74 |     1480 |  0.0024003050 |  0.0024000941
[INFO 01-20 10:51:36] optimpv.pymooOptimizer: Generation 75: Best objective = 0.002400
    75 |     1500 |  0.0024002245 |  0.0024000735
[INFO 01-20 10:51:36] optimpv.pymooOptimizer: Generation 76: Best objective = 0.002400
    76 |     1520 |  0.0024001586 |  0.0024000509
[INFO 01-20 10:51:37] optimpv.pymooOptimizer: Generation 77: Best objective = 0.002372
    77 |     1540 |  0.0023987008 |  0.0023718976
[INFO 01-20 10:51:37] optimpv.pymooOptimizer: Generation 78: Best objective = 0.002372
    78 |     1560 |  0.0023972682 |  0.0023718976
[INFO 01-20 10:51:38] optimpv.pymooOptimizer: Generation 79: Best objective = 0.002371
    79 |     1580 |  0.0023920535 |  0.0023705718
[INFO 01-20 10:51:38] optimpv.pymooOptimizer: Generation 80: Best objective = 0.002335
    80 |     1600 |  0.0023809753 |  0.0023348679
[INFO 01-20 10:51:38] optimpv.pymooOptimizer: Generation 81: Best objective = 0.002335
    81 |     1620 |  0.0023701992 |  0.0023348679
[INFO 01-20 10:51:39] optimpv.pymooOptimizer: Generation 82: Best objective = 0.002335
    82 |     1640 |  0.0023668525 |  0.0023348679
[INFO 01-20 10:51:39] optimpv.pymooOptimizer: Generation 83: Best objective = 0.002335
    83 |     1660 |  0.0023631215 |  0.0023348623
[INFO 01-20 10:51:39] optimpv.pymooOptimizer: Generation 84: Best objective = 0.002335
    84 |     1680 |  0.0023559795 |  0.0023347960
[INFO 01-20 10:51:40] optimpv.pymooOptimizer: Generation 85: Best objective = 0.002335
    85 |     1700 |  0.0023488441 |  0.0023347960
[INFO 01-20 10:51:40] optimpv.pymooOptimizer: Generation 86: Best objective = 0.002335
    86 |     1720 |  0.0023434937 |  0.0023347960
[INFO 01-20 10:51:40] optimpv.pymooOptimizer: Generation 87: Best objective = 0.002335
    87 |     1740 |  0.0023348412 |  0.0023347960
[INFO 01-20 10:51:41] optimpv.pymooOptimizer: Generation 88: Best objective = 0.002335
    88 |     1760 |  0.0023348295 |  0.0023347955
[INFO 01-20 10:51:41] optimpv.pymooOptimizer: Generation 89: Best objective = 0.002335
    89 |     1780 |  0.0023348091 |  0.0023347955
[INFO 01-20 10:51:42] optimpv.pymooOptimizer: Generation 90: Best objective = 0.002335
    90 |     1800 |  0.0023347962 |  0.0023347955
[INFO 01-20 10:51:42] optimpv.pymooOptimizer: Generation 91: Best objective = 0.002323
    91 |     1820 |  0.0023341923 |  0.0023227254
[INFO 01-20 10:51:42] optimpv.pymooOptimizer: Generation 92: Best objective = 0.002323
    92 |     1840 |  0.0023341923 |  0.0023227254
[INFO 01-20 10:51:43] optimpv.pymooOptimizer: Generation 93: Best objective = 0.002323
    93 |     1860 |  0.0023335878 |  0.0023227113
[INFO 01-20 10:51:43] optimpv.pymooOptimizer: Generation 94: Best objective = 0.002323
    94 |     1880 |  0.0023329863 |  0.0023227113
[INFO 01-20 10:51:43] optimpv.pymooOptimizer: Generation 95: Best objective = 0.002323
    95 |     1900 |  0.0023317807 |  0.0023227113
[INFO 01-20 10:51:44] optimpv.pymooOptimizer: Generation 96: Best objective = 0.002323
    96 |     1920 |  0.0023305622 |  0.0023225137
[INFO 01-20 10:51:44] optimpv.pymooOptimizer: Generation 97: Best objective = 0.002323
    97 |     1940 |  0.0023293536 |  0.0023225137
[INFO 01-20 10:51:44] optimpv.pymooOptimizer: Generation 98: Best objective = 0.002323
    98 |     1960 |  0.0023268682 |  0.0023225137
[INFO 01-20 10:51:45] optimpv.pymooOptimizer: Generation 99: Best objective = 0.002323
    99 |     1980 |  0.0023244551 |  0.0023225137
[INFO 01-20 10:51:45] optimpv.pymooOptimizer: Generation 100: Best objective = 0.002323
[INFO 01-20 10:51:45] optimpv.pymooOptimizer: Optimization completed after 101 generations
[INFO 01-20 10:51:45] optimpv.pymooOptimizer: Number of function evaluations: 2000
[INFO 01-20 10:51:45] optimpv.pymooOptimizer: Best objective value: 0.002323
   100 |     2000 |  0.0023226840 |  0.0023225051
[6]:
<pymoo.core.result.Result at 0x73a3b8fa9e50>
[7]:
# get the best parameters and update the params list in the optimizer and the agent
optimizer.update_params_with_best_balance()
jv.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)

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

Best parameters:
l2.mu_n fitted value: 1.2957703120615665e-07 original value: 7e-08
l2.mu_p fitted value: 3.663753682084455e-08 original value: 5e-08
l2.N_t_bulk fitted value: 7.912248003855794e+19 original value: 1e+20
l2.preLangevin fitted value: 0.007544798309069992 original value: 0.01
R_series fitted value: 0.00011631902332779839 original value: 0.0001

SimSS command line:
./simss -l2.mu_n 1.2957703120615665e-07 -l2.mu_p 3.663753682084455e-08 -l2.N_t_bulk 7.912248003855794e+19 -l2.preLangevin 0.007544798309069992 -R_series 0.00011631902332779839
[8]:
optimizer.plot_convergence(yscale='log', xscale='linear')
../_images/examples_JV_fakeOPV_pymoo_11_0.png
[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()
../_images/examples_JV_fakeOPV_pymoo_12_0.png
[10]:
# 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('ZnO',session_path)
sim.clean_up_output('ActiveLayer',session_path)
sim.clean_up_output('BM_HTL',session_path)
sim.clean_up_output('simulation_setup_fakeOPV',session_path)