{ "cells": [ { "cell_type": "markdown", "id": "07234160", "metadata": {}, "source": [ "\n", "*This notebook contains material from [CBE60499](https://ndcbe.github.io/CBE60499);\n", "content is available [on Github](git@github.com:ndcbe/CBE60499.git).*\n" ] }, { "cell_type": "markdown", "id": "f2c995ee", "metadata": {}, "source": [ "\n", "< [2.1 Continuous Optimization](https://ndcbe.github.io/CBE60499/02.01-LP-NLP.html) | [Contents](toc.html) | [Tag Index](tag_index.html) | [2.3 Logical Modeling and Generalized Disjunctive Programs](https://ndcbe.github.io/CBE60499/02.03-GDP.html) >
"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 1,
"link": "[2.2 Integer Programs](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2-Integer-Programs)",
"section": "2.2 Integer Programs"
}
},
"source": [
"# 2.2 Integer Programs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"nbpages": {
"level": 1,
"link": "[2.2 Integer Programs](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2-Integer-Programs)",
"section": "2.2 Integer Programs"
}
},
"outputs": [],
"source": [
"# This code cell installs packages on Colab\n",
"\n",
"import sys\n",
"if \"google.colab\" in sys.modules:\n",
" !wget \"https://raw.githubusercontent.com/ndcbe/CBE60499/main/notebooks/helper.py\"\n",
" import helper\n",
" helper.install_idaes()\n",
" helper.install_ipopt()\n",
" helper.install_glpk()\n",
" helper.install_cbc()\n",
" helper.download_figures(['feasible.png'])"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[2.2.1 Optimizing Across Process Alternatives](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1-Optimizing-Across-Process-Alternatives)",
"section": "2.2.1 Optimizing Across Process Alternatives"
}
},
"source": [
"## 2.2.1 Optimizing Across Process Alternatives"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[2.2.1 Optimizing Across Process Alternatives](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1-Optimizing-Across-Process-Alternatives)",
"section": "2.2.1 Optimizing Across Process Alternatives"
}
},
"source": [
"Reference: Example 15.3 from Biegler, Grossmann, Westerberg (1997)."
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[2.2.1 Optimizing Across Process Alternatives](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1-Optimizing-Across-Process-Alternatives)",
"section": "2.2.1 Optimizing Across Process Alternatives"
}
},
"source": [
"Assume that we have the choice of selecting two reactors (shown below) for the reaction $A \\rightarrow B$. Reactor I has a higher conversation (80%) but it is more expensive; reactor II has a lower conversion (66.7%) but is cheaper. The cost of feed $A$ is \\$5/kmol. Which process alternative (reactor I, reactor II, or both) has the minimum costs to make 10 kmol/hr of product B?"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[2.2.1 Optimizing Across Process Alternatives](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1-Optimizing-Across-Process-Alternatives)",
"section": "2.2.1 Optimizing Across Process Alternatives"
}
},
"source": [
"Let $x_i$ be the size of reactor $i$.\n",
"\n",
"Continuous cost model: $c_i (x_i)^{0.6}$"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[2.2.1.1 Develop the optimization model](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1.1-Develop-the-optimization-model)",
"section": "2.2.1.1 Develop the optimization model"
}
},
"source": [
"### 2.2.1.1 Develop the optimization model\n",
"* Draw a picture\n",
"* Sets\n",
"* Parameters\n",
"* Variables\n",
"* Objective\n",
"* Constraints\n",
"* Degree of freedom analysis"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[2.2.1.2 Solve with Continuous Cost Model in Pyomo](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1.2-Solve-with-Continuous-Cost-Model-in-Pyomo)",
"section": "2.2.1.2 Solve with Continuous Cost Model in Pyomo"
}
},
"source": [
"### 2.2.1.2 Solve with Continuous Cost Model in Pyomo"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[2.2.1.2 Solve with Continuous Cost Model in Pyomo](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1.2-Solve-with-Continuous-Cost-Model-in-Pyomo)",
"section": "2.2.1.2 Solve with Continuous Cost Model in Pyomo"
}
},
"source": [
"We start my defining the model in Pyomo."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"nbpages": {
"level": 3,
"link": "[2.2.1.2 Solve with Continuous Cost Model in Pyomo](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1.2-Solve-with-Continuous-Cost-Model-in-Pyomo)",
"section": "2.2.1.2 Solve with Continuous Cost Model in Pyomo"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1 Set Declarations\n",
" REACTORS : Size=1, Index=None, Ordered=Insertion\n",
" Key : Dimen : Domain : Size : Members\n",
" None : 1 : Any : 2 : {1, 2}\n",
"\n",
"4 Param Declarations\n",
" conversion : Size=2, Index=REACTORS, Domain=Any, Default=None, Mutable=False\n",
" Key : Value\n",
" 1 : 0.8\n",
" 2 : 0.67\n",
" feed_cost : Size=1, Index=None, Domain=Any, Default=None, Mutable=False\n",
" Key : Value\n",
" None : 5.0\n",
" product_flowrate : Size=1, Index=None, Domain=Any, Default=None, Mutable=False\n",
" Key : Value\n",
" None : 10.0\n",
" reactor_cost : Size=2, Index=REACTORS, Domain=Any, Default=None, Mutable=False\n",
" Key : Value\n",
" 1 : 5.5\n",
" 2 : 4.0\n",
"\n",
"3 Var Declarations\n",
" feed_flowrate : Size=1, Index=None\n",
" Key : Lower : Value : Upper : Fixed : Stale : Domain\n",
" None : 0 : None : None : False : True : NonNegativeReals\n",
" reactor_effluent : Size=2, Index=REACTORS\n",
" Key : Lower : Value : Upper : Fixed : Stale : Domain\n",
" 1 : 0 : None : None : False : True : NonNegativeReals\n",
" 2 : 0 : None : None : False : True : NonNegativeReals\n",
" reactor_feed : Size=2, Index=REACTORS\n",
" Key : Lower : Value : Upper : Fixed : Stale : Domain\n",
" 1 : 0 : None : None : False : True : NonNegativeReals\n",
" 2 : 0 : None : None : False : True : NonNegativeReals\n",
"\n",
"1 Objective Declarations\n",
" cost : Size=1, Index=None, Active=True\n",
" Key : Active : Sense : Expression\n",
" None : True : minimize : 5.5*reactor_feed[1]**0.6 + 4.0*reactor_feed[2]**0.6 + 5.0*feed_flowrate\n",
"\n",
"3 Constraint Declarations\n",
" inlet_split : Size=1, Index=None, Active=True\n",
" Key : Lower : Body : Upper : Active\n",
" None : 0.0 : feed_flowrate - (reactor_feed[1] + reactor_feed[2]) : 0.0 : True\n",
" mixer : Size=1, Index=None, Active=True\n",
" Key : Lower : Body : Upper : Active\n",
" None : 10.0 : reactor_effluent[1] + reactor_effluent[2] : 10.0 : True\n",
" reactor_performance : Size=2, Index=REACTORS, Active=True\n",
" Key : Lower : Body : Upper : Active\n",
" 1 : 0.0 : reactor_effluent[1] - 0.8*reactor_feed[1] : 0.0 : True\n",
" 2 : 0.0 : reactor_effluent[2] - 0.67*reactor_feed[2] : 0.0 : True\n",
"\n",
"12 Declarations: REACTORS reactor_cost product_flowrate conversion feed_cost feed_flowrate reactor_feed reactor_effluent inlet_split reactor_performance mixer cost\n"
]
}
],
"source": [
"import pyomo.environ as pyo\n",
"\n",
"nlp = pyo.ConcreteModel()\n",
"\n",
"## Define sets\n",
"nlp.REACTORS = pyo.Set(initialize=range(1,3))\n",
"\n",
"## Define parameters (data)\n",
"\n",
"# $ / hr\n",
"cost_coefficient = {1:5.5, 2:4.0}\n",
"nlp.reactor_cost = pyo.Param(nlp.REACTORS, initialize=cost_coefficient)\n",
"\n",
"# kmol/hr B\n",
"nlp.product_flowrate = pyo.Param(initialize=10.0)\n",
"\n",
"# conversion fraction\n",
"reactor_conversion = {1:0.8, 2:0.67}\n",
"nlp.conversion = pyo.Param(nlp.REACTORS, initialize=reactor_conversion)\n",
"\n",
"# feed cost, $/kmol of A\n",
"nlp.feed_cost = pyo.Param(initialize=5.0)\n",
"\n",
"\n",
"## Define variables\n",
"\n",
"# Feed flowrate into reactor, x0 in handout illustration\n",
"nlp.feed_flowrate = pyo.Var(domain=pyo.NonNegativeReals)\n",
"\n",
"# Reactor feed, x1 and x2 in handout illustration\n",
"nlp.reactor_feed = pyo.Var(nlp.REACTORS, domain=pyo.NonNegativeReals)\n",
"\n",
"# Reactor effluent (outlet), z1 and z2 in handout illustration\n",
"nlp.reactor_effluent = pyo.Var(nlp.REACTORS, domain=pyo.NonNegativeReals)\n",
"\n",
"## Define constraints\n",
"\n",
"# YOUR SOLUTION HERE\n",
"\n",
"## Define objective\n",
"nlp.cost = pyo.Objective(expr=sum(nlp.reactor_cost[r] * (nlp.reactor_feed[r])**(0.6) for r in nlp.REACTORS) +\n",
" nlp.feed_cost * nlp.feed_flowrate)\n",
"\n",
"nlp.pprint()"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[2.2.1.3 Initialize to Favor Reaction 1 and Solve](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1.3-Initialize-to-Favor-Reaction-1-and-Solve)",
"section": "2.2.1.3 Initialize to Favor Reaction 1 and Solve"
}
},
"source": [
"### 2.2.1.3 Initialize to Favor Reaction 1 and Solve"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"nbpages": {
"level": 3,
"link": "[2.2.1.3 Initialize to Favor Reaction 1 and Solve](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1.3-Initialize-to-Favor-Reaction-1-and-Solve)",
"section": "2.2.1.3 Initialize to Favor Reaction 1 and Solve"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1 Set Declarations\n",
" REACTORS : Size=1, Index=None, Ordered=Insertion\n",
" Key : Dimen : Domain : Size : Members\n",
" None : 1 : Any : 2 : {1, 2}\n",
"\n",
"4 Param Declarations\n",
" conversion : Size=2, Index=REACTORS, Domain=Any, Default=None, Mutable=False\n",
" Key : Value\n",
" 1 : 0.8\n",
" 2 : 0.67\n",
" feed_cost : Size=1, Index=None, Domain=Any, Default=None, Mutable=False\n",
" Key : Value\n",
" None : 5.0\n",
" product_flowrate : Size=1, Index=None, Domain=Any, Default=None, Mutable=False\n",
" Key : Value\n",
" None : 10.0\n",
" reactor_cost : Size=2, Index=REACTORS, Domain=Any, Default=None, Mutable=False\n",
" Key : Value\n",
" 1 : 5.5\n",
" 2 : 4.0\n",
"\n",
"3 Var Declarations\n",
" feed_flowrate : Size=1, Index=None\n",
" Key : Lower : Value : Upper : Fixed : Stale : Domain\n",
" None : 0 : 20.0 : None : False : False : NonNegativeReals\n",
" reactor_effluent : Size=2, Index=REACTORS\n",
" Key : Lower : Value : Upper : Fixed : Stale : Domain\n",
" 1 : 0 : 16.0 : None : False : False : NonNegativeReals\n",
" 2 : 0 : 0.0 : None : False : False : NonNegativeReals\n",
" reactor_feed : Size=2, Index=REACTORS\n",
" Key : Lower : Value : Upper : Fixed : Stale : Domain\n",
" 1 : 0 : 20.0 : None : False : False : NonNegativeReals\n",
" 2 : 0 : 0 : None : False : False : NonNegativeReals\n",
"\n",
"1 Objective Declarations\n",
" cost : Size=1, Index=None, Active=True\n",
" Key : Active : Sense : Expression\n",
" None : True : minimize : 5.5*reactor_feed[1]**0.6 + 4.0*reactor_feed[2]**0.6 + 5.0*feed_flowrate\n",
"\n",
"3 Constraint Declarations\n",
" inlet_split : Size=1, Index=None, Active=True\n",
" Key : Lower : Body : Upper : Active\n",
" None : 0.0 : feed_flowrate - (reactor_feed[1] + reactor_feed[2]) : 0.0 : True\n",
" mixer : Size=1, Index=None, Active=True\n",
" Key : Lower : Body : Upper : Active\n",
" None : 10.0 : reactor_effluent[1] + reactor_effluent[2] : 10.0 : True\n",
" reactor_performance : Size=2, Index=REACTORS, Active=True\n",
" Key : Lower : Body : Upper : Active\n",
" 1 : 0.0 : reactor_effluent[1] - 0.8*reactor_feed[1] : 0.0 : True\n",
" 2 : 0.0 : reactor_effluent[2] - 0.67*reactor_feed[2] : 0.0 : True\n",
"\n",
"12 Declarations: REACTORS reactor_cost product_flowrate conversion feed_cost feed_flowrate reactor_feed reactor_effluent inlet_split reactor_performance mixer cost\n"
]
}
],
"source": [
"def initialize(model, reactor_choice=1):\n",
" ''' Initialize all of the variables in the model to demonstrate local solutions\n",
" \n",
" Arguments:\n",
" model: Pyomo model\n",
" reactor_choice: 1 or 2\n",
" \n",
" Returns:\n",
" nothing\n",
" \n",
" Action:\n",
" initializes model\n",
" \n",
" '''\n",
" \n",
" # Guess 20 kmol/hr feed of A\n",
" model.feed_flowrate = 20.0\n",
" \n",
" # Either assign all of the feed to reactor 1 or 2\n",
" if reactor_choice == 1:\n",
" model.reactor_feed[1] = 20.0\n",
" model.reactor_feed[2] = 0\n",
" elif reactor_choice == 2:\n",
" model.reactor_feed[1] = 0\n",
" model.reactor_feed[2] = 20.0\n",
" else:\n",
" raise ValueError(\"Argument reactor_choice needs value 1 or 2.\")\n",
" \n",
" # Based on the feed assignments, calculate effluent flowrate\n",
" for r in model.REACTORS:\n",
" model.reactor_effluent[r] = model.reactor_feed[r]() * model.conversion[r]\n",
" \n",
"initialize(nlp, reactor_choice=1)\n",
"nlp.pprint()"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[2.2.1.3 Initialize to Favor Reaction 1 and Solve](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1.3-Initialize-to-Favor-Reaction-1-and-Solve)",
"section": "2.2.1.3 Initialize to Favor Reaction 1 and Solve"
}
},
"source": [
"Now let's solve the model."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"nbpages": {
"level": 3,
"link": "[2.2.1.3 Initialize to Favor Reaction 1 and Solve](https://ndcbe.github.io/CBE60499/02.02-IP.html#2.2.1.3-Initialize-to-Favor-Reaction-1-and-Solve)",
"section": "2.2.1.3 Initialize to Favor Reaction 1 and Solve"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Error evaluating \"var =\" definition -1: can't evaluate pow'(0,0.6).\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ipopt 3.13.2: \n",
"\n",
"******************************************************************************\n",
"This program contains Ipopt, a library for large-scale nonlinear optimization.\n",
" Ipopt is released as open source code under the Eclipse Public License (EPL).\n",
" For more information visit http://projects.coin-or.org/Ipopt\n",
"******************************************************************************\n",
"\n",
"This is Ipopt version 3.13.2, running with linear solver ma27.\n",
"\n",
"Number of nonzeros in equality constraint Jacobian...: 9\n",
"Number of nonzeros in inequality constraint Jacobian.: 0\n",
"Number of nonzeros in Lagrangian Hessian.............: 2\n",
"\n",
"ERROR: Solver (ipopt) returned non-zero return code (1)\n",
"ERROR: See the solver log above for diagnostic information.\n"
]
},
{
"ename": "ApplicationError",
"evalue": "Solver (ipopt) did not exit normally",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mApplicationError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m
"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.8.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}