def info_matrix(tic, spt, mp): designer1 = Designer() designer1.simulate = simulate designer1.ti_controls_candidates = np.array([tic]) designer1.sampling_times_candidates = np.array([spt]) designer1.model_parameters = mp designer1.initialize(verbose=0) designer1._trim_fim = False efforts = np.array([[1] * spt.size]) return designer1.eval_fim(efforts)
from pydex.core.designer import Designer from examples.time_varying_controls.case_2_tvc_model import simulate import numpy as np designer_1 = Designer() designer_1.simulate = simulate """ specifying nominal model parameter values """ np.random.seed(123) n_scr = 100 pre_exp_constant = np.random.uniform(0.1, 1.0, n_scr) activ_energy = np.random.uniform(1e3, 1e4, n_scr) theta_0 = np.log(pre_exp_constant) - activ_energy / (8.314159 * 273.15) theta_1 = activ_energy / (8.314159 * 273.15) theta_nom = np.array([ theta_0, theta_1, np.ones_like(pre_exp_constant), 0.5 * np.ones_like(pre_exp_constant) ]).T # value of theta_0, theta_1, alpha_a, nu designer_1.model_parameters = theta_nom # assigning it to the designer's theta """ enumerating candidates """ tic, tvc = designer_1.enumerate_candidates( bounds=[ [5, 10], # cA0 [273.15, 323.15], # temp [0, 1e-1], # q_in in L/min [10, 20], # ca_in in mol/L [0, 1], # cb_in in mol/L ], levels=[ 1, 5, 3,
Solution : a 2^3 factorial design, criterion does not affect design. """ def simulate(ti_controls, model_parameters): return np.array([ # constant term model_parameters[0] + # linear term model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[1] + model_parameters[3] * ti_controls[2] ]) designer = Designer() designer.simulate = simulate designer.model_parameters = np.ones( 4) # values won't affect design, but still needed designer.ti_controls_candidates = designer.enumerate_candidates( bounds=[ [-1, 1], [-1, 1], [-1, 1], ], levels=[ 11, 11, 11, ], )
def simulate(ti_controls, model_parameters): return np.array([ # constant term model_parameters[0] + # linear term model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[1] + # interaction term model_parameters[3] * ti_controls[0] * ti_controls[1] + # squared term model_parameters[4] * ti_controls[0]**2 + model_parameters[5] * ti_controls[1]**2 ]) designer_1 = Designer() designer_1.simulate = simulate reso = 11 tic = designer_1.create_grid(bounds=[(-1, 1), (-1, 1)], levels=[reso, reso]) designer_1.ti_controls_candidates = tic designer_1.model_parameters = np.ones( 6) # values won't affect design, but still needed designer_1.initialize( verbose=2) # 0: silent, 1: overview, 2: detailed, 3: very detailed designer_1.design_experiment(designer_1.d_opt_criterion, n_exp=7, write=False) designer_1.print_optimal_candidates() designer_1.plot_optimal_controls(alpha=0.3, non_opt_candidates=True)
# linear-linear interaction model_parameters[5] * ti_controls[0] * ti_controls[1] + model_parameters[6] * ti_controls[0] * ti_controls[2] + model_parameters[7] * ti_controls[0] * ti_controls[3] + model_parameters[8] * ti_controls[1] * ti_controls[2] + model_parameters[9] * ti_controls[1] * ti_controls[3] + model_parameters[10] * ti_controls[2] * ti_controls[3] + # quadratic model_parameters[11] * ti_controls[0] ** 2 + model_parameters[12] * ti_controls[1] ** 2 + model_parameters[13] * ti_controls[2] ** 2 + model_parameters[14] * ti_controls[3] ** 2 ]) designer = Designer() designer.simulate = simulate designer.model_parameters = np.ones(15) # values won't affect design, but still needed outer_axes_reso = 11 designer.ti_controls_candidates = designer.enumerate_candidates( bounds=[ [-1, 1], [-1, 1], [-1, 1], [-1, 1], ], levels=[ 5, 5, outer_axes_reso, outer_axes_reso,
from pydex.core.designer import Designer import numpy as np def simulate(ti_controls, model_parameters): return np.array([ model_parameters[0] + model_parameters[1] * np.exp(model_parameters[2] * ti_controls[0]) ]) designer = Designer() designer.simulate = simulate tic = np.mgrid[-1:1:111j] designer.ti_controls_candidates = tic[:, None] mp = np.array([1, 2, -1]) designer.model_parameters = mp designer.initialize() criterion = designer.d_opt_criterion designer.design_experiment(criterion, write=False) designer.print_optimal_candidates() designer.plot_optimal_controls() criterion = designer.a_opt_criterion designer.design_experiment(criterion, write=False) designer.print_optimal_candidates() designer.plot_optimal_controls()
from pydex.core.designer import Designer import numpy as np def simulate(ti_controls, model_parameters): return np.array([ model_parameters[0] + model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[0] ** 2 ]) designer = Designer() designer.simulate = simulate designer.ti_controls_candidates = designer.enumerate_candidates( bounds=[ [-1, 1], ], levels=[101], ) designer.model_parameters = np.ones(3) designer.initialize(verbose=2) criteria = [ designer.dg_opt_criterion, designer.ag_opt_criterion, designer.eg_opt_criterion, designer.di_opt_criterion, designer.ai_opt_criterion, designer.ei_opt_criterion, ] for criterion in criteria: designer.design_experiment( criterion=criterion, write=False, package="scipy",
from sir_model import simulate from pydex.core.designer import Designer import numpy as np designer = Designer() designer.simulate = simulate designer.ti_controls_candidates = [[100, 1, 0]] designer.sampling_times_candidates = [np.linspace(0, 10, 31)] designer.model_parameters = np.random.uniform(low=[5, 0.5], high=[10, 1.5], size=[100, 2]) designer.initialize(verbose=2) designer.solve_cvar_problem( designer.cvar_d_opt_criterion, beta=0.80, optimize_sampling_times=True, optimizer="MOSEK", package="cvxpy", reso=5, plot=True, write=False, ) designer.plot_pareto_frontier(write=False) designer.show_plots()
from pydex.core.designer import Designer from dow_chemical import simulate import numpy as np designer = Designer() designer.simulate = simulate designer.ti_controls_candidates = designer.enumerate_candidates( bounds=[ [0.5, 3.5], [0, 7], ], levels=[ 5, 5, ], ) designer.sampling_times_candidates = np.array([ np.linspace(0, 1, 21) for _ in range(len(designer.ti_controls_candidates)) ]) designer.model_parameters = np.array([ 1.8934, 2.7585, 1.7540e3, 6.1894e-3, 0.0048, ]) designer.initialize(verbose=2) # designer.estimability_study_fim() designer.design_experiment( criterion=designer.d_opt_criterion, write=False,
model.cb[t] ** model.alpha_b) model.material_balance_a = po.Constraint(model.t, rule=_material_balance_a) def _material_balance_b(m, t): k = po.exp(m.theta_0 + m.theta_1 * (m.temp - 273.15) / m.temp) return m.dcb_dt[t] / m.tau == m.nu * k * (m.ca[t] ** model.alpha_a) * ( model.cb[t] ** model.alpha_b) model.material_balance_b = po.Constraint(model.t, rule=_material_balance_b) return model model1 = create_model() simulator1 = pod.Simulator(model1, package="casadi") designer1 = Designer() designer1.model = model1 designer1.simulator = simulator1 designer1.simulate = simulate def info_matrix(tic, spt, mp): designer1.ti_controls_candidates = np.array([tic]) designer1.sampling_times_candidates = np.array([spt]) designer1.model_parameters = mp designer1.initialize() designer1._trim_fim = False efforts = np.array([[1] * spt.size]) return designer1.eval_fim(efforts, mp) def simul_d_opt(x): mp = np.array([-4.5, -2.2, 1, 0.5])
from pydex.core.designer import Designer from examples.ode.ode_oed_case_1_pyomo import create_model, simulate, create_simulator import numpy as np """ loading only saves states and results, need to redeclare the model, simulate function, and simulator """ model_1 = create_model() designer_1 = Designer() designer_1.model = model_1 designer_1.simulate = simulate designer_1.simulator = create_simulator(model_1, package='casadi') """ loading state (experimental candidates, nominal model parameter values """ designer_1.load_state('/ode_oed_case_2_result/date_2020-4-16/state_1.pkl') """ loading sensitivity values from previous run """ designer_1.load_sensitivity( '/ode_oed_case_2_result/date_2020-4-16/sensitivity_1.pkl') """" re-initialize the designer """ designer_1.initialize() """ estimability study without redoing sensitivity analysis """ designer_1.responses_scales = np.ones(2) # equal scale of responses designer_1.estimability_study_fim() """ design experiment without redoing sensitivity analysis """ package, optimizer = ("cvxpy", "MOSEK") # package, optimizer = ("cvxpy", "SCS") # package, optimizer = ("cvxpy", "CVXOPT") # package, optimizer = ("scipy", "SLSQP") criterion = designer_1.d_opt_criterion # criterion = designer_1.a_opt_criterion # criterion = designer_1.e_opt_criterion
spt = np.linspace(0, 1, 11) theta_nom = [-4.5, 2.2, 1.0, 0.5] #theta_nom = np.random.multivariate_normal( # mean=[-4.5, 2.2, 1.0, 0.5], # cov=[ # [0.10, 0.0, 0.0, 0.0,], # [0.0, 0.10, 0.0, 0.0], # [0.0, 0.0, .10, 0.0], # [0.0, 0.0, 0.0, 0.01], # ], # size=100, #) #theta_nom[:, 2] = np.round(theta_nom[:, 2]) pyMod.plot_ode_model(ti_controls, spt, theta_nom) designer_1 = Designer() designer_1.simulate = pyMod.simulate designer_1.model_parameters = theta_nom tic = designer_1.enumerate_candidates(bounds=[[1, 5], [273.15, 323.15], ], levels=[5, 5]) designer_1.ti_controls_candidates = tic print(np.array2string(tic, separator=',')) figure2 = plt.figure(2) plt.scatter(tic[:, 0], tic[:, 1], ) plt.xlabel(r"$C_A^0\quad (\frac{mol}{L})$") plt.ylabel("$T\quad (k)$") spt = np.array([np.linspace(0, 1, 11) for _ in tic])
from pydex.core.designer import Designer from case_5_model import simulate import numpy as np designer = Designer() designer.simulate = simulate tic = designer.enumerate_candidates( bounds=[ [273.15, 323.15], ], levels=[ 11, ], ) designer.ti_controls_candidates = tic spt = np.array([np.linspace(0, 10, 21) for _ in tic]) designer.sampling_times_candidates = spt designer._num_steps = 7 # nominal at 1, 1 if False: mp = [1, 3, -1, 5] # uncertain uniform if True: mp = np.random.uniform( low=[0, 2, -2, 4], high=[2, 4, 0, 6],
# constant term model_parameters[0] + # linear term model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[1] + model_parameters[3] * ti_controls[2] + # 2-interaction term model_parameters[4] * ti_controls[0] * ti_controls[1] + model_parameters[5] * ti_controls[0] * ti_controls[2] + model_parameters[6] * ti_controls[1] * ti_controls[2] + # 3-interaction term model_parameters[7] * ti_controls[0] * ti_controls[1] * ti_controls[2] ]) designer_1 = Designer() designer_1.simulate = simulate reso = 5 tic = designer_1.create_grid(bounds=np.array([(-1, 1), (-1, 1), (-1, 1)]), levels=np.array([reso, reso, reso])) designer_1.ti_controls_candidates = tic designer_1.model_parameters = np.ones( 8) # values won't affect design, but still needed designer_1.initialize( verbose=2) # 0: silent, 1: overview, 2: detailed, 3: very detailed designer_1.design_exact_experiment(designer_1.d_opt_criterion, number_of_experiments=10,
Problem : design optimal experiment for a order 1 polynomial. Solution : a 2^4 factorial design. """ def simulate(ti_controls, model_parameters): return np.array([ # constant model_parameters[0] + # linear model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[1] + model_parameters[3] * ti_controls[2] + model_parameters[4] * ti_controls[3] ]) designer = Designer() designer.simulate = simulate designer.model_parameters = np.ones(5) designer.ti_controls_candidates = designer.enumerate_candidates( bounds=[ [-1, 1], [-1, 1], [-1, 1], [-1, 1], ], levels=[ 5, 5, 5, 5, ],
from real_model import candidates1, data1 from matplotlib import pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np candidate = candidates1 data = data1 def simulate(ti_controls, model_parameters): x1, x2 = ti_controls return np.array([ x1 * np.exp(-model_parameters[0] * x2), 1 - x1 * np.exp(-model_parameters[0] * x2), ]) designer = Designer() designer.simulate = simulate designer.model_parameters = [5] designer.ti_controls_candidates = candidate designer.data = data designer.initialize(verbose=2) designer.estimate_parameters( bounds=[ [-1e2, 1e2], ], write=False, update_parameters=True, ftol=1e-15, xtol=1e-15, gtol=1e-15, )
from pydex.core.designer import Designer from case_2_model import simulate import numpy as np designer_1 = Designer() designer_1.simulate = simulate """ specifying nominal model parameter values """ pre_exp_constant = 0.1 activ_energy = 5000 theta_0 = np.log(pre_exp_constant) - activ_energy / (8.314159 * 273.15) theta_1 = activ_energy / (8.314159 * 273.15) theta_nom = np.array([theta_0, theta_1, 1, 0.5]) # value of theta_0, theta_1, alpha_a, nu designer_1.model_parameters = theta_nom # assigning it to the designer's theta """ creating experimental candidates, here, it is generated as a grid """ tic = designer_1.enumerate_candidates( bounds=[ [1, 5], # initial C_A concentration [273.15, 323.15] # reaction temperature ], levels=[ 11, # initial C_A concentration 11, # reaction temperature ], ) designer_1.ti_controls_candidates = tic # defining sampling time candidates spt_candidates = np.array([np.linspace(0, 200, 11) for _ in tic]) designer_1.sampling_times_candidates = spt_candidates
y0=ti_controls[0], t=sampling_times, tfirst=True) ca = sol[:, 0] return ca def dca_dt(t, ca, theta, a): dca_dt = -theta[0] * ca return dca_dt if __name__ == '__main__': """ create a designer """ problem_size = [] designer_1 = Designer( ) # without explicit dimension, one extra ODE evaluation """ overwrite the designer's simulate function """ designer_1.simulate = simulate """ specifying nominal model parameter """ theta_nom = np.array([0.25]) # value of beta, has to be an array designer_1.model_parameters = theta_nom # assigning it to the designer's theta """ creating experimental candidates, here, it is generated as a grid """ n_s_times = 10 # number of equally-spaced sampling time candidates n_c = 10 # grid resolution of control candidates generated # defining the same sampling time candidates for all experimental candidates tau_upper = 20 tau_lower = 0 sampling_times_candidates = np.array( [np.linspace(tau_lower, tau_upper, n_s_times) for _ in range(n_c)])
# constant term model_parameters[0] + # linear term model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[1] + model_parameters[3] * ti_controls[2] + # 2-interaction term model_parameters[4] * ti_controls[0] * ti_controls[1] + model_parameters[5] * ti_controls[0] * ti_controls[2] + model_parameters[6] * ti_controls[1] * ti_controls[2] + # 3-interaction term model_parameters[7] * ti_controls[0] * ti_controls[1] * ti_controls[2] ]) designer_1 = Designer() designer_1.simulate = simulate reso = 11j tic_1, tic_2, tic_3 = np.mgrid[-1:1:reso, -1:1:reso, -1:1:reso] tic_1 = tic_1.flatten() tic_2 = tic_2.flatten() tic_3 = tic_3.flatten() designer_1.ti_controls_candidates = np.array([tic_1, tic_2, tic_3]).T designer_1.model_parameters = np.ones(8) # values won't affect design, but still needed designer_1.initialize(verbose=2) # 0: silent, 1: overview, 2: detailed, 3: very detailed designer_1.design_experiment(designer_1.d_opt_criterion, write=False)
if False: t = np.arange(0, 72, 0.75) y = simulate([{0: 0.2}, {0: 35}], t, [0.31, 0.18, 0.55, 0.03]) # monod fig = plt.figure() axes = fig.add_subplot(111) axes.scatter(t, y[:, 0], label="biomass") axes.scatter(t, y[:, 1], label="substrate") axes.set_xlim([0, 80]) axes.set_ylim([0, 30]) axes.legend() plt.show() designer = Designer() designer.simulate = simulate designer.model_parameters = np.array([0.31, 0.18, 0.55, 0.03]) tic, tvc = designer.enumerate_candidates(bounds=np.array([ [0, 0.5], [5, 35], ]), levels=np.array([ 3, 3, ]), switching_times=np.array([ np.linspace(0, 72, 4), np.linspace(0, 72, 1), ])) designer.ti_controls_candidates = tic
def simulate(ti_controls, model_parameters): return np.array([ # constant term model_parameters[0] + # linear term model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[1] + # interaction term model_parameters[3] * ti_controls[0] * ti_controls[1] + # squared terms model_parameters[4] * ti_controls[0]**2 + model_parameters[5] * ti_controls[1]**2 ]) designer_1 = Designer() designer_1.simulate = simulate designer_1.model_parameters = np.ones( 6) # values won't affect design, but still needed """ initializing initial grid """ reso = 41j tic_1, tic_2 = np.mgrid[-1:1:reso, -1:1:reso] tic_1 = tic_1.flatten() tic_2 = tic_2.flatten() tic = np.array([tic_1, tic_2]).T package, optimizer = ("cvxpy", "MOSEK") criterion = designer_1.a_opt_criterion """ FOLIUM """ # filtering initial grid
import numpy as np from pydex.core.designer import Designer def simulate(ti_controls, model_parameters): return np.array( [model_parameters[0] * np.exp(model_parameters[1] * ti_controls[0])]) designer = Designer() designer.simulate = simulate reso = 21j tic = np.mgrid[0:0.5:reso] designer.ti_controls_candidates = np.array([tic]).T np.random.seed(123) n_scr = 200 designer.model_parameters = np.random.multivariate_normal( mean=[10, -5], cov=np.array([ [2**2, 0.00], [0.00, 1.5**2], ]), size=n_scr, ) designer._num_steps = 6 designer.start_logging() designer.initialize(verbose=2)
import numpy as np from pydex.core.designer import Designer def simulate(ti_controls, model_parameters): return np.array([ np.exp(model_parameters[0] * ti_controls[0]) ]) designer = Designer() designer.simulate = simulate reso = 21j tic = np.mgrid[0:1:reso] designer.ti_controls_candidates = np.array([tic]).T np.random.seed(123) n_scr = 100 designer.model_parameters = np.random.normal(loc=-1, scale=0.50, size=(n_scr, 1)) designer.initialize(verbose=2) """ Pseudo-bayesian type do not really matter in this case because only a single model parameter is involved i.e, information is a scalar, all criterion becomes equivalent to the information matrix itself. """ pb_type = 0 # pb_type = 1
from case_6_hgp_tvc_model import simulate_hgp from pydex.core.designer import Designer import numpy as np designer = Designer() designer.simulate = simulate_hgp tic, tvc = designer.enumerate_candidates( bounds=[ [100, 200], [1, 10], [21.980, 22], ], levels=[ 1, 1, 5, ], switching_times=[ None, None, np.linspace(0, 1, 5)[:-1], ], ) designer.ti_controls_candidates = tic designer.tv_controls_candidates = tvc designer.sampling_times_candidates = [np.linspace(0, 24 * 14, 11) for _ in tic] mp = [ 3.1, # estimated gas in place in 10^12 m3 - taken from wikipedia page of Ghawar field on 2020-12-25 ] designer.model_parameters = mp
import numpy as np from pydex.core.designer import Designer def simulate(ti_controls, model_parameters): return np.array( [model_parameters[0] * np.exp(model_parameters[1] * ti_controls[0])]) designer = Designer() designer.simulate = simulate reso = 21j tic = np.mgrid[0:1:reso] designer.ti_controls_candidates = np.array([tic]).T np.random.seed(123) n_scr = 100 designer.model_parameters = np.random.multivariate_normal( mean=[1, -1], cov=np.array([ [0.2**2, 0.00], [0.00, 0.2**2], ]), size=n_scr, ) designer.initialize(verbose=2) """ Pseudo-bayesian type do not really matter in this case because only a single model parameter is involved i.e, information is a scalar, all criterion becomes equivalent to the information matrix itself.
return m.dca_dt[t] / m.tau == -m.beta * m.ca[t] model.material_balance = po.Constraint(model.t, rule=_material_balance) return model def create_simulator(model, package): return pod.Simulator(model, package=package) if __name__ == '__main__': """ create a pyomo model """ model_1 = create_model() """ create a designer """ designer_1 = Designer() """ pass pyomo model and simulator to designer """ designer_1.model = model_1 designer_1.simulator = create_simulator(model_1, package='casadi') """ overwrite the designer's simulate function """ designer_1.simulate = simulate """ specifying nominal model parameter """ theta_nom = np.array([0.25]) # value of beta, has to be an array designer_1.model_parameters = theta_nom # assigning it to the designer's theta """ creating experimental candidates, here, it is generated as a grid """ n_s_times = 10 # number of equally-spaced sampling time candidates n_c = 10 # grid resolution of control candidates generated # defining sampling time candidates tau_upper = 20 tau_lower = 0
import numpy as np from pydex.core.designer import Designer def simulate(ti_controls, model_parameters): return np.array( [model_parameters[0] * np.exp(model_parameters[1] * ti_controls[0])]) designer = Designer() designer.simulate = simulate reso = 21j tic = np.mgrid[0:1:reso] designer.ti_controls_candidates = np.array([tic]).T designer.model_parameters = [1, -1] designer.initialize(verbose=2) """ Pseudo-bayesian type do not really matter in this case because only a single model parameter is involved i.e, information is a scalar, all criterion becomes equivalent to the information matrix itself. """ designer.design_experiment( designer.d_opt_criterion, write=False, package="cvxpy", optimizer="MOSEK",
~ dg, ag, eg criteria: OFAT experiments ~ di, ai, ei criteria: 2^2 factorial design """ def simulate(ti_controls, model_parameters): return np.array([ # constant term model_parameters[0] + # linear term model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[1] ]) designer = Designer() designer.simulate = simulate designer.model_parameters = np.ones( 3) # values won't affect design, but still needed designer.ti_controls_candidates = designer.enumerate_candidates( bounds=[ [-1, 1], [-1, 1], ], levels=[ 11, 11, ], ) designer.initialize( verbose=2) # 0: silent, 1: overview, 2: detailed, 3: very detailed
def simulate(ti_controls, model_parameters): return np.array([ # constant term model_parameters[0] + # linear term model_parameters[1] * ti_controls[0] + model_parameters[2] * ti_controls[1] + # interaction term model_parameters[3] * ti_controls[0] * ti_controls[1] + # squared terms model_parameters[4] * ti_controls[0]**2 + model_parameters[5] * ti_controls[1]**2 ]) designer_1 = Designer() designer_1.simulate = simulate reso = 11j tic_1, tic_2 = np.mgrid[-1:1:reso, -1:1:reso] tic_1 = tic_1.flatten() tic_2 = tic_2.flatten() designer_1.ti_controls_candidates = np.array([tic_1, tic_2]).T designer_1.model_parameters = np.ones( 6) # values won't affect design, but still needed designer_1.initialize( verbose=2) # 0: silent, 1: overview, 2: detailed, 3: very detailed """ cvxpy solvers """ package, optimizer = ("cvxpy", "MOSEK")
""" def simulate(ti_controls, model_parameters): return np.array([ model_parameters[0] + model_parameters[1] * np.exp(-1 * ti_controls[0]) + model_parameters[2] * np.exp(1 * ti_controls[0]) + model_parameters[3] * np.exp(-1 * ti_controls[1]) + model_parameters[4] * np.exp(1 * ti_controls[1]) ]) designer_1 = Designer() designer_1.simulate = simulate reso = 11 tic = designer_1.create_grid([[-1, 1], [-1, 1]], [reso, reso]) designer_1.ti_controls_candidates = tic designer_1.model_parameters = np.ones(5) # values won't affect design, but still needed designer_1.initialize(verbose=2) # 0: silent, 1: overview, 2: detailed, 3: very detailed designer_1.design_experiment(designer_1.d_opt_criterion, write=False) designer_1.print_optimal_candidates() designer_1.plot_optimal_efforts() designer_1.plot_optimal_controls()