{ "cells": [ { "cell_type": "markdown", "id": "f17a116a", "metadata": {}, "source": [ "# Design Space Exploration\n", "\n", "In this demonstration we show how we can leverage the `OptProblem` class from the `standard_evaluator` library to perform optimization studies that can be version controlled. \n", "\n", "![Design Space Exploration (running multiple optimizations) process](design_space_exploration.drawio.png)\n", "\n", "The idea is that we will want to run multiple optimization problems that are driven by JSOn files that we can version control. In a future step we will also manage the assembly information itself in a JSON file that can be version controlled, but for this demonstration we went down an easier path.\n", "\n", "We first load all required libraries and methods." ] }, { "cell_type": "code", "execution_count": 1, "id": "acef51ce-e90f-43a3-9716-ecb16167b371", "metadata": { "metadata": {} }, "outputs": [], "source": [ "import typing\n", "import openmdao.api as om\n", "import openmdao.core.system as oms\n", "import pandas as pd\n", "\n", "from standard_evaluator import get_interface, show_structure, create_problem, get_state, set_state, load_state, save_state\n", "from standard_evaluator import load_assembly, save_assembly, convert_om_var, get_opt_problem, set_opt_problem\n", "from standard_evaluator import Variable, FloatVariable, IntVariable, ArrayVariable, OptProblem" ] }, { "cell_type": "markdown", "id": "763bdf4f-e824-456c-898f-1513dcff5e7c", "metadata": {}, "source": [ "## Creating the OpenMDAO assembly\n", "\n", "In this example we use the Sellar Problem from the [OpenMDAO documentation](https://openmdao.org/newdocs/versions/latest/basic_user_guide/multidisciplinary_optimization/sellar_opt.html). \n", "\n", "We first setup the assembly, set the optimization variables, constraints, and the objective. We can then run the optimization." ] }, { "cell_type": "code", "execution_count": 2, "id": "d9bdb3c0", "metadata": { "metadata": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 3.183393951729169\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "minimum found at\n", "0.0\n", "[1.97763888e+00 8.83056605e-15]\n", "minumum objective\n", "3.183393951729169\n" ] } ], "source": [ "import numpy as np\n", "import openmdao.api as om\n", "\n", "from openmdao.test_suite.components.sellar import SellarDis1, SellarDis2\n", "\n", "\n", "class SellarMDA(om.Group):\n", " \"\"\"\n", " Group containing the Sellar MDA.\n", " \"\"\"\n", "\n", " def setup(self):\n", " cycle = self.add_subsystem('cycle', om.Group(), promotes=['*'])\n", " cycle.add_subsystem('d1', SellarDis1(), promotes_inputs=['x', 'z', 'y2'],\n", " promotes_outputs=['y1'])\n", " cycle.add_subsystem('d2', SellarDis2(), promotes_inputs=['z', 'y1'],\n", " promotes_outputs=['y2'])\n", "\n", " cycle.set_input_defaults('x', 1.0)\n", " cycle.set_input_defaults('z', np.array([5.0, 2.0]))\n", "\n", " # Nonlinear Block Gauss Seidel is a gradient free solver\n", " cycle.nonlinear_solver = om.NonlinearBlockGS()\n", "\n", " self.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n", " z=np.array([0.0, 0.0]), x=0.0),\n", " promotes=['x', 'z', 'y1', 'y2', 'obj'])\n", "\n", " self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n", " self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])\n", "\n", "class SellarMDA(om.Group):\n", " \"\"\"\n", " Group containing the Sellar MDA.\n", " \"\"\"\n", "\n", " def setup(self):\n", " cycle = self.add_subsystem('cycle', om.Group(), promotes=['*'])\n", " cycle.add_subsystem('d1', SellarDis1(), promotes_inputs=['x', 'z', 'y2'],\n", " promotes_outputs=['y1'])\n", " cycle.add_subsystem('d2', SellarDis2(), promotes_inputs=['z', 'y1'],\n", " promotes_outputs=['y2'])\n", "\n", " cycle.set_input_defaults('x', 1.0)\n", " cycle.set_input_defaults('z', np.array([5.0, 2.0]))\n", "\n", " # Nonlinear Block Gauss Seidel is a gradient free solver\n", " cycle.nonlinear_solver = om.NonlinearBlockGS()\n", "\n", " self.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n", " z=np.array([0.0, 0.0]), x=0.0),\n", " promotes=['x', 'z', 'y1', 'y2', 'obj'])\n", "\n", " self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n", " self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])\n", "\n", "import openmdao.api as om\n", "from openmdao.test_suite.components.sellar_feature import SellarMDA\n", "\n", "prob = om.Problem()\n", "prob.model = SellarMDA()\n", "\n", "prob.driver = om.ScipyOptimizeDriver()\n", "prob.driver.options['optimizer'] = 'SLSQP'\n", "# prob.driver.options['maxiter'] = 100\n", "prob.driver.options['tol'] = 1e-8\n", "\n", "prob.model.add_design_var('x', lower=0, upper=10)\n", "prob.model.add_design_var('z', lower=0, upper=10)\n", "prob.model.add_objective('obj')\n", "prob.model.add_constraint('con1', upper=0)\n", "prob.model.add_constraint('con2', upper=0)\n", "\n", "# Ask OpenMDAO to finite-difference across the model to compute the gradients for the optimizer\n", "prob.model.approx_totals()\n", "\n", "prob.setup()\n", "prob.set_solver_print(level=0)\n", "\n", "prob.run_driver()\n", "\n", "print('minimum found at')\n", "print(prob.get_val('x')[0])\n", "print(prob.get_val('z'))\n", "\n", "print('minumum objective')\n", "print(prob.get_val('obj')[0])" ] }, { "cell_type": "markdown", "id": "44266398", "metadata": {}, "source": [ "In the next step we get the description of the optimization problem and store that in an instance of the neutral `OptProblem`. We also capture the structure of the assembly in the neutral format.\n", "\n", "We show the content of the `original_opt` variable," ] }, { "cell_type": "code", "execution_count": 3, "id": "c4baddaf", "metadata": { "metadata": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Warning: More work is needed to support array variables\n" ] }, { "data": { "text/plain": [ "OptProblem(name='opt_problem', class_type='OptProblem', variables=[FloatVariable(name='x', default=None, bounds=(0.0, 10.0), shift=0.0, scale=1.0, units=None, description='', options={'parallel_deriv_color': None}, class_type='float'), ArrayVariable(name='z', default=None, bounds=(array([0., 0.]), array([10., 10.])), shift=array([0., 0.]), scale=array([1., 1.]), units=None, description='', options={'parallel_deriv_color': None}, class_type='floatarray', shape=(2,))], responses=[FloatVariable(name='con1', default=None, bounds=(-1e+30, 0.0), shift=0.0, scale=1.0, units=None, description='', options={'parallel_deriv_color': None}, class_type='float'), FloatVariable(name='con2', default=None, bounds=(-1e+30, 0.0), shift=0.0, scale=1.0, units=None, description='', options={'parallel_deriv_color': None}, class_type='float'), FloatVariable(name='obj', default=None, bounds=(-inf, inf), shift=0.0, scale=1.0, units=None, description='', options={'parallel_deriv_color': None}, class_type='float')], objectives=['obj'], constraints=['con1', 'con2'], description=None, cite=None, options={})" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "original_opt = get_opt_problem(prob)\n", "info = get_interface(prob.model)\n", "original_opt" ] }, { "cell_type": "markdown", "id": "6376615a", "metadata": {}, "source": [ "## Setting up a series of optimization studies\n", "\n", "In the next step we take the original optimization problem and create a series of optimization problems where we change the upper bound of the first nonlinear constraint. This is a typical scenario in industry, we are trying to explore the design space and often the constraints are not fully defined.\n", "\n", "We store all of the optimization problems in JSON files. This will allow us to fully describe the studies we are doing, and they can be version controlled. " ] }, { "cell_type": "code", "execution_count": 8, "id": "38f38d48", "metadata": { "metadata": {} }, "outputs": [], "source": [ "import json\n", "\n", "bound_values = [-3.5, -2.5, -1.5, -.5, -.4, -.3, -.2, -.1, 0.0, .1, .2]\n", "indx = 0\n", "for upper in bound_values:\n", " new_opt = original_opt.model_copy()\n", " new_opt.responses[0].bounds = (-np.inf, upper)\n", " optproblem_name = f'optproblem{indx:02}.json'\n", " indx += 1\n", " # Convert and write JSON object to file\n", " with open(optproblem_name, \"w\") as outfile:\n", " json.dump(new_opt.model_dump(exclude_unset=True), outfile, indent=2, skipkeys=True)\n" ] }, { "cell_type": "markdown", "id": "16cd0670", "metadata": {}, "source": [ "## Running a series of optimization problems\n", "\n", "In the next step we actually run the different optimization problems. To do this we first create a pattern for all the optimization files, and get the names of all of them.\n", "\n", "Then we run a loop through all the file names, first loading the optimization problem formulation into a dictionary, convert it into `OptProblem`'s, create a new instance of the Sellar problem, set the optimization problem, the optimzition parameters, and run the optimization. We store the results from the optimization in a Pandas DataFrame together with the name of the file that defined the specific optimization problem.\n", "\n", "After running all the optimizations we combine the results into a single DataFrame, and show the summary." ] }, { "cell_type": "code", "execution_count": 9, "id": "8a7cf9a4", "metadata": { "metadata": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 6.664694351674094\n", " Iterations: 5\n", " Function evaluations: 6\n", " Gradient evaluations: 5\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 5.667025907351937\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 4.670917299584386\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 3.677841549628989\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 3.5788057528834227\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 3.4798368284597276\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 3.380940701913713\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 3.2821239617838844\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 3.183393951729169\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 3.08475887838721\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n", "Optimization terminated successfully (Exit mode 0)\n", " Current function value: 2.9862279381209578\n", " Iterations: 6\n", " Function evaluations: 6\n", " Gradient evaluations: 6\n", "Optimization Complete\n", "-----------------------------------\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
y1y2zxcon1con2objname
06.665.361395[2.7806975800167444, 3.051394295571152e-12]0.0-3.5-18.6386056.664694optproblem00.json
05.664.958151[2.5790754506581415, 6.221918747285027e-13]0.0-2.5-19.0418495.667026optproblem01.json
04.664.517407[2.358703314489707, 1.2497789641957312e-13]0.0-1.5-19.4825934.670917optproblem02.json
03.664.026225[2.1131126469752384, 0.0]0.0-0.5-19.9737753.677842optproblem03.json
03.563.973592[2.086796226417705, 0.0]0.0-0.4-20.0264083.578806optproblem04.json
03.463.920215[2.060107523783193, 0.0]0.0-0.3-20.0797853.479837optproblem05.json
03.363.866061[2.0330302779941305, 6.990458292776596e-15]0.0-0.2-20.1339393.380941optproblem06.json
03.263.811094[2.0055470085439713, 5.500933528914423e-15]0.0-0.1-20.1889063.282124optproblem07.json
03.163.755278[1.977638883487764, 8.830566052859473e-15]0.0-0.0-20.2447223.183394optproblem08.json
03.063.698571[1.9492855684910377, 0.0]0.00.1-20.3014293.084759optproblem09.json
02.963.64093[1.9204650534922432, 5.9424529525480574e-15]0.00.2-20.359072.986228optproblem10.json
\n", "
" ], "text/plain": [ " y1 y2 z x con1 \\\n", "0 6.66 5.361395 [2.7806975800167444, 3.051394295571152e-12] 0.0 -3.5 \n", "0 5.66 4.958151 [2.5790754506581415, 6.221918747285027e-13] 0.0 -2.5 \n", "0 4.66 4.517407 [2.358703314489707, 1.2497789641957312e-13] 0.0 -1.5 \n", "0 3.66 4.026225 [2.1131126469752384, 0.0] 0.0 -0.5 \n", "0 3.56 3.973592 [2.086796226417705, 0.0] 0.0 -0.4 \n", "0 3.46 3.920215 [2.060107523783193, 0.0] 0.0 -0.3 \n", "0 3.36 3.866061 [2.0330302779941305, 6.990458292776596e-15] 0.0 -0.2 \n", "0 3.26 3.811094 [2.0055470085439713, 5.500933528914423e-15] 0.0 -0.1 \n", "0 3.16 3.755278 [1.977638883487764, 8.830566052859473e-15] 0.0 -0.0 \n", "0 3.06 3.698571 [1.9492855684910377, 0.0] 0.0 0.1 \n", "0 2.96 3.64093 [1.9204650534922432, 5.9424529525480574e-15] 0.0 0.2 \n", "\n", " con2 obj name \n", "0 -18.638605 6.664694 optproblem00.json \n", "0 -19.041849 5.667026 optproblem01.json \n", "0 -19.482593 4.670917 optproblem02.json \n", "0 -19.973775 3.677842 optproblem03.json \n", "0 -20.026408 3.578806 optproblem04.json \n", "0 -20.079785 3.479837 optproblem05.json \n", "0 -20.133939 3.380941 optproblem06.json \n", "0 -20.188906 3.282124 optproblem07.json \n", "0 -20.244722 3.183394 optproblem08.json \n", "0 -20.301429 3.084759 optproblem09.json \n", "0 -20.35907 2.986228 optproblem10.json " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "solutions = []\n", "import glob\n", "\n", "# Specify the pattern for the JSON files\n", "pattern = 'optproblem*.json'\n", "\n", "# Use glob to find all files matching the pattern\n", "json_files = glob.glob(pattern)\n", "\n", "# Loop through the list of files and load each JSON file\n", "data_list = []\n", "for file in json_files:\n", " with open(file, 'r') as f:\n", " data = json.load(f) # Load the JSON data\n", " new_opt = OptProblem.model_validate(data)\n", " new_prob = om.Problem()\n", " new_prob.model = SellarMDA()\n", "\n", " # Setting the optimization problem\n", " set_opt_problem(new_prob, new_opt)\n", "\n", " # Setting the optimizer options.\n", " new_prob.driver = om.ScipyOptimizeDriver()\n", " new_prob.driver.options['optimizer'] = 'SLSQP'\n", " # prob.driver.options['maxiter'] = 100\n", " new_prob.driver.options['tol'] = 1e-8\n", "\n", " # Ask OpenMDAO to finite-difference across the model to compute the gradients for the optimizer\n", " new_prob.model.approx_totals()\n", "\n", " new_prob.set_solver_print(level=0)\n", "\n", " # Run the optimization\n", " new_prob.run_driver()\n", "\n", " # Get the state of the assembly, which will be the optimization solution\n", " state = get_state(new_prob, info)\n", " # We will store the solution in a dictionary, including the name of the file.\n", " state = {key: value.flatten()[0] if len(value) == 1 else value for key, value in state.items()}\n", " state['name'] = file\n", "\n", " # Convert the dictionary to a Pandas Series, and store as a DataFrame\n", " solutions.append(pd.Series(state).to_frame().T)\n", "\n", "# Combine all the solutions into a single DataFrame\n", "df = pd.concat(solutions)\n", "# Show the result DataFrame\n", "df\n" ] }, { "cell_type": "markdown", "id": "a66b228a", "metadata": {}, "source": [ "Since in this example we only varied one constraint we can create a plot showing the impact of the change of the constraint on the value of the objective function, which is what we show next to finish this demonstration." ] }, { "cell_type": "code", "execution_count": 10, "id": "327ce5d1", "metadata": { "metadata": {} }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "# Ensure that plots are displayed inline in Jupyter Notebook\n", "%matplotlib inline\n", "\n", "# Plotting con1 vs obj\n", "plt.figure(figsize=(8, 5)) # Optional: Set the figure size\n", "plt.plot(df['con1'], df['obj'], marker='o', linestyle='-', color='b') # Line plot with markers\n", "plt.title('con1 vs obj') # Title of the plot\n", "plt.xlabel('con1') # Label for x-axis\n", "plt.ylabel('obj') # Label for y-axis\n", "plt.grid() # Optional: Add a grid\n", "plt.show() # Display the plot" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 5 }