|
| 1 | +# ___________________________________________________________________________ |
| 2 | +# |
| 3 | +# Pyomo: Python Optimization Modeling Objects |
| 4 | +# Copyright (c) 2008-2025 |
| 5 | +# National Technology and Engineering Solutions of Sandia, LLC |
| 6 | +# Under the terms of Contract DE-NA0003525 with National Technology and |
| 7 | +# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain |
| 8 | +# rights in this software. |
| 9 | +# This software is distributed under the 3-clause BSD License. |
| 10 | +# ___________________________________________________________________________ |
| 11 | +from pyomo.common.dependencies import numpy as np |
| 12 | + |
| 13 | +from pyomo.contrib.doe.examples.reactor_experiment import ReactorExperiment |
| 14 | +from pyomo.contrib.doe import DesignOfExperiments |
| 15 | + |
| 16 | +import pyomo.environ as pyo |
| 17 | + |
| 18 | +import json |
| 19 | +from pathlib import Path |
| 20 | + |
| 21 | + |
| 22 | +# Example for sensitivity analysis on the reactor experiment |
| 23 | +# After sensitivity analysis is done, we perform optimal DoE |
| 24 | +def run_reactor_doe(): |
| 25 | + # Read in file |
| 26 | + DATA_DIR = Path(__file__).parent |
| 27 | + file_path = DATA_DIR / "result.json" |
| 28 | + |
| 29 | + with open(file_path) as f: |
| 30 | + data_ex = json.load(f) |
| 31 | + |
| 32 | + # Put temperature control time points into correct format for reactor experiment |
| 33 | + data_ex["control_points"] = { |
| 34 | + float(k): v for k, v in data_ex["control_points"].items() |
| 35 | + } |
| 36 | + |
| 37 | + # Create a ReactorExperiment object; data and discretization information are part |
| 38 | + # of the constructor of this object |
| 39 | + experiment = ReactorExperiment(data=data_ex, nfe=10, ncp=3) |
| 40 | + |
| 41 | + # Use a central difference, with step size 1e-3 |
| 42 | + fd_formula = "central" |
| 43 | + step_size = 1e-3 |
| 44 | + |
| 45 | + # Use the minimum_eigenvalue objective with scaled sensitivity matrix |
| 46 | + objective_option = "minimum_eigenvalue" |
| 47 | + scale_nominal_param_value = True |
| 48 | + |
| 49 | + # Create the DesignOfExperiments object |
| 50 | + # We will not be passing any prior information in this example |
| 51 | + # and allow the experiment object and the DesignOfExperiments |
| 52 | + # call of ``run_doe`` perform model initialization. |
| 53 | + doe_obj = DesignOfExperiments( |
| 54 | + experiment, |
| 55 | + fd_formula=fd_formula, |
| 56 | + step=step_size, |
| 57 | + objective_option=objective_option, |
| 58 | + scale_constant_value=1, |
| 59 | + scale_nominal_param_value=scale_nominal_param_value, |
| 60 | + prior_FIM=None, |
| 61 | + jac_initial=None, |
| 62 | + fim_initial=None, |
| 63 | + L_diagonal_lower_bound=1e-7, |
| 64 | + solver=None, |
| 65 | + tee=True, |
| 66 | + get_labeled_model_args=None, |
| 67 | + _Cholesky_option=False, |
| 68 | + _only_compute_fim_lower=True, |
| 69 | + ) |
| 70 | + |
| 71 | + # Make design ranges to compute the full factorial design |
| 72 | + design_ranges = {"CA[0]": [1, 5, 9], "T[0]": [300, 700, 9]} |
| 73 | + |
| 74 | + # Compute the full factorial design with the sequential FIM calculation |
| 75 | + doe_obj.compute_FIM_full_factorial(design_ranges=design_ranges, method="sequential") |
| 76 | + |
| 77 | + # Plot the results |
| 78 | + # doe_obj.draw_factorial_figure( |
| 79 | + # sensitivity_design_variables=["CA[0]", "T[0]"], |
| 80 | + # fixed_design_variables={ |
| 81 | + # "T[0.125]": 300, |
| 82 | + # "T[0.25]": 300, |
| 83 | + # "T[0.375]": 300, |
| 84 | + # "T[0.5]": 300, |
| 85 | + # "T[0.625]": 300, |
| 86 | + # "T[0.75]": 300, |
| 87 | + # "T[0.875]": 300, |
| 88 | + # "T[1]": 300, |
| 89 | + # }, |
| 90 | + # title_text="Reactor Example", |
| 91 | + # xlabel_text="Concentration of A (M)", |
| 92 | + # ylabel_text="Initial Temperature (K)", |
| 93 | + # figure_file_name="example_reactor_compute_FIM", |
| 94 | + # log_scale=False, |
| 95 | + # ) |
| 96 | + |
| 97 | + ########################### |
| 98 | + # End sensitivity analysis |
| 99 | + |
| 100 | + # Begin optimal DoE |
| 101 | + #################### |
| 102 | + doe_obj.run_doe() |
| 103 | + |
| 104 | + # Print out a results summary |
| 105 | + print("Optimal experiment values: ") |
| 106 | + print( |
| 107 | + "\tInitial concentration: {:.2f}".format( |
| 108 | + doe_obj.results["Experiment Design"][0] |
| 109 | + ) |
| 110 | + ) |
| 111 | + print( |
| 112 | + ("\tTemperature values: [" + "{:.2f}, " * 8 + "{:.2f}]").format( |
| 113 | + *doe_obj.results["Experiment Design"][1:] |
| 114 | + ) |
| 115 | + ) |
| 116 | + #print(doe_obj.results["Experiment Design"][1:]) |
| 117 | + print("FIM at optimal design:\n {}".format(np.array(doe_obj.results["FIM"]))) |
| 118 | + print( |
| 119 | + "Objective value at optimal design: {:.2f}".format( |
| 120 | + pyo.value(doe_obj.model.objective) |
| 121 | + ) |
| 122 | + ) |
| 123 | + |
| 124 | + print(doe_obj.results["Experiment Design Names"]) |
| 125 | + print(doe_obj.results["log10 E-opt"]) |
| 126 | + |
| 127 | + doe_obj.model.obj_cons.pprint() |
| 128 | + doe_obj.model.fim.pprint() |
| 129 | + doe_obj.model.minimum_diagonal.pprint() |
| 130 | + doe_obj.model.objective.pprint() |
| 131 | + |
| 132 | + ################### |
| 133 | + # End optimal DoE |
| 134 | + |
| 135 | + |
| 136 | +if __name__ == "__main__": |
| 137 | + run_reactor_doe() |
0 commit comments