From ad5e1ae991bfd530543909abcb69ad1eed335ce7 Mon Sep 17 00:00:00 2001 From: Tom van Woudenberg Date: Wed, 1 May 2024 15:55:17 +0200 Subject: [PATCH] Update moo_example.ipynb --- book/pages/moo_example.ipynb | 251 +++++++++++++++++++++++++++++------ 1 file changed, 213 insertions(+), 38 deletions(-) diff --git a/book/pages/moo_example.ipynb b/book/pages/moo_example.ipynb index cb3a23e..5d32513 100644 --- a/book/pages/moo_example.ipynb +++ b/book/pages/moo_example.ipynb @@ -190,7 +190,7 @@ "\n", ":::{card} Test yourself\n", "Try and adjust the values for $x$. Can you find the optimal solution? How does it change for different models?\n", - "\n", + "\n", ":::" ] }, @@ -201,7 +201,7 @@ "source": [ "## Method\n", "\n", - "Now let's solve this problem using an optimization method." + "Now let's solve this problem using an optimization method. The interpolated data is stored in `CO2func` and `POWfunc`." ] }, { @@ -224,12 +224,13 @@ "outputs": [], "source": [ "import scipy as sp\n", - "import numpy as np" + "import numpy as np\n", + "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "2871c599", "metadata": { "tags": [ @@ -240,7 +241,8 @@ "outputs": [], "source": [ "import scipy as sp \n", - "import numpy as np" + "import numpy as np\n", + "import matplotlib.pyplot as plt" ] }, { @@ -254,12 +256,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, + "id": "38cfe848", + "metadata": { + "tags": [ + "thebe-remove-input-init" + ] + }, + "outputs": [], + "source": [ + "RPM = np.array([800, 1000, 1200, 1400, 1700, 1800])\n", + "CO2 = np.array([708, 696.889, 688.247, 682.897, 684.955, 697.3 ])\n", + "POW = np.array([161.141, 263.243, 330.51 , 381.561, 391.17, 370 ])\n", + "\n", + "def CO2func(s):\n", + " return sp.interpolate.pchip_interpolate(RPM,CO2,s)\n", + "\n", + "def POWfunc(s):\n", + " return sp.interpolate.pchip_interpolate(RPM,POW,s);" + ] + }, + { + "cell_type": "code", + "execution_count": 12, "id": "a7a3e663", "metadata": {}, "outputs": [], "source": [ - "x0 = np.array([5,0,1])" + "x0 = np.array(1200)" ] }, { @@ -269,52 +293,98 @@ "source": [ "### Define objective function\n", "\n", - "The objective function was defined in {eq}`nonlinear_constrained_optimization_f`, which gives:" + "Let's define the objective function for each of the three models\n", + "\n", + "#### Weighted objective function\n", + "\n", + "The objective function was defined in {eq}`multi_objective_optimization_weighted_example`, which gives:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "c753c482", "metadata": {}, "outputs": [], "source": [ - "def func(x):\n", - " vol = x[0]*x[1]*x[2]\n", - " return vol" + "def weighted_obj(x):\n", + " delta_p = 1/3\n", + " delta_c = 1 - delta_p\n", + " return -delta_p * POWfunc(x) + delta_c * CO2func(x)" ] }, { "cell_type": "markdown", - "id": "7d93884f", + "id": "d568d456", "metadata": {}, "source": [ - "### Define constrain functions" + "#### Goal attainment\n", + "\n", + "The objective function was defined in {eq}`multi_objective_optimization_goal_example`, which gives:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "9131bdfc", + "metadata": {}, + "outputs": [], + "source": [ + "def goal_attainment(x):\n", + " Pt = 460\n", + " Ct = 640\n", + " return max(Pt - POWfunc(x),CO2func(x)-Ct)" ] }, { "cell_type": "markdown", - "id": "b18490c9", + "id": "20a34e4e", "metadata": {}, "source": [ - "The constraint functions were defined in {eq}`nonlinear_constrained_optimization_g`. We had no equality constraints. Unlike before with {ref}`the method to solve linear constrained problem `, we need an object which defines the upper and lower bounds. As this problem has only an upper bound of $0$, the lower bound is set to $\\infty$ which is `np.inf` in python. Note that a single constraint object can include multiple constraints." + "#### Pareto front\n", + "\n", + "For the pareto front, the objective functions needed to be normalized as defiend by `eq`{normalizing_f_example}:" ] }, { "cell_type": "code", - "execution_count": null, - "id": "fb2a2361", + "execution_count": 15, + "id": "75e23af0", "metadata": {}, "outputs": [], "source": [ - "def nonlinconfun(x):\n", - " c1 = 0.8 - x[0]*x[1]\n", - " c2 = 0.8 - x[0]*x[2]\n", - " c3 = 0.8 - x[1]*x[2]\n", - " c4 = 3000 - 2500 * x[0] * x[1] * x[2]\n", - " return np.array([c1,c2,c3,c4])\n", + "def POWfunc_normalized(x):\n", + " return (POWfunc(x) - 150)/(400 - 150)\n", "\n", - "cons = sp.optimize.NonlinearConstraint(nonlinconfun, np.array([-np.inf,-np.inf,-np.inf,-np.inf]), np.array([0,0,0,0]))" + "def CO2func_normalized(x):\n", + " return (CO2func(x) - 680)/(710 - 680)" + ] + }, + { + "cell_type": "markdown", + "id": "c5c95606", + "metadata": {}, + "source": [ + "The objective function was defined in {eq}`multi_objective_optimization_pareto_example`, which gives:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "3d257378", + "metadata": {}, + "outputs": [], + "source": [ + "def weighted_obj_pareto(x):\n", + " return -delta_p * POWfunc_normalized(x) + delta_c * CO2func_normalized(x)" + ] + }, + { + "cell_type": "markdown", + "id": "8ac5aae2", + "metadata": {}, + "source": [ + "in which delta_p and delta_c are defined when solving this problem" ] }, { @@ -323,19 +393,17 @@ "metadata": {}, "source": [ "### Define bounds\n", - "The bounds were defined in {eq}`bounds_nonlinear` and result in:" + "The one single bound was defined in {eq}`bounds_moo` and result in:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "42656ee2", "metadata": {}, "outputs": [], "source": [ - "bounds = [[0, None],\n", - " [0, None],\n", - " [0, None]]" + "bounds = [[800,1800]]" ] }, { @@ -351,20 +419,130 @@ "id": "18dba09c", "metadata": {}, "source": [ - "Now let's solve the problem. The `cons` object can be added directly, in the case of equality constraints as well you can define a list of constrainer objects as an input." + "Now let's solve the problem for each of the three models.\n", + "\n", + "#### Weighted objective function" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "d2d014c1", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " message: CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL\n", + " success: True\n", + " status: 0\n", + " fun: 325.81425292950235\n", + " x: [ 1.613e+03]\n", + " nit: 7\n", + " jac: [-5.684e-06]\n", + " nfev: 26\n", + " njev: 13\n", + " hess_inv: <1x1 LbfgsInvHessProduct with dtype=float64>\n" + ] + } + ], "source": [ - "result = sp.optimize.minimize(fun = func,x0 = x0,bounds = bounds,constraints=cons)\n", + "result = sp.optimize.minimize(fun = weighted_obj, x0 = x0, bounds = bounds)\n", "print(result)" ] }, + { + "cell_type": "markdown", + "id": "5c92dab4", + "metadata": {}, + "source": [ + "#### Goal attainment" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "89a9bfc1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " message: CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL\n", + " success: True\n", + " status: 0\n", + " fun: 68.83000008096866\n", + " x: [ 1.700e+03]\n", + " nit: 12\n", + " jac: [-5.684e-06]\n", + " nfev: 50\n", + " njev: 25\n", + " hess_inv: <1x1 LbfgsInvHessProduct with dtype=float64>\n" + ] + } + ], + "source": [ + "result2 = sp.optimize.minimize(fun = goal_attainment, x0 = x0, bounds=bounds)\n", + "print(result2)" + ] + }, + { + "cell_type": "markdown", + "id": "ba5d92ea", + "metadata": {}, + "source": [ + "#### Pareto front\n", + "\n", + "For the pareto front we need to solve this problem for a collection of weights. The results are stored in a list" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "476d4e0d", + "metadata": {}, + "outputs": [], + "source": [ + "x_pareto_opt =[]\n", + "for delta_p in np.linspace(0,1,100):\n", + " delta_c = 1- delta_p\n", + " result_i = sp.optimize.minimize(fun = weighted_obj_pareto,x0=x0,bounds=bounds)\n", + " x_pareto_opt.append(result_i.x[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "a58bf1f8", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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AABCo1U1TpWVlSoqKlJxcbGKi4v197//XT169FBtbW1bXmPIRWtwkqTUH2329HUqXTk13JcDAECH1qqpoZSUFF199dWqq6tTXV2dqqqq5HK52uracA7ezTBPu9zK3VLGjBMAACHU7OBUUVGh4uJiFRUVqaioSLW1tcrIyNA111yju+66S1dddVUorhN+/GuarMeSCE8AAIRIs4LToEGDVFNTo8zMTF1zzTVavHixrrzyStnt9lBdHwLwDk0ut/GZafIvGKc1AQAAbadZwcnal85ms8lut8tutzfZDBOh4b93nf9MkxWmrHAFAADaRrOLwz/77DPPUt3WrVt16tQpZWZmavz48crKytKVV14ZdWEqmovDpcaX7bjLDgCAttXqzuGffvqp58661157TTabTV9//XUbXV77iPbgJNGaAACA9tCqqaGvvvpKH374oT788EN98MEHqq2t9SznoX0tmTjcE5pi7TGEJgAAQqBZwenQoUP6/e9/r0WLFmnUqFEaOHCg5syZo08++UQzZ87Um2++2azZpjVr1mjMmDGKj49XfHy80tPTtXnzZs/zx44d0913363k5GTFxcVp1KhRWrNmTYPX2bZtm6699lr17NlT559/vsaPH9/ptoYJ1JoAAAC0rWYVh/fv319du3bV2LFj9b//9//W+PHjdfXVVysuLq5Fb56cnKxVq1Zp2LBhkqRnn31W06dP186dOzV69GgtXbpURUVF2rBhgwYPHqzXX39dixYt0sCBAzV9+nRJ9aHpu9/9rpYvX65f/epXio2N1QcffBB1dVatYS3TpQ1NVIajjyQ1KBjnDjsAAFqvWTVOr732mjIzM9WzZ8+QXVBiYqJ+8YtfaN68ebrkkks0Y8YM/eQnP/E8f+WVV2ratGn6+c9/LklKS0tTdna253FLRHONk3cheEn5YTkrqj130nnfVWcFq7zb08N5uQAARLVmTctMmTJFPXv21IYNGxo95/7772/RhbhcLuXl5en48eNKT6//j3tmZqby8/O1f/9+GWNUVFSk0tJSTZkyRVL90uG7776rfv36KSMjQxdccIGysrL09ttvN/ledXV1qqmp8fmJVt6tCfxnm6wwZT22ngcAAC3Torvqzj//fG3YsEHXX3+9z/GlS5cqLy9PBw4cCPq1du/erfT0dJ06dUrnnXeeNm7cqGnTpkmSTp8+rQUL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kksuUUlJSaPvVVdXp5qaGp8foDMLZimvKRsXpCnDkSRJKimv0qy1zgahqaS8SvYYW9teOAC0s7AHp927d+u8885Tt27dtHDhQm3atEkXX3yxRo4cqUGDBmn58uU6cuSITp8+rVWrVungwYM6cOCAJOngwYOKjY1V7969fV7zggsu0MGDBxt9z4cfflgJCQmen5SUlJCOEegM/MOTf2iitQGAjiDswWnEiBHatWuXnE6n7rzzTs2ZM0effPKJunbtqhdffFGlpaVKTExUjx49VFxcrKlTp8putzf5msYY2WyN/5/t8uXLdfToUc9PZWVlWw8L6JSsJTpvgULT6ibqpnK3lFEPBSBihT04xcbGatiwYRo7dqwefvhhXXrppfrlL38pSbryyiu1a9cuff311zpw4IAKCgpUVVWlIUOGSJL69++v06dP68iRIz6veejQIV1wwQWNvme3bt08d/JZPwBab9ZaZ4NjdlvD2ilrixf/8GQVqbOkByBShT04+TPGeOqbLAkJCerbt6/Kysq0Y8cOTZ8+XVJ9sOratasKCws95x44cEAfffSRMjIy2vW6gc7Ov6bJ4jKmQaAKdMceW7wAiAZhbYD54IMPaurUqUpJSVFtba3y8vJUXFysgoICSdIf/vAH9e3bVxdddJF2796te+65RzfddJOnGDwhIUHz5s3Tfffdp6SkJCUmJuoHP/iBvvWtb2nSpEnhHBrQqQQqBF+WnSpnRZWn3mnWWqfPUh5bvACIRmGdcfrqq680e/ZsjRgxQhMnTtS7776rgoICZWdnS6qfPZo9e7ZGjhypJUuWaPbs2Xr++ed9XmP16tW66aab9P3vf19XX321evTooT/96U/nrIMC0HZcbqPk3nENCsGtgvH47l1UUl7VYGluycThni7lbPECIBpEXB+ncKCPE9A2mtsPylqes8JTYzNOre0zBQBthb3qALSZpsKLf+jxr2myHgc61yom93/O+zUAoD0QnAC0u8a2eJEUMCAFeo5icgDhQHAC0O5cbhMw8FiPXe6GFQQUkwOIBNQ4iRonIJqk/mizp5i8dOXURs9bXViqd/dUKcPRJ+AyYUn5YX17SBK1UQCaJeL6OAFAY3K3lHlC02mXu9Hu41J9XZSzorpBo01ric9ZUU2jTQDNxlIdgKjQnGJy72M5haWe86zHkrQsO1Uut1HuljLu1gMQNIITgIjX3GJyS2Ph6Vzhi7v1ADSG4AQg4rWkmNz7HKuYXJJPo82m7tbLcCQxEwWgAYrDRXE40JF5zypZ/EOYfyNO/w7o/udxNx/QeVEcDqDD8g5Ny7JTPUtv/gXj/lu/bFyQxibEAAJiqQ5Ah+QfmrzDjnfNk7U853+3Hn2jAARCcALQIbncRmlDExv0cbL+uqT8sOeuuqbu1rNCE5sQA5CocZJEjRPQWTW2/OZdIF5SXnXOTYgBdB7MOAHotJq6W89ZUeVTIH6uvlHBWl1YKnuMjTv2gChFcALQaTUWUOq3ZKlqdt+oYNhjbPSOAqIYwQkA/LSmb9S5NNU7yv892W8PiDwEJwDw01QQaYsap2Dv2LP223NWVPv8nveyYYajT6uvB0DwCE4AEAbB3LEXzH57FKsD7YvgBABh0FTvKG/n2m8PQPuiczgAtDPvmqbSlVMbdCn3Z3U2t9BTCggfZpwAoB0FKgQ/1x171uyUpakZKgChRXACgHbU3Dv2/LeOkRpuGRNqVu8pl9s06EFl9Z6ynucOP3R0BCcAaEfNuWOvOfvthZLVe8rqpG69p3+H9bShiY3OhNHcEx0FwQkAIlSw++2FmvdSYoYjSTmFpZ7O6lZo8p4N8/4dieae6FjYq07sVQcAwbACkN1mk8sYz5/es2GNbZrMXYDoKAhOIjgBQLBSf7TZp1A91h6j0pVTfc6xwlJrNkdubE+/1YWl2r63WlcNTmyw7MdyINoD7QgAAEGx7u6z22ySJLvN5rnDz5vVPqGp5p7nYtVV+b/29r3VKimv0va91Q2uLeds2AJCieAEADgn70JwlzE+f/oHnEDNPZtrycThDfpbWZsvW3VV3sdZDkR7oTgcANAk/7vn/OuXrPBkCVTjJDX/7r+m9vSzXrepvf5CrbHlRIllw46M4AQAaJLVe6r+Lr+kBo07reMl5YflrKhuVnPPc2lsT79g9voLNWs50boeS7B3ERK8ohPBCQDQpGB7T7ncpkHrBO9zWtI6obE9/YLd6y+UAoXC5iwbegcv7+ai/sGLEBVZuKtO3FUHAJGosdYGjS0ZhqvGqTV3EfqPqb3H5j/r5f3YP7A1J8DNeGqb7DE2bVyQ1uC5WWudcrmNXrgjvW0H004oDgcARJzG9vTzDhjex8+1UXIoteYuQuvaS8qrZLfZfMbWHoHQ/+5F6/GstU6fuxSbe9eiPaZ+LLPWOn2Oz1rrrB9rFN/9yFIdACDiNLan31WDE33+tLRmObC1Wrts6F2vZYUnq19WqGfRAi03eneFb2mA27ggzROSZq11+jzOcCQFnImKFizViaU6AEDLtEWndP+lPqsje6DmoqHifw3WzF5rmphK38wwWaI9NEks1QEA0CKNLSc2Z9nQ+zVKV0719MdqrLloqPgvN25ckNbqJqaSGoSkaA9NEsEJAIAWaWw50QpP51o2DDRbZS1lNdZcNFT8lxtnrXW2uomppIA1TtGOpTqxVAcAaH/+d7D5hyirRUGoC8T939u/FqmlRer+r9NRapwoDgcAIAy8b+v3n73yDyihKnpvatbL2tamJU1MA4WkQAXj0YjgBABAmAXbZLSt+Qc278fWrJf3NQQb4OqboTacWbLCUzjufmwrLNWJpToAABAcisMBAACCRHACAAAIEsEJAAAgSAQnAACAIBGcAAAAgkRwAgAACBLBCQAAIEgEJwAAgCARnAAAAIJEcAIAAAgSe9VJsnadqampCfOVAACA5urVq5dsNlu7vBfBSVJtba0kKSUlJcxXAgAAmqs995plk19JbrdbX375Zbsm1taqqalRSkqKKisrO+TGxB15fB15bBLji2YdeWxSxx5fRx6bdO7xMePUzmJiYpScnBzuy2iR+Pj4DvklsXTk8XXksUmML5p15LFJHXt8HXlsUmSMj+JwAACAIBGcAAAAgkRwilLdunXTihUr1K1bt3BfSkh05PF15LFJjC+adeSxSR17fB15bFJkjY/icAAAgCAx4wQAABAkghMAAECQCE4AAABBIjgBAAAEieDUDvbv369bb71VSUlJ6tGjhy677DK99957nuePHTumu+++W8nJyYqLi9OoUaO0Zs0an9e444475HA4FBcXp759+2r69On67LPPzvneTzzxhIYMGaLu3bvryiuv1FtvveXzvDFGP/3pTzVw4EDFxcVp/Pjx+vjjjyN+bA8//LCuuuoq9erVS/369dNNN92kzz//3OecuXPnymaz+fykpaUFPbZwju+nP/1pg2vv37+/zzmt/ezCOb7Bgwc3GJ/NZtNdd93lOae1n19bjM1ijNHUqVNls9n08ssvn/O9Q/29C+f42uO7F66xRdP3riXja4/vXVuNb/z48Q2uY+bMmed87/b47skgpKqrq82gQYPM3Llzzbvvvmv27Nlj3njjDfPFF194zpk/f75xOBymqKjI7Nmzxzz11FPGbrebl19+2XPOU089ZbZu3Wr27Nlj3nvvPXPDDTeYlJQU889//rPR987LyzNdu3Y1a9euNZ988om55557TM+ePc3f//53zzmrVq0yvXr1Mi+++KLZvXu3mTFjhhkwYICpqamJ6LFNmTLFrFu3znz00Udm165d5rrrrjMXXXSROXbsmOecOXPmmO9+97vmwIEDnp+qqqpzjisSxrdixQozevRon2s/dOiQzzmt+ezCPb5Dhw75jK2wsNBIMkVFRZ5zWvP5tdXYLDk5OWbq1KlGktm0aVOT7x3q7124xxfq7144xxZN37uWjC/U37u2HF9WVpZZsGCBz3V8/fXXTb53e3z3jDGG4BRiP/zhD01mZmaT54wePdr87Gc/8zl2xRVXmB//+MeN/s4HH3xgJPn8w+hv3LhxZuHChT7HRo4caR544AFjjDFut9v079/frFq1yvP8qVOnTEJCgnnyySebvGZjwjs2f4cOHTKSzNatWz3H5syZY6ZPnx70a/gL5/hWrFhhLr300kafb+1nZ0xkfX733HOPcTgcxu12e4615vNry7Ht2rXLJCcnmwMHDgT1H6dQf++MCe/4/LX1dy+cY4u2711rP7u2/t4Z03bjy8rKMvfcc0+z3rs9vnvGGMNSXYjl5+dr7Nix+t73vqd+/frp8ssv19q1a33OyczMVH5+vvbv3y9jjIqKilRaWqopU6YEfM3jx49r3bp1GjJkiFJSUgKec/r0ab333nuaPHmyz/HJkyerpKREkrRnzx4dPHjQ55xu3bopKyvLc04kji2Qo0ePSpISExN9jhcXF6tfv35KTU3VggULdOjQoaBfM9zjKysr08CBAzVkyBDNnDlTFRUVnuda+9lFwvgsp0+f1oYNG/Rv//ZvDTbpbOnn11ZjO3HihG6++WY9/vjjDZZsGhtLqL934RxfIG393Qv32KLle9fazy4U37u2HJ8kPffcc+rTp49Gjx6tH/zgB6qtrW1yPO3x3ZPEUl2odevWzXTr1s0sX77cvP/+++bJJ5803bt3N88++6znnLq6OnPbbbcZSaZLly4mNjbWrF+/vsFr/frXvzY9e/Y0kszIkSOb/D/6/fv3G0nmnXfe8Tm+cuVKk5qaaowx5p133jGSzP79+33OWbBggZk8eXLEjs2f2+02N9xwQ4P/y8nLyzN//vOfze7du01+fr659NJLzejRo82pU6eCet1wju/VV181f/zjH82HH35oCgsLTVZWlrngggvM4cOHjTGt/+zCPT5vL7zwgrHb7Q3G0prPr63Gdvvtt5t58+Z5Husc/1ffHt+7cI7PXyi+e+EcWzR971r72YXie9eW43v66adNYWGh2b17t3n++efN4MGDzaRJkxp93/b67hnDUl3Ide3a1aSnp/scW7x4sUlLS/M8/sUvfmFSU1NNfn6++eCDD8yvfvUrc95555nCwkKf3/v6669NaWmp2bp1q7nhhhvMFVdcYU6ePBnwfa1/iEpKSnyO/8d//IcZMWKEMeabf4i+/PJLn3Pmz59vpkyZErFj87do0SIzaNAgU1lZ2eR5X375penatat58cUXg3rdSBmfMcYcO3bMXHDBBebRRx81xrT+s4uk8U2ePNlcf/315zyvOZ9fW4ztlVdeMcOGDTO1tbWe3wk2OIXyexfO8fkLxXcvUsZmTOR+79pifKH43hnTtv9e8bZjxw4jybz33nsBn2+v754xBKeQu+iii3z+r8AYY5544gkzcOBAY4wxJ06cMF27djV//vOffc6ZN29ekx9kXV2d6dGjh9m4cWOjz9vtdvPSSy/5HF+yZIm55pprjDHGlJeXG0nm/fff9znnxhtvNLfddlvEjs3b3XffbZKTk01FRcU5zzXGmGHDhvmsbzclEsbnbdKkSZ71+9Z+dsZExvj27t1rYmJiAha9BhLs59cWY7vnnnuMzWYzdrvd8yPJxMTEmKysrIDv2x7fu3COz1uovnuRMDZvkfi9a+34QvW9MyZ0/15xu92ma9euJi8vL+Dz7fXdM4Yap5C7+uqrG9yqW1paqkGDBkmSzpw5ozNnzigmxvejsNvtcrvdTb62MUZ1dXUBn4uNjdWVV16pwsJCn+OFhYXKyMiQJA0ZMkT9+/f3Oef06dPaunWr55xIHJv1/N13362XXnpJb775poYMGXLO662qqlJlZaUGDBhwznOl8I7PX11dnT799FPPtbf2s5MiY3zr1q1Tv379dN11153z3OZ8fm0xtgceeEAffvihdu3a5fmRpNWrV2vdunUB37c9vnfhHJ8U+u9eOMfmL1K/d60dX6i+d1Lo/r3y8ccf68yZM41eR3t99yRR4xRqf/vb30yXLl3MypUrTVlZmXnuuedMjx49zIYNGzznZGVlmdGjR5uioiJTUVFh1q1bZ7p3726eeOIJY0x9Sv7P//xPs2PHDvP3v//dlJSUmOnTp5vExETz1VdfeV7n2muvNb/61a88j61bM5955hnzySefmHvvvdf07NnT7N2713POqlWrTEJCgnnppZfM7t27zc033xz0rZnhHNudd95pEhISTHFxsc/tqidOnDDGGFNbW2vuu+8+U1JSYvbs2WOKiopMenq6ufDCC4O+7TSc47vvvvtMcXGxqaioME6n01x//fWmV69ebfbZhXt8xhjjcrnMRRddZH74wx82uLbWfn5tMbZAFGA5pL2/d+EeX6i/e+EcW7R871o6PmNC+71rq/F98cUX5qGHHjLbt283e/bsMX/5y1/MyJEjzeWXX+7T5iQc3z1jWKprF3/605/MJZdcYrp162ZGjhxpnn76aZ/nDxw4YObOnWsGDhxounfvbkaMGGEeffRRzy2i+/fvN1OnTjX9+vUzXbt2NcnJyWbWrFnms88+83mdQYMGmRUrVvgc+/Wvf20GDRpkYmNjzRVXXOFzy7Ax9dOfK1asMP379zfdunUz11xzjdm9e3fEj01SwJ9169YZY+qngydPnmz69u1runbtai666CIzZ84c849//CPosYVzfFZvka5du5qBAwea//W//pf5+OOPfX6ntZ9dOMdnjDGvvfaakWQ+//zzBtfVFp9fa8cWSKD/OIXjexfO8bXHdy9cY4uW711Lx2dM6L93bTG+f/zjH+aaa64xiYmJJjY21jgcDrNkyZIG/aTC9d2zGWNM8PNTAAAAnRc1TgAAAEEiOAEAAASJ4AQAABAkghMAAECQCE4AAABBIjgBAAAEieAEAAAQJIITAABAkAhOAAAAQSI4AQAABIngBCBqVVVVqV+/ftq7d2+rXmf8+PG699572+Samvu6//qv/6qcnJw2f28AoUFwAtAqBw8e1OLFizV06FB169ZNKSkpuuGGG7RlyxbPOZWVlZo3b54GDhyo2NhYDRo0SPfcc4+qqqpa9d4PP/ywbrjhBg0ePLhFvz937lw98MADTZ7z5JNPqlevXvrnP//pOXbs2DF17dpV3/nOd3zOfeutt2Sz2VRaWhr0Nfzf//t/tXLlStXU1DTv4gGEBcEJQIvt3btXV155pd58803993//t3bv3q2CggJNmDBBd911lySpoqJCY8eOVWlpqZ5//nl98cUXevLJJ7Vlyxalp6erurq6Re998uRJPfPMM5o/f36Lft/tdusvf/mLpk+f3uR5EyZM0LFjx7Rjxw7Psbfeekv9+/fX9u3bdeLECc/x4uJiDRw4UKmpqUFfx5gxYzR48GA999xzzR8EgHZHcALQYosWLZLNZtPf/vY3/eu//qtSU1M1evRoLVu2TE6nU5J01113KTY2Vq+//rqysrJ00UUXaerUqXrjjTe0f/9+/ehHP2rRe2/evFldunRRenq6z/Ha2lrdcsst6tmzpwYMGKDVq1cHXDJ75513FBMTo29/+9sNXrugoEAJCQlav369RowYoYEDB6q4uNjzfHFxsaZPny6Hw6GSkhKf4xMmTPB5LbfbrX//939XYmKi+vfvr5/+9KcN3u/GG2/U888/3/y/CQDaHcEJQItUV1eroKBAd911l3r27Nng+fPPP1/V1dV67bXXtGjRIsXFxfk8379/f91yyy164YUXZIxp9vv/9a9/1dixYxscX7Zsmd555x3l5+ersLBQb731lt5///0G5+Xn5+uGG25QTIzvvwbz8vL0/e9/X+vXr9dtt90mqb5WqaioyHNOUVGRxo8fr6ysLM/x06dPa9u2bQ2C07PPPquePXvq3Xff1X//93/rZz/7mQoLC33OGTdunP72t7+prq6u2X8fALQvghOAFvniiy9kjNHIkSMbPaesrEzGGI0aNSrg86NGjdKRI0f0//7f/1NlZaXGjx+viy++WGPGjNEf/vCHJt9/7969GjhwoM+x2tpaPfvss3rkkUc0ceJEXXLJJVq3bp1cLleD38/Pz2+wTPfEE09o4cKFeuWVV3yeGz9+vN555x3985//VG1trXbu3KlrrrlGWVlZnpkop9OpkydPNghOY8aM0YoVKzR8+HDddtttGjt2rE/9lyRdeOGFqqur08GDB5scM4Dw6xLuCwAQnaxZIpvN1iav0aVLFz322GO67LLLdOjQIV1xxRWaNm1awNksqb7GqXv37j7HKioqdObMGY0bN85zLCEhQSNGjPA579NPP9W+ffs0adIkz7EXX3xRX331ld5++22f35fq65yOHz+u7du368iRI0pNTVW/fv2UlZWl2bNn6/jx4youLtZFF12koUOH+vzumDFjfB4PGDBAhw4d8jlmzcZ510sBiEzMOAFokeHDh8tms+nTTz9t9Jxhw4bJZrPpk08+Cfj8Z599pt69e6tPnz4aMGCALrvsMklSv379lJiY2GTheJ8+fXTkyBGfY42FOf+lwPz8fGVnZ/ssH1522WXq27ev1q1b1+D8YcOGKTk5WUVFRSoqKlJWVpak+uXGIUOG6J133lFRUZGuvfbaBtfZtWtXn8c2m01ut9vnmDXOvn37NjpeAJGB4ASgRRITEzVlyhT9+te/1vHjxxs8//XXXyspKUnZ2dl64okndPLkSZ/nDx48qOeee04zZsxoEHR27Nght9utlJSURt//8ssvbxDIHA6Hunbtqr/97W+eYzU1NSorK/M575VXXtGNN97Y4HeLior0yiuvaPHixQ3eb8KECSouLlZxcbHGjx/vOZ6VlaXXXntNTqezwTJdsD766CMlJyerT58+Lfp9AO2H4ASgxZ544gm5XC6NGzdOL774osrKyvTpp58qNzfXc7fb448/rrq6Ok2ZMkV//etfVVlZqYKCAmVnZ+vCCy/UypUrfV6zqqpKt912m55++ukm33vKlCn6+OOPfWadevXqpTlz5uj+++9XUVGRPv74Y/3bv/2bYmJiPOHs0KFD2r59u66//voGr5mamqqioiK9+OKLDe7CmzBhgt5++23t2rXLM+Mk1QentWvX6tSpUy0OTm+99ZYmT57cot8F0L4ITgBabMiQIXr//fc1YcIE3XfffbrkkkuUnZ2tLVu2aM2aNZLql/R27Nghh8OhGTNmyOFw6Pbbb9eECRO0bds2JSYmel6vrq5O//Iv/6Lly5crIyOjyff+1re+pbFjx+r3v/+9z/GcnBylp6fr+uuv16RJk3T11Vdr1KhRnnqoP/3pT/r2t7+tfv36BXzdESNG6M0339Tzzz+v++67z3N8woQJOnnypIYNG6YLLrjAczwrK0u1tbVyOBxNzpA15tSpU9q0aZMWLFjQ7N8F0P5spiX3AQNAGzPGaNasWRoxYkTAXkeBvPrqq/rBD36gjz76qEFbAcvx48d14YUX6tFHH9W8efN04403KjMzU//+7//ehlffcr/+9a/1yiuv6PXXXw/3pQAIAnfVAYgI77zzjl544QWNGTNGL7/8siTpf/7nf/Stb32r0d+ZNm2aysrKtH//fs9sz86dO/XZZ59p3LhxOnr0qH72s59Jkqe9QGZmpm6++ebQDqYZunbtql/96lfhvgwAQWLGCUCHsnPnTs2fP1+ff/65YmNjdeWVVyonJ6fJAAYAwSI4AQAABInicAAAgCARnAAAAIJEcAIAAAgSwQkAACBIBCcAAIAgEZwAAACCRHACAAAIEsEJAAAgSAQnAACAIBGcAAAAgvT/AcgtyWF0c7fXAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "P_pareto_opt = POWfunc(x_pareto_opt)\n", + "C_pareto_opt = CO2func(x_pareto_opt)\n", + "\n", + "plt.figure()\n", + "plt.plot(C_pareto_opt,P_pareto_opt,'x')\n", + "plt.ylabel('Power (kW)')\n", + "plt.xlabel('CO$_2$ (g/kWh)')\n", + "ax = plt.gca()\n", + "ax.invert_yaxis()\n", + "ax.spines['right'].set_color('none')\n", + "ax.spines['top'].set_color('none')" + ] + }, { "cell_type": "markdown", "id": "702e8343", @@ -372,10 +550,7 @@ "source": [ "## Exercise\n", "\n", - ":::{card} Test yourself\n", - "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding on this page.\n", - "\n", - ":::" + "...\n" ] }, {