From 1ba1370890263d4d255e322302a30888320bd9ab Mon Sep 17 00:00:00 2001 From: luohezhiming <98901358+luohezhiming@users.noreply.github.com> Date: Fri, 2 Jun 2023 18:55:49 -0400 Subject: [PATCH] Fix held tutorials by updating IDAES imports (#40) * revise import errors * move files to doc folder * Add ipynb artifacts for tutorials * Change tutorials position in TOC to address FileNotFound error See IDAES/examples#50 * Set missing generated data files to be ignored * Try using a Markdown header to obtain a clearer sidebar entry * Try removing ref to logo * Add updated ipynb artifacts --------- Co-authored-by: Ludovico Bianchi --- .gitignore | 3 +- idaes_examples/mod/notebook_checks.py | 4 +- idaes_examples/notebooks/_toc.yml | 9 +- .../notebooks/docs/tut/introduction_doc.ipynb | 1 + .../docs/tut/introduction_exercise.ipynb | 1 + .../docs/tut/introduction_short_doc.ipynb | 1 + .../tut/introduction_short_exercise.ipynb | 1 + .../tut/introduction_short_solution.ipynb | 1 + .../docs/tut/introduction_short_src.ipynb | 1 + .../docs/tut/introduction_short_test.ipynb | 1 + .../docs/tut/introduction_short_usr.ipynb | 1 + .../docs/tut/introduction_solution.ipynb | 1 + .../notebooks/docs/tut/introduction_src.ipynb | 1 + .../docs/tut/introduction_test.ipynb | 1 + .../notebooks/docs/tut/introduction_usr.ipynb | 1 + .../tut/notebook_test_script.py | 0 .../notebooks/{held => docs}/tut/sin_data.csv | 0 .../held/tut/introduction_short_src.ipynb | 965 -------------- .../notebooks/held/tut/introduction_src.ipynb | 1155 ----------------- 19 files changed, 20 insertions(+), 2128 deletions(-) create mode 100644 idaes_examples/notebooks/docs/tut/introduction_doc.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_exercise.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_short_doc.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_short_exercise.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_short_solution.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_short_src.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_short_test.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_short_usr.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_solution.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_src.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_test.ipynb create mode 100644 idaes_examples/notebooks/docs/tut/introduction_usr.ipynb rename idaes_examples/notebooks/{held => docs}/tut/notebook_test_script.py (100%) rename idaes_examples/notebooks/{held => docs}/tut/sin_data.csv (100%) delete mode 100644 idaes_examples/notebooks/held/tut/introduction_short_src.ipynb delete mode 100644 idaes_examples/notebooks/held/tut/introduction_src.ipynb diff --git a/.gitignore b/.gitignore index fede940e..357127f9 100644 --- a/.gitignore +++ b/.gitignore @@ -143,7 +143,8 @@ idaes_examples/notebooks/**/pysmo/*.pickle idaes_examples/notebooks/**/omlt/keras_surrogate/*.pb idaes_examples/notebooks/**/omlt/keras_surrogate/*.pdf idaes_examples/notebooks/**/omlt/*.pdf -**/alamo/alamo_run.alm +alamo_run.alm +idaes_examples/notebooks/docs/tut/sin_data.csv *.pb *_info.json variables.* diff --git a/idaes_examples/mod/notebook_checks.py b/idaes_examples/mod/notebook_checks.py index 842f86aa..e8c6e0bd 100644 --- a/idaes_examples/mod/notebook_checks.py +++ b/idaes_examples/mod/notebook_checks.py @@ -25,13 +25,13 @@ idaes_import_check = True try: from idaes.core import * - from idaes.generic_models.unit_models import (PressureChanger, + from idaes.models.unit_models import (PressureChanger, CSTR, Flash, Heater, Mixer, Separator) - from idaes.generic_models.unit_models.pressure_changer import ThermodynamicAssumption + from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption from idaes.core.util.model_statistics import degrees_of_freedom except Exception as err: diff --git a/idaes_examples/notebooks/_toc.yml b/idaes_examples/notebooks/_toc.yml index 6ef2ef3b..dec14a37 100644 --- a/idaes_examples/notebooks/_toc.yml +++ b/idaes_examples/notebooks/_toc.yml @@ -2,15 +2,14 @@ format: jb-book parts: - caption: Tutorials chapters: + - file: docs/tut/index + sections: + - file: docs/tut/introduction_short_doc + - file: docs/tut/introduction_doc - file: docs/tut/core/index sections: - file: docs/tut/core/flash_unit_doc - file: docs/tut/core/hda_flowsheet_doc - # Moved to 'held' until their imports can be fixed - # - file: docs/tut/general/index - # sections: - # - file: docs/tut/introduction_short_doc - # - file: docs/tut/introduction_doc - file: docs/tut/ui/index sections: - file: docs/tut/ui/visualizer_tutorial_doc diff --git a/idaes_examples/notebooks/docs/tut/introduction_doc.ipynb b/idaes_examples/notebooks/docs/tut/introduction_doc.ipynb new file mode 100644 index 00000000..425194f1 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_doc.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": 1, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": 6, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "# Todo: print the value of xlist to verify the results\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python provides a short-hand notation for building lists called *list comprehensions*. An example of a list comprehension that creates all even numbers from 0 to 40 is:\n", "\n", "```python\n", "values = [q*2 for q in range(21)]\n", "```\n", "\n", "Note also that list comprehensions can include if clauses. For example, we could also implement the above example with the following code:\n", "\n", "```python\n", "values = [q for q in range(41) if q % 2 == 0]\n", "```\n", "\n", "Note that `%` is the modulus operator (it returns the remainder of the division). Therefore, in the above code, `q % 2` returns 0 if the value in `q` is exactly divisible by 2 (i.e., an even number).\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, create the same xlist that we created previously, but use the list comprehension notation. Verify that this result is correct by printing it.\n", "
\n"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define the list comprehension\n", "xlist = [i * 5 for i in range(11)]\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the len of the list\n", "print(len(xlist))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": 11, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This same task could have been done with a list comprehension (using much less code).\n", "\n", "
\n", "Inline Exercise:\n", "Write the list comprehension to compute the values of ylist. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result\n", "ylist = [x**2 for x in xlist]\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": 14, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python also supports dictionary comprehensions much like list comprehensions. For example:\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "d2 = {k:v**2 for k,v in d.items()}\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "Redo the conversion from square kilometers to square miles using a dictionary comprehension.\n", "
"]}, {"cell_type": "code", "execution_count": 15, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "areas_mi = {k: v * (0.62137**2) for k, v in areas.items()}\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": 21, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = [math.sin(xv) for xv in x]\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Importing and exporting data using Pandas\n", "\n", "Often, it is useful to output the data in a general format so it can be imported into other tools or presented in a familiar application. Python makes this easy with many great packages already available. The next code shows how to use the `pandas` package to create a dataframe and export the data to a csv file that we can import to excel. You could also consult [pandas documentation](https://pandas.pydata.org/pandas-docs/stable/) to see how to export the data directly to excel.\n", "
\n", "Inline Exercise:\n", "Execute the code below that shows how to import some data into a DataFrame from the Pandas package and then export this data to a csv file.\n", "
"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["import pandas as pd\n", "\n", "df_sin = pd.DataFrame({\"x\": x, \"sin(x) (radians)\": y})\n", "print(df_sin)\n", "df_sin.to_csv(\"sin_data.csv\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you go back to the browser tab that showed all the Jupyter notebook files and refresh, you will now see that there is a csv file with the x and y data. You can consult the Pandas documentation do learn about the many data analysis and statistical features of the `pandas` package.\n", "\n", "### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)\n", "* [pandas](https://pandas.pydata.org/pandas-docs/stable/)\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": 24, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_exercise.ipynb b/idaes_examples/notebooks/docs/tut/introduction_exercise.ipynb new file mode 100644 index 00000000..0c8670d6 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_exercise.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": 1, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the value of x"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Print the value of x"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", "\n", "# Todo: print the value of xlist to verify the results\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python provides a short-hand notation for building lists called *list comprehensions*. An example of a list comprehension that creates all even numbers from 0 to 40 is:\n", "\n", "```python\n", "values = [q*2 for q in range(21)]\n", "```\n", "\n", "Note also that list comprehensions can include if clauses. For example, we could also implement the above example with the following code:\n", "\n", "```python\n", "values = [q for q in range(41) if q % 2 == 0]\n", "```\n", "\n", "Note that `%` is the modulus operator (it returns the remainder of the division). Therefore, in the above code, `q % 2` returns 0 if the value in `q` is exactly divisible by 2 (i.e., an even number).\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, create the same xlist that we created previously, but use the list comprehension notation. Verify that this result is correct by printing it.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: define the list comprehension"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the len of the list"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This same task could have been done with a list comprehension (using much less code).\n", "\n", "
\n", "Inline Exercise:\n", "Write the list comprehension to compute the values of ylist. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " \n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python also supports dictionary comprehensions much like list comprehensions. For example:\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "d2 = {k:v**2 for k,v in d.items()}\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "Redo the conversion from square kilometers to square miles using a dictionary comprehension.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "\n", "\n", "# Todo: Generate the figure"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Importing and exporting data using Pandas\n", "\n", "Often, it is useful to output the data in a general format so it can be imported into other tools or presented in a familiar application. Python makes this easy with many great packages already available. The next code shows how to use the `pandas` package to create a dataframe and export the data to a csv file that we can import to excel. You could also consult [pandas documentation](https://pandas.pydata.org/pandas-docs/stable/) to see how to export the data directly to excel.\n", "
\n", "Inline Exercise:\n", "Execute the code below that shows how to import some data into a DataFrame from the Pandas package and then export this data to a csv file.\n", "
"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["import pandas as pd\n", "\n", "df_sin = pd.DataFrame({\"x\": x, \"sin(x) (radians)\": y})\n", "print(df_sin)\n", "df_sin.to_csv(\"sin_data.csv\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you go back to the browser tab that showed all the Jupyter notebook files and refresh, you will now see that there is a csv file with the x and y data. You can consult the Pandas documentation do learn about the many data analysis and statistical features of the `pandas` package.\n", "\n", "### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)\n", "* [pandas](https://pandas.pydata.org/pandas-docs/stable/)\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "\n", "\n", "# Todo: add the constraint here\n", "\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_short_doc.ipynb b/idaes_examples/notebooks/docs/tut/introduction_short_doc.ipynb new file mode 100644 index 00000000..ba876cec --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_short_doc.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": null, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES (short)"]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["from idaes_examples.mod.notebook_checks import run_checks\n", "\n", "assert run_checks() == 4"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax. One recommended by the IDAES team is https://www.coursera.org/learn/python."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": ["print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "print(xlist) # Todo: print the value of xlist to verify the results"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["print(len(xlist)) # Todo: print the len of the list"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": 18, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = []\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": 20, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": ["# Check the solution\n", "\n", "assert value(model.obj) == 0.5\n", "assert value(model.x) == 0.5\n", "assert value(model.y) == 0.5"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_short_exercise.ipynb b/idaes_examples/notebooks/docs/tut/introduction_short_exercise.ipynb new file mode 100644 index 00000000..89a4440b --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_short_exercise.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": null, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES (short)"]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["from idaes_examples.mod.notebook_checks import run_checks\n", "\n", "assert run_checks() == 4"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax. One recommended by the IDAES team is https://www.coursera.org/learn/python."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the value of x"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": ["print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", "\n", "# Todo: print the value of xlist to verify the results\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the len of the list"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", "\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "\n", "\n", "# Todo: add the constraint here\n", "\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": ["# Check the solution\n", "\n", "assert value(model.obj) == 0.5\n", "assert value(model.x) == 0.5\n", "assert value(model.y) == 0.5"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_short_solution.ipynb b/idaes_examples/notebooks/docs/tut/introduction_short_solution.ipynb new file mode 100644 index 00000000..3dbb3060 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_short_solution.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": null, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES (short)"]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["from idaes_examples.mod.notebook_checks import run_checks\n", "\n", "assert run_checks() == 4"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax. One recommended by the IDAES team is https://www.coursera.org/learn/python."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the value of x"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": ["print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", "\n", "# Todo: print the value of xlist to verify the results\n"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "print(xlist) # Todo: print the value of xlist to verify the results"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the len of the list"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["print(len(xlist)) # Todo: print the len of the list"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "\n", "print(ylist)"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", "\n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure"]}, {"cell_type": "code", "execution_count": 18, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = []\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "\n", "\n", "# Todo: add the constraint here\n", "\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "code", "execution_count": 20, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": ["# Check the solution\n", "\n", "assert value(model.obj) == 0.5\n", "assert value(model.x) == 0.5\n", "assert value(model.y) == 0.5"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_short_src.ipynb b/idaes_examples/notebooks/docs/tut/introduction_short_src.ipynb new file mode 100644 index 00000000..0f82983d --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_short_src.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": null, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES (short)"]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["from idaes_examples.mod.notebook_checks import run_checks\n", "\n", "assert run_checks() == 4"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax. One recommended by the IDAES team is https://www.coursera.org/learn/python."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the value of x"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": ["print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", "\n", "# Todo: print the value of xlist to verify the results\n"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "print(xlist) # Todo: print the value of xlist to verify the results"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the len of the list"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["print(len(xlist)) # Todo: print the len of the list"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "\n", "print(ylist)"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", "\n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure"]}, {"cell_type": "code", "execution_count": 18, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = []\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "\n", "\n", "# Todo: add the constraint here\n", "\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "code", "execution_count": 20, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": ["# Check the solution\n", "\n", "assert value(model.obj) == 0.5\n", "assert value(model.x) == 0.5\n", "assert value(model.y) == 0.5"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 2} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_short_test.ipynb b/idaes_examples/notebooks/docs/tut/introduction_short_test.ipynb new file mode 100644 index 00000000..ba876cec --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_short_test.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": null, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES (short)"]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["from idaes_examples.mod.notebook_checks import run_checks\n", "\n", "assert run_checks() == 4"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax. One recommended by the IDAES team is https://www.coursera.org/learn/python."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": ["print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "print(xlist) # Todo: print the value of xlist to verify the results"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["print(len(xlist)) # Todo: print the len of the list"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": 18, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = []\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": 20, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": ["# Check the solution\n", "\n", "assert value(model.obj) == 0.5\n", "assert value(model.x) == 0.5\n", "assert value(model.y) == 0.5"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_short_usr.ipynb b/idaes_examples/notebooks/docs/tut/introduction_short_usr.ipynb new file mode 100644 index 00000000..3dbb3060 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_short_usr.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": null, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES (short)"]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["from idaes_examples.mod.notebook_checks import run_checks\n", "\n", "assert run_checks() == 4"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax. One recommended by the IDAES team is https://www.coursera.org/learn/python."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to the variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the value of x"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to the variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": ["print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", "\n", "# Todo: print the value of xlist to verify the results\n"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "print(xlist) # Todo: print the value of xlist to verify the results"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the len of the list"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["print(len(xlist)) # Todo: print the len of the list"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "\n", "print(ylist)"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", "\n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure"]}, {"cell_type": "code", "execution_count": 18, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = []\n", "for xv in x:\n", " y.append(math.sin(xv))\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "\n", "\n", "# Todo: add the constraint here\n", "\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "code", "execution_count": 20, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": ["# Check the solution\n", "\n", "assert value(model.obj) == 0.5\n", "assert value(model.x) == 0.5\n", "assert value(model.y) == 0.5"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_solution.ipynb b/idaes_examples/notebooks/docs/tut/introduction_solution.ipynb new file mode 100644 index 00000000..e93203d2 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_solution.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": 1, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the value of x"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Print the value of x"]}, {"cell_type": "code", "execution_count": 6, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", "\n", "# Todo: print the value of xlist to verify the results\n"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "# Todo: print the value of xlist to verify the results\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python provides a short-hand notation for building lists called *list comprehensions*. An example of a list comprehension that creates all even numbers from 0 to 40 is:\n", "\n", "```python\n", "values = [q*2 for q in range(21)]\n", "```\n", "\n", "Note also that list comprehensions can include if clauses. For example, we could also implement the above example with the following code:\n", "\n", "```python\n", "values = [q for q in range(41) if q % 2 == 0]\n", "```\n", "\n", "Note that `%` is the modulus operator (it returns the remainder of the division). Therefore, in the above code, `q % 2` returns 0 if the value in `q` is exactly divisible by 2 (i.e., an even number).\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, create the same xlist that we created previously, but use the list comprehension notation. Verify that this result is correct by printing it.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: define the list comprehension"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define the list comprehension\n", "xlist = [i * 5 for i in range(11)]\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the len of the list"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the len of the list\n", "print(len(xlist))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "\n", "\n", "print(ylist)"]}, {"cell_type": "code", "execution_count": 11, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This same task could have been done with a list comprehension (using much less code).\n", "\n", "
\n", "Inline Exercise:\n", "Write the list comprehension to compute the values of ylist. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result\n", "ylist = [x**2 for x in xlist]\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " \n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 14, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python also supports dictionary comprehensions much like list comprehensions. For example:\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "d2 = {k:v**2 for k,v in d.items()}\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "Redo the conversion from square kilometers to square miles using a dictionary comprehension.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "\n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 15, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "areas_mi = {k: v * (0.62137**2) for k, v in areas.items()}\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "\n", "\n", "# Todo: Generate the figure"]}, {"cell_type": "code", "execution_count": 21, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = [math.sin(xv) for xv in x]\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Importing and exporting data using Pandas\n", "\n", "Often, it is useful to output the data in a general format so it can be imported into other tools or presented in a familiar application. Python makes this easy with many great packages already available. The next code shows how to use the `pandas` package to create a dataframe and export the data to a csv file that we can import to excel. You could also consult [pandas documentation](https://pandas.pydata.org/pandas-docs/stable/) to see how to export the data directly to excel.\n", "
\n", "Inline Exercise:\n", "Execute the code below that shows how to import some data into a DataFrame from the Pandas package and then export this data to a csv file.\n", "
"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["import pandas as pd\n", "\n", "df_sin = pd.DataFrame({\"x\": x, \"sin(x) (radians)\": y})\n", "print(df_sin)\n", "df_sin.to_csv(\"sin_data.csv\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you go back to the browser tab that showed all the Jupyter notebook files and refresh, you will now see that there is a csv file with the x and y data. You can consult the Pandas documentation do learn about the many data analysis and statistical features of the `pandas` package.\n", "\n", "### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)\n", "* [pandas](https://pandas.pydata.org/pandas-docs/stable/)\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "\n", "\n", "# Todo: add the constraint here\n", "\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "code", "execution_count": 24, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_src.ipynb b/idaes_examples/notebooks/docs/tut/introduction_src.ipynb new file mode 100644 index 00000000..bfd16af8 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_src.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": 1, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "code", "execution_count": 2, "metadata": {"tags": ["testing"]}, "outputs": [], "source": ["from idaes_examples.mod import notebook_checks\n", "\n", "n = notebook_checks.run_checks()\n", "assert n == 4, f\"{4 - n} notebook check(s) failed\""]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the value of x"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Print the value of x"]}, {"cell_type": "code", "execution_count": 6, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", "\n", "# Todo: print the value of xlist to verify the results\n"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "# Todo: print the value of xlist to verify the results\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python provides a short-hand notation for building lists called *list comprehensions*. An example of a list comprehension that creates all even numbers from 0 to 40 is:\n", "\n", "```python\n", "values = [q*2 for q in range(21)]\n", "```\n", "\n", "Note also that list comprehensions can include if clauses. For example, we could also implement the above example with the following code:\n", "\n", "```python\n", "values = [q for q in range(41) if q % 2 == 0]\n", "```\n", "\n", "Note that `%` is the modulus operator (it returns the remainder of the division). Therefore, in the above code, `q % 2` returns 0 if the value in `q` is exactly divisible by 2 (i.e., an even number).\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, create the same xlist that we created previously, but use the list comprehension notation. Verify that this result is correct by printing it.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: define the list comprehension"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define the list comprehension\n", "xlist = [i * 5 for i in range(11)]\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the len of the list"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the len of the list\n", "print(len(xlist))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "\n", "\n", "print(ylist)"]}, {"cell_type": "code", "execution_count": 11, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This same task could have been done with a list comprehension (using much less code).\n", "\n", "
\n", "Inline Exercise:\n", "Write the list comprehension to compute the values of ylist. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result\n", "ylist = [x**2 for x in xlist]\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " \n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 14, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python also supports dictionary comprehensions much like list comprehensions. For example:\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "d2 = {k:v**2 for k,v in d.items()}\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "Redo the conversion from square kilometers to square miles using a dictionary comprehension.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "\n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 15, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "areas_mi = {k: v * (0.62137**2) for k, v in areas.items()}\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "\n", "\n", "# Todo: Generate the figure"]}, {"cell_type": "code", "execution_count": 21, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = [math.sin(xv) for xv in x]\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Importing and exporting data using Pandas\n", "\n", "Often, it is useful to output the data in a general format so it can be imported into other tools or presented in a familiar application. Python makes this easy with many great packages already available. The next code shows how to use the `pandas` package to create a dataframe and export the data to a csv file that we can import to excel. You could also consult [pandas documentation](https://pandas.pydata.org/pandas-docs/stable/) to see how to export the data directly to excel.\n", "
\n", "Inline Exercise:\n", "Execute the code below that shows how to import some data into a DataFrame from the Pandas package and then export this data to a csv file.\n", "
"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["import pandas as pd\n", "\n", "df_sin = pd.DataFrame({\"x\": x, \"sin(x) (radians)\": y})\n", "print(df_sin)\n", "df_sin.to_csv(\"sin_data.csv\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you go back to the browser tab that showed all the Jupyter notebook files and refresh, you will now see that there is a csv file with the x and y data. You can consult the Pandas documentation do learn about the many data analysis and statistical features of the `pandas` package.\n", "\n", "### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)\n", "* [pandas](https://pandas.pydata.org/pandas-docs/stable/)\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "\n", "\n", "# Todo: add the constraint here\n", "\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "code", "execution_count": 24, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 25, "metadata": {"tags": ["testing"]}, "outputs": [], "source": ["# Check the solution\n", "\n", "assert value(model.obj) == 0.5\n", "assert value(model.x) == 0.5\n", "assert value(model.y) == 0.5"]}, {"cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 2} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_test.ipynb b/idaes_examples/notebooks/docs/tut/introduction_test.ipynb new file mode 100644 index 00000000..ecc99e2c --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_test.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": 1, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "code", "execution_count": 2, "metadata": {"tags": ["testing"]}, "outputs": [], "source": ["from idaes_examples.mod import notebook_checks\n", "\n", "n = notebook_checks.run_checks()\n", "assert n == 4, f\"{4 - n} notebook check(s) failed\""]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": 6, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "# Todo: print the value of xlist to verify the results\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python provides a short-hand notation for building lists called *list comprehensions*. An example of a list comprehension that creates all even numbers from 0 to 40 is:\n", "\n", "```python\n", "values = [q*2 for q in range(21)]\n", "```\n", "\n", "Note also that list comprehensions can include if clauses. For example, we could also implement the above example with the following code:\n", "\n", "```python\n", "values = [q for q in range(41) if q % 2 == 0]\n", "```\n", "\n", "Note that `%` is the modulus operator (it returns the remainder of the division). Therefore, in the above code, `q % 2` returns 0 if the value in `q` is exactly divisible by 2 (i.e., an even number).\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, create the same xlist that we created previously, but use the list comprehension notation. Verify that this result is correct by printing it.\n", "
\n"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define the list comprehension\n", "xlist = [i * 5 for i in range(11)]\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the len of the list\n", "print(len(xlist))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": 11, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This same task could have been done with a list comprehension (using much less code).\n", "\n", "
\n", "Inline Exercise:\n", "Write the list comprehension to compute the values of ylist. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result\n", "ylist = [x**2 for x in xlist]\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": 14, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python also supports dictionary comprehensions much like list comprehensions. For example:\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "d2 = {k:v**2 for k,v in d.items()}\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "Redo the conversion from square kilometers to square miles using a dictionary comprehension.\n", "
"]}, {"cell_type": "code", "execution_count": 15, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "areas_mi = {k: v * (0.62137**2) for k, v in areas.items()}\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": 21, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = [math.sin(xv) for xv in x]\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Importing and exporting data using Pandas\n", "\n", "Often, it is useful to output the data in a general format so it can be imported into other tools or presented in a familiar application. Python makes this easy with many great packages already available. The next code shows how to use the `pandas` package to create a dataframe and export the data to a csv file that we can import to excel. You could also consult [pandas documentation](https://pandas.pydata.org/pandas-docs/stable/) to see how to export the data directly to excel.\n", "
\n", "Inline Exercise:\n", "Execute the code below that shows how to import some data into a DataFrame from the Pandas package and then export this data to a csv file.\n", "
"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["import pandas as pd\n", "\n", "df_sin = pd.DataFrame({\"x\": x, \"sin(x) (radians)\": y})\n", "print(df_sin)\n", "df_sin.to_csv(\"sin_data.csv\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you go back to the browser tab that showed all the Jupyter notebook files and refresh, you will now see that there is a csv file with the x and y data. You can consult the Pandas documentation do learn about the many data analysis and statistical features of the `pandas` package.\n", "\n", "### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)\n", "* [pandas](https://pandas.pydata.org/pandas-docs/stable/)\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": 24, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 25, "metadata": {"tags": ["testing"]}, "outputs": [], "source": ["# Check the solution\n", "\n", "assert value(model.obj) == 0.5\n", "assert value(model.x) == 0.5\n", "assert value(model.y) == 0.5"]}, {"cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/introduction_usr.ipynb b/idaes_examples/notebooks/docs/tut/introduction_usr.ipynb new file mode 100644 index 00000000..e93203d2 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/introduction_usr.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "code", "execution_count": 1, "metadata": {"tags": ["header", "hide-cell"]}, "outputs": [], "source": ["###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", "# Framework (IDAES IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", "# University of California, through Lawrence Berkeley National Laboratory,\n", "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", "# University, West Virginia University Research Corporation, et al.\n", "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Introduction to IDAES"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", "\n", "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", "\n", "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", "\n", "You can execute a cell by pressing `Shift+Enter`."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["run \"notebook_test_script.py\""]}, {"cell_type": "markdown", "metadata": {}, "source": ["If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Outline of Workshop\n", "\n", "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", "\n", "Welcome Module (this one):\n", "\n", "* Introduction to Jupyter notebooks and Python\n", "* Introduction to Pyomo\n", "\n", "Module 1 will cover:\n", "\n", "* how to import models from the core IDAES model library,\n", "* how to create a model for a single unit operation,\n", "* how to define feed and operating conditions,\n", "* how to initialize and solve a single unit model,\n", "* some ways we can manipulate the model and examine the results.\n", "\n", "Module 2 will demonstrate:\n", "\n", "* how to combine unit models together to form flowsheets,\n", "* tools to initialize and solve flowsheets with recycle loops,\n", "* how to optimize process operating conditions to meet product specifications.\n", "\n", "Module 3 will demonstrate:\n", "\n", "* how to build new unit models using the IDAES tools,\n", "* how to include new unit models into flowsheets.\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Jupyter Notebooks and Python\n", "\n", "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", "\n", "There are many additional tutorials online to learn more about the Python syntax."]}, {"cell_type": "markdown", "metadata": {}, "source": ["In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x"]}, {"cell_type": "code", "execution_count": 3, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 5 to variable x\n", "x = 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", "\n", "
\n", "Inline Exercise:\n", "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the value of x"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["
\n", "Inline Exercise:\n", "Now change the value of the x variable to 8 and execute the cell.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: Assign a value of 8 to variable x\n", "x = 8"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Jupyter notebooks and execution order\n", "\n", "
\n", "Note:\n", "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", "
\n", "\n", "
\n", "Inline Exercise:\n", "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", "
\n", "\n", "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", "\n", "**Again, notice that the state of the environment is determined by the execution order.**\n", "\n", "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", "\n", "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", "\n", "Some important commands to remember:\n", "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", "\n", "To show the use of these commands, complete the following.\n", "
\n", "Inline Exercise:\n", "\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Print the value of x"]}, {"cell_type": "code", "execution_count": 6, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Print the value of x\n", "print(x)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python `if` statements\n", "\n", "In the code below, we show an example of an `if` statement in Python.\n", "\n", "```python\n", "temp = 325\n", "# some other code\n", "if temp > 320:\n", " print('temperature is too high')\n", "elif x < 290:\n", " print('temperature is too low')\n", "else:\n", " print('temperature is just right')\n", "```\n", "\n", "
\n", "Note:\n", "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", "
\n", "\n", "Using the syntax above for the `if` statement, write the following code.\n", "
\n", "Inline Exercise:\n", "\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here"]}, {"cell_type": "code", "execution_count": 7, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["T_degC = 20\n", "# some other code\n", "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", "\n", "# Todo: put the if statement here\n", "if T_degF < 70:\n", " print(\"The room is too cold.\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python list containers\n", "\n", "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", "\n", "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the code block below to create the desired list and print the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", "\n", "# Todo: print the value of xlist to verify the results\n"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Create a list with the values 0 to 50 with steps of 5.\n", "xlist = list()\n", "for i in range(11):\n", " # Todo: use the append method of list to append the correct value\n", " xlist.append(i * 5)\n", "\n", "# Todo: print the value of xlist to verify the results\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python provides a short-hand notation for building lists called *list comprehensions*. An example of a list comprehension that creates all even numbers from 0 to 40 is:\n", "\n", "```python\n", "values = [q*2 for q in range(21)]\n", "```\n", "\n", "Note also that list comprehensions can include if clauses. For example, we could also implement the above example with the following code:\n", "\n", "```python\n", "values = [q for q in range(41) if q % 2 == 0]\n", "```\n", "\n", "Note that `%` is the modulus operator (it returns the remainder of the division). Therefore, in the above code, `q % 2` returns 0 if the value in `q` is exactly divisible by 2 (i.e., an even number).\n", "\n", "
\n", "Inline Exercise:\n", "In the cell below, create the same xlist that we created previously, but use the list comprehension notation. Verify that this result is correct by printing it.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: define the list comprehension"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define the list comprehension\n", "xlist = [i * 5 for i in range(11)]\n", "print(xlist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can easily check the length of a list using the python `len(l)` function.\n", "
\n", "Inline Exercise:\n", "Print the length of `xlist`. It should be 11.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: print the len of the list"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: print the len of the list\n", "print(len(xlist))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", "\n", "
\n", "Inline Exercise:\n", "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "\n", "\n", "print(ylist)"]}, {"cell_type": "code", "execution_count": 11, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["ylist = list()\n", "\n", "# Todo: define the for loop to add elements to ylist using the values in xlist\n", "for x in xlist:\n", " ylist.append(x**2)\n", "\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This same task could have been done with a list comprehension (using much less code).\n", "\n", "
\n", "Inline Exercise:\n", "Write the list comprehension to compute the values of ylist. Print the values in ylist to check the result.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result"]}, {"cell_type": "code", "execution_count": 12, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: create ylist using a list comprehension and print the result\n", "ylist = [x**2 for x in xlist]\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Python dictionary containers\n", "\n", "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", "
\n", "Inline Exercise:\n", "Execute the lines below to see the areas dictionary.\n", "
"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["areas = dict()\n", "areas[\"South Dakota\"] = 199742\n", "areas[\"Oklahoma\"] = 181035\n", "print(areas)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", "\n", "You can loop through dictionaries in different ways. For example,\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "for k in d.keys():\n", " # loop through the keys in the dictionary\n", " # access the value with d[k]\n", " print('key=', k, 'value=', d[k])\n", " \n", "for v in d.values():\n", " # loop through the values in the dictionary, ignoring the keys\n", " print('value=', v)\n", " \n", "for k,v in d.items():\n", " # loop through the entries in the dictionary, retrieving both\n", " # the key and the value\n", " print('key=', k, 'value=', v)\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " \n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 14, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["areas_mi = dict()\n", "for state_name, area in areas.items():\n", " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", " areas_mi[state_name] = area * (0.62137**2)\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Python also supports dictionary comprehensions much like list comprehensions. For example:\n", "```python\n", "d = {'A': 2, 'B': 4, 'D': 16}\n", "d2 = {k:v**2 for k,v in d.items()}\n", "```\n", "\n", "
\n", "Inline Exercise:\n", "Redo the conversion from square kilometers to square miles using a dictionary comprehension.\n", "
"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "\n", "print(areas_mi)"]}, {"cell_type": "code", "execution_count": 15, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["# Todo: define areas_mi using a dictionary comprehension and print the result\n", "areas_mi = {k: v * (0.62137**2) for k, v in areas.items()}\n", "print(areas_mi)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Matplotlib for generating figures\n", "\n", "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", "\n", "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["import numpy as np"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["xlist = list(np.linspace(0, 50, 16))\n", "ylist = [x**2 for x in xlist]\n", "print(xlist)\n", "print(ylist)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the next two cells to see the output.\n", "
"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": ["import matplotlib.pyplot as plt"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["plt.plot(xlist, ylist)\n", "plt.title(\"Embedded x vs y figure\")\n", "plt.xlabel(\"x\")\n", "plt.ylabel(\"y\")\n", "plt.legend([\"data\"])\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", "
\n", "Inline Exercise:\n", "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", "
"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": ["import math"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "\n", "\n", "# Todo: Generate the figure"]}, {"cell_type": "code", "execution_count": 21, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["x = list(np.linspace(0, 2 * math.pi, 100))\n", "\n", "# Todo: create the list for y\n", "y = [math.sin(xv) for xv in x]\n", "\n", "# Todo: Generate the figure\n", "plt.plot(x, y)\n", "plt.title(\"Trig: sin function\")\n", "plt.xlabel(\"x in radians\")\n", "plt.ylabel(\"sin(x)\")\n", "plt.show()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Importing and exporting data using Pandas\n", "\n", "Often, it is useful to output the data in a general format so it can be imported into other tools or presented in a familiar application. Python makes this easy with many great packages already available. The next code shows how to use the `pandas` package to create a dataframe and export the data to a csv file that we can import to excel. You could also consult [pandas documentation](https://pandas.pydata.org/pandas-docs/stable/) to see how to export the data directly to excel.\n", "
\n", "Inline Exercise:\n", "Execute the code below that shows how to import some data into a DataFrame from the Pandas package and then export this data to a csv file.\n", "
"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": ["import pandas as pd\n", "\n", "df_sin = pd.DataFrame({\"x\": x, \"sin(x) (radians)\": y})\n", "print(df_sin)\n", "df_sin.to_csv(\"sin_data.csv\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you go back to the browser tab that showed all the Jupyter notebook files and refresh, you will now see that there is a csv file with the x and y data. You can consult the Pandas documentation do learn about the many data analysis and statistical features of the `pandas` package.\n", "\n", "### Further Information\n", "\n", "Further information of the packages mentioned above can be found using the following links:\n", "\n", "* [numpy](https://numpy.org/devdocs/)\n", "* [matplotlib](https://matplotlib.org/)\n", "* [pandas](https://pandas.pydata.org/pandas-docs/stable/)\n"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Introduction to Pyomo\n", "\n", "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", "\n", "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", "* You can use Pyomo components to define your objective function or to create additional constraints.\n", "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", "\n", "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", "\n", "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", "
"]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": ["from pyomo.environ import ConcreteModel, Var\n", "\n", "model = ConcreteModel()\n", "model.x = Var()\n", "model.y = Var()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", "```python\n", "model.obj = Objective(expr=model.x**2)\n", "```\n", "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", "```python\n", "model.obj = Objective(expr=model.y, sense=maximize)\n", "```\n", "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", "\n", "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", "```python\n", "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", "```\n", "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", "```python\n", "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", "```\n", "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", "\n", "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", "\n", "
\n", "Inline Exercise:\n", "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", "
\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {"tags": ["exercise"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "\n", "\n", "# Todo: add the constraint here\n", "\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "code", "execution_count": 24, "metadata": {"tags": ["solution"]}, "outputs": [], "source": ["from pyomo.environ import Objective, Constraint, value, SolverFactory\n", "\n", "# Todo: add the objective function here\n", "model.obj = Objective(expr=model.x**2 + model.y**2)\n", "\n", "# Todo: add the constraint here\n", "model.con = Constraint(expr=model.x + model.y == 1)\n", "\n", "# now solve the problem\n", "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", "\n", "# print the values of x, y, and the objective function at the solution\n", "# Note that the results are automatically stored in the model variables\n", "print(\"x =\", value(model.x))\n", "print(\"y =\", value(model.y))\n", "print(\"obj =\", value(model.obj))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", "\n", "
\n", "Inline Exercise:\n", "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", "
"]}, {"cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": ["print(\"*** Output from model.pprint():\")\n", "model.pprint()\n", "\n", "print()\n", "print(\"*** Output from model.display():\")\n", "model.display()"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": []}], "metadata": {"celltoolbar": "Tags", "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.10.11"}}, "nbformat": 4, "nbformat_minor": 3} \ No newline at end of file diff --git a/idaes_examples/notebooks/held/tut/notebook_test_script.py b/idaes_examples/notebooks/docs/tut/notebook_test_script.py similarity index 100% rename from idaes_examples/notebooks/held/tut/notebook_test_script.py rename to idaes_examples/notebooks/docs/tut/notebook_test_script.py diff --git a/idaes_examples/notebooks/held/tut/sin_data.csv b/idaes_examples/notebooks/docs/tut/sin_data.csv similarity index 100% rename from idaes_examples/notebooks/held/tut/sin_data.csv rename to idaes_examples/notebooks/docs/tut/sin_data.csv diff --git a/idaes_examples/notebooks/held/tut/introduction_short_src.ipynb b/idaes_examples/notebooks/held/tut/introduction_short_src.ipynb deleted file mode 100644 index 4616f592..00000000 --- a/idaes_examples/notebooks/held/tut/introduction_short_src.ipynb +++ /dev/null @@ -1,965 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "73c88037", - "metadata": { - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[//]: #![idaes_icon](idaes_icon.png)\n", - "\n", - "

Welcome to the IDAES Workshop

" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Pyomo Import Checks: Passed\n", - "IDAES Import Checks: FAILED\n", - "Solver Availability Check: Passed\n", - "Simple Model Check: Passed\n", - "Something is not right. Please contact someone for assistance.\n" - ] - } - ], - "source": [ - "run \"notebook_test_script.py\"" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Pyomo Import Checks: Passed\n", - "IDAES Import Checks: FAILED\n", - "Solver Availability Check: Passed\n", - "Simple Model Check: Passed\n" - ] - }, - { - "ename": "AssertionError", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mAssertionError\u001B[0m Traceback (most recent call last)", - "\u001B[1;32m~\\AppData\\Local\\Temp\\ipykernel_13308\\216857602.py\u001B[0m in \u001B[0;36m\u001B[1;34m()\u001B[0m\n\u001B[0;32m 1\u001B[0m \u001B[1;32mfrom\u001B[0m \u001B[0midaes_examples\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mmod\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mnotebook_checks\u001B[0m \u001B[1;32mimport\u001B[0m \u001B[0mrun_checks\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m----> 2\u001B[1;33m \u001B[1;32massert\u001B[0m \u001B[0mrun_checks\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m)\u001B[0m \u001B[1;33m==\u001B[0m \u001B[1;36m4\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m", - "\u001B[1;31mAssertionError\u001B[0m: " - ] - } - ], - "source": [ - "from idaes_examples.mod.notebook_checks import run_checks\n", - "\n", - "assert run_checks() == 4" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", - "\n", - "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", - "\n", - "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", - "\n", - "You can execute a cell by pressing `Shift+Enter`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Outline of Workshop\n", - "\n", - "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", - "\n", - "Welcome Module (this one):\n", - "\n", - "* Introduction to Jupyter notebooks and Python\n", - "* Introduction to Pyomo\n", - "\n", - "Module 1 will cover:\n", - "\n", - "* how to import models from the core IDAES model library,\n", - "* how to create a model for a single unit operation,\n", - "* how to define feed and operating conditions,\n", - "* how to initialize and solve a single unit model,\n", - "* some ways we can manipulate the model and examine the results.\n", - "\n", - "Module 2 will demonstrate:\n", - "\n", - "* how to combine unit models together to form flowsheets,\n", - "* tools to initialize and solve flowsheets with recycle loops,\n", - "* how to optimize process operating conditions to meet product specifications.\n", - "\n", - "Module 3 will demonstrate:\n", - "\n", - "* how to build new unit models using the IDAES tools,\n", - "* how to include new unit models into flowsheets.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Introduction to Jupyter Notebooks and Python\n", - "\n", - "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", - "\n", - "There are many additional tutorials online to learn more about the Python syntax. One recommended by the IDAES team is https://www.coursera.org/learn/python." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: Assign a value of 5 to the variable x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Assign a value of 5 to the variable x\n", - "x = 5" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: print the value of x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: print the value of x\n", - "print(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "Inline Exercise:\n", - "Now change the value of the x variable to 8 and execute the cell.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: Assign a value of 8 to the variable x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Assign a value of 8 to the variable x\n", - "x = 8" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Jupyter notebooks and execution order\n", - "\n", - "
\n", - "Note:\n", - "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", - "
\n", - "\n", - "
\n", - "Inline Exercise:\n", - "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", - "
\n", - "\n", - "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", - "\n", - "**Again, notice that the state of the environment is determined by the execution order.**\n", - "\n", - "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", - "\n", - "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", - "\n", - "Some important commands to remember:\n", - "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", - "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", - "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", - "\n", - "To show the use of these commands, complete the following.\n", - "
\n", - "Inline Exercise:\n", - "
    \n", - "
  • Clear the current state (using Kernel | Restart & Clear Output). You should notice that the square brackets that listed the execution order are all now empty.
  • \n", - "
  • Select the cell immediately below this text\n", - "
  • Re-run all the code up to this point (Cell | Run All Above). You should now see that the square brackets indicate the expected execution order.
  • \n", - "
  • Print the value of x again using the print function. You should see the value 8 printed, while the earlier cell printing x shows the value of 5 as expected.
  • \n", - "
\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python `if` statements\n", - "\n", - "In the code below, we show an example of an `if` statement in Python.\n", - "\n", - "```python\n", - "temp = 325\n", - "# some other code\n", - "if temp > 320:\n", - " print('temperature is too high')\n", - "elif x < 290:\n", - " print('temperature is too low')\n", - "else:\n", - " print('temperature is just right')\n", - "```\n", - "\n", - "
\n", - "Note:\n", - "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", - "
\n", - "\n", - "Using the syntax above for the `if` statement, write the following code.\n", - "
\n", - "Inline Exercise:\n", - "
    \n", - "
  • set the value of the variable T_degC to 20
  • \n", - "
  • convert this from degrees Celsius to degrees Fahrenheit (use variable name T_degF)
  • \n", - "
  • write an `if` statement that prints a message if the degrees Fahrenheit are below 70
  • \n", - "
\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "T_degC = 20\n", - "# some other code\n", - "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", - "\n", - "# Todo: put the if statement here" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "T_degC = 20\n", - "# some other code\n", - "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", - "\n", - "# Todo: put the if statement here\n", - "if T_degF < 70:\n", - " print(\"The room is too cold.\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python list containers\n", - "\n", - "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", - "\n", - "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", - "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Complete the code block below to create the desired list and print the result.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Create a list with the values 0 to 50 with steps of 5.\n", - "xlist = list()\n", - "for i in range(11):\n", - " # Todo: use the append method of list to append the correct value\n", - "\n", - "# Todo: print the value of xlist to verify the results\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Create a list with the values 0 to 50 with steps of 5.\n", - "xlist = list()\n", - "for i in range(11):\n", - " # Todo: use the append method of list to append the correct value\n", - " xlist.append(i * 5)\n", - "\n", - "print(xlist) # Todo: print the value of xlist to verify the results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can easily check the length of a list using the python `len(l)` function.\n", - "
\n", - "Inline Exercise:\n", - "Print the length of `xlist`. It should be 11.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: print the len of the list" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "print(len(xlist)) # Todo: print the len of the list" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "ylist = list()\n", - "\n", - "# Todo: define the for loop to add elements to ylist using the values in xlist\n", - "\n", - "print(ylist)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "ylist = list()\n", - "\n", - "# Todo: define the for loop to add elements to ylist using the values in xlist\n", - "for x in xlist:\n", - " ylist.append(x**2)\n", - "\n", - "print(ylist)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python dictionary containers\n", - "\n", - "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", - "
\n", - "Inline Exercise:\n", - "Execute the lines below to see the areas dictionary.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "areas = dict()\n", - "areas[\"South Dakota\"] = 199742\n", - "areas[\"Oklahoma\"] = 181035\n", - "print(areas)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", - "\n", - "You can loop through dictionaries in different ways. For example,\n", - "```python\n", - "d = {'A': 2, 'B': 4, 'D': 16}\n", - "for k in d.keys():\n", - " # loop through the keys in the dictionary\n", - " # access the value with d[k]\n", - " print('key=', k, 'value=', d[k])\n", - " \n", - "for v in d.values():\n", - " # loop through the values in the dictionary, ignoring the keys\n", - " print('value=', v)\n", - " \n", - "for k,v in d.items():\n", - " # loop through the entries in the dictionary, retrieving both\n", - " # the key and the value\n", - " print('key=', k, 'value=', v)\n", - "```\n", - "\n", - "
\n", - "Inline Exercise:\n", - "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "areas_mi = dict()\n", - "for state_name, area in areas.items():\n", - " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", - "\n", - "print(areas_mi)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "areas_mi = dict()\n", - "for state_name, area in areas.items():\n", - " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", - " areas_mi[state_name] = area * (0.62137**2)\n", - "print(areas_mi)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Matplotlib for generating figures\n", - "\n", - "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", - "\n", - "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", - "
\n", - "Inline Exercise:\n", - "Execute the next two cells to see the output.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xlist = list(np.linspace(0, 50, 16))\n", - "ylist = [x**2 for x in xlist]\n", - "print(xlist)\n", - "print(ylist)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the next two cells to see the output.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.plot(xlist, ylist)\n", - "plt.title(\"Embedded x vs y figure\")\n", - "plt.xlabel(\"x\")\n", - "plt.ylabel(\"y\")\n", - "plt.legend([\"data\"])\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", - "
\n", - "Inline Exercise:\n", - "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import math" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "x = list(np.linspace(0, 2 * math.pi, 100))\n", - "\n", - "# Todo: create the list for y\n", - "\n", - "for xv in x:\n", - " y.append(math.sin(xv))\n", - "\n", - "# Todo: Generate the figure" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "x = list(np.linspace(0, 2 * math.pi, 100))\n", - "\n", - "# Todo: create the list for y\n", - "y = []\n", - "for xv in x:\n", - " y.append(math.sin(xv))\n", - "\n", - "# Todo: Generate the figure\n", - "plt.plot(x, y)\n", - "plt.title(\"Trig: sin function\")\n", - "plt.xlabel(\"x in radians\")\n", - "plt.ylabel(\"sin(x)\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Further Information\n", - "\n", - "Further information of the packages mentioned above can be found using the following links:\n", - "\n", - "* [numpy](https://numpy.org/devdocs/)\n", - "* [matplotlib](https://matplotlib.org/)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Introduction to Pyomo\n", - "\n", - "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", - "\n", - "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", - "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", - "* You can use Pyomo components to define your objective function or to create additional constraints.\n", - "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", - "\n", - "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", - "\n", - "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from pyomo.environ import ConcreteModel, Var\n", - "\n", - "model = ConcreteModel()\n", - "model.x = Var()\n", - "model.y = Var()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", - "```python\n", - "model.obj = Objective(expr=model.x**2)\n", - "```\n", - "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", - "```python\n", - "model.obj = Objective(expr=model.y, sense=maximize)\n", - "```\n", - "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", - "\n", - "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", - "```python\n", - "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", - "```\n", - "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", - "```python\n", - "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", - "```\n", - "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", - "\n", - "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "from pyomo.environ import Objective, Constraint, value, SolverFactory\n", - "\n", - "# Todo: add the objective function here\n", - "\n", - "\n", - "# Todo: add the constraint here\n", - "\n", - "\n", - "# now solve the problem\n", - "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", - "\n", - "# print the values of x, y, and the objective function at the solution\n", - "# Note that the results are automatically stored in the model variables\n", - "print(\"x =\", value(model.x))\n", - "print(\"y =\", value(model.y))\n", - "print(\"obj =\", value(model.obj))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "from pyomo.environ import Objective, Constraint, value, SolverFactory\n", - "\n", - "# Todo: add the objective function here\n", - "model.obj = Objective(expr=model.x**2 + model.y**2)\n", - "\n", - "# Todo: add the constraint here\n", - "model.con = Constraint(expr=model.x + model.y == 1)\n", - "\n", - "# now solve the problem\n", - "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", - "\n", - "# print the values of x, y, and the objective function at the solution\n", - "# Note that the results are automatically stored in the model variables\n", - "print(\"x =\", value(model.x))\n", - "print(\"y =\", value(model.y))\n", - "print(\"obj =\", value(model.obj))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Check the solution\n", - "\n", - "assert value(model.obj) == 0.5\n", - "assert value(model.x) == 0.5\n", - "assert value(model.y) == 0.5" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"*** Output from model.pprint():\")\n", - "model.pprint()\n", - "\n", - "print()\n", - "print(\"*** Output from model.display():\")\n", - "model.display()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "celltoolbar": "Tags", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/idaes_examples/notebooks/held/tut/introduction_src.ipynb b/idaes_examples/notebooks/held/tut/introduction_src.ipynb deleted file mode 100644 index 92ddfcfb..00000000 --- a/idaes_examples/notebooks/held/tut/introduction_src.ipynb +++ /dev/null @@ -1,1155 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "89bacb83", - "metadata": { - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[//]: #![idaes_icon](idaes_icon.png)\n", - "\n", - "

Welcome to the IDAES Workshop

" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Welcome and thank you for taking the time to attend today's workshop. Today we will introduce you to the fundamentals of working with the IDAES process modeling toolset, and we will demonstrate how these tools can be applied for optimization applications.\n", - "\n", - "Today's workshop will be conducted using Jupyter Notebooks which provide an online, interactive Python environment for you to use (without the need for installing anything).\n", - "\n", - "Before we get started on some actual examples, let's make sure that everything is working correctly. The cell below contains a command to run a simple test script that will test that everything we will need for today is working properly.\n", - "\n", - "You can execute a cell by pressing `Shift+Enter`." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Pyomo Import Checks: Passed\n", - "IDAES Import Checks: FAILED\n", - "Solver Availability Check: Passed\n", - "Simple Model Check: Passed\n", - "Something is not right. Please contact someone for assistance.\n" - ] - } - ], - "source": [ - "run \"notebook_test_script.py\"" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false, - "tags": [ - "testing" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Pyomo Import Checks: Passed\n", - "IDAES Import Checks: FAILED\n", - "Solver Availability Check: Passed\n", - "Simple Model Check: Passed\n" - ] - }, - { - "ename": "AssertionError", - "evalue": "1 notebook check(s) failed", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mAssertionError\u001B[0m Traceback (most recent call last)", - "\u001B[1;32m~\\AppData\\Local\\Temp\\ipykernel_7092\\4262110294.py\u001B[0m in \u001B[0;36m\u001B[1;34m()\u001B[0m\n\u001B[0;32m 1\u001B[0m \u001B[1;32mfrom\u001B[0m \u001B[0midaes_examples\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mmod\u001B[0m \u001B[1;32mimport\u001B[0m \u001B[0mnotebook_checks\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 2\u001B[0m \u001B[0mn\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mnotebook_checks\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mrun_checks\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m----> 3\u001B[1;33m \u001B[1;32massert\u001B[0m \u001B[0mn\u001B[0m \u001B[1;33m==\u001B[0m \u001B[1;36m4\u001B[0m\u001B[1;33m,\u001B[0m \u001B[1;34mf\"{4 - n} notebook check(s) failed\"\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m", - "\u001B[1;31mAssertionError\u001B[0m: 1 notebook check(s) failed" - ] - } - ], - "source": [ - "from idaes_examples.mod import notebook_checks\n", - "\n", - "n = notebook_checks.run_checks()\n", - "assert n == 4, f\"{4 - n} notebook check(s) failed\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If everything worked properly, you should see a message saying `All good!` and a summary of all the checks that were run. If you don't see this, please contact someone for assistance." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Outline of Workshop\n", - "\n", - "Today's workshop is divided into four modules which will take you through the steps of setting up a flowsheet within the IDAES framework.\n", - "\n", - "Welcome Module (this one):\n", - "\n", - "* Introduction to Jupyter notebooks and Python\n", - "* Introduction to Pyomo\n", - "\n", - "Module 1 will cover:\n", - "\n", - "* how to import models from the core IDAES model library,\n", - "* how to create a model for a single unit operation,\n", - "* how to define feed and operating conditions,\n", - "* how to initialize and solve a single unit model,\n", - "* some ways we can manipulate the model and examine the results.\n", - "\n", - "Module 2 will demonstrate:\n", - "\n", - "* how to combine unit models together to form flowsheets,\n", - "* tools to initialize and solve flowsheets with recycle loops,\n", - "* how to optimize process operating conditions to meet product specifications.\n", - "\n", - "Module 3 will demonstrate:\n", - "\n", - "* how to build new unit models using the IDAES tools,\n", - "* how to include new unit models into flowsheets.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Introduction to Jupyter Notebooks and Python\n", - "\n", - "In this short notebook, we will briefly describe the uses of Jupyter notebooks like this one, and provide you with the necessary background in Python for this workshop. We will cover `if` statements, looping, array-like containers called lists and dictionaries, as well as the use of some external packages for working with data. \n", - "\n", - "There are many additional tutorials online to learn more about the Python syntax." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In Python, variables do not need to be declared before they are used. You can simply define a new variable using `x = 5`.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "In the cell below, assign a value of 5 to the variable x. Don't forget to type Shift+Enter to execute the line.
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: Assign a value of 5 to variable x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Assign a value of 5 to variable x\n", - "x = 5" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can easily see the value of a variable using the built-in `print` function. For example, to print the value of `x` use `print(x)`.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Write the code to print the value of x. Don't forget to hit Shift+Enter to execute the cell.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: print the value of x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: print the value of x\n", - "print(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "Inline Exercise:\n", - "Now change the value of the x variable to 8 and execute the cell.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: Assign a value of 8 to variable x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Assign a value of 8 to variable x\n", - "x = 8" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Jupyter notebooks and execution order\n", - "\n", - "
\n", - "Note:\n", - "When using Jupyter notebooks, it is very important to know that the cells can be executed out of order (intentionally or not). The state of the environment (e.g., values of variables, imports, etc.) is defined by the execution order.\n", - "
\n", - "\n", - "
\n", - "Inline Exercise:\n", - "To see this concept, select the cell above that contained the print statement and execute the cell again using Shift+Enter.\n", - "
\n", - "\n", - "You should see that the value `8` is now printed. This may seem problematic if you are used to programming in environments where the state is linked to the order of the commands as *written*, not as *executed*.\n", - "\n", - "**Again, notice that the state of the environment is determined by the execution order.**\n", - "\n", - "Note also that the square brackets to the left of the cell show the order that cells were executed. If you scroll to the top, you should see that the code cells show an execution order of `[1]`, `[2]`, `[5]`, and `[4]`, indicating the actual execution order.\n", - "\n", - "There are some useful menu commands at the top of the Jupyter notebook to help with these problems and make sure you retain the execution order as expected.\n", - "\n", - "Some important commands to remember:\n", - "* You can clear the current state with the menu item `Kernel | Restart & Clear Output`\n", - "* It is often useful to clear the state using the menu command just described, and then execute all the lines **above the currently selected cell** using `Cell | Run All Above`.\n", - "* You can clear all the state and re-run the entire notebook using `Kernel | Restart & Run All`.\n", - "\n", - "To show the use of these commands, complete the following.\n", - "
\n", - "Inline Exercise:\n", - "
    \n", - "
  • Clear the current state (using Kernel | Restart & Clear Output). You should notice that the square brackets that listed the execution order are all now empty.
  • \n", - "
  • Select the cell immediately below this text\n", - "
  • Re-run all the code up to this point (Cell | Run All Above). You should now see that the square brackets indicate the expected execution order.
  • \n", - "
  • Print the value of x again using the print function. You should see the value 8 printed, while the earlier cell printing x shows the value of 5 as expected.
  • \n", - "
\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Print the value of x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Print the value of x\n", - "print(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python `if` statements\n", - "\n", - "In the code below, we show an example of an `if` statement in Python.\n", - "\n", - "```python\n", - "temp = 325\n", - "# some other code\n", - "if temp > 320:\n", - " print('temperature is too high')\n", - "elif x < 290:\n", - " print('temperature is too low')\n", - "else:\n", - " print('temperature is just right')\n", - "```\n", - "\n", - "
\n", - "Note:\n", - "You will notice that there are no braces to separate blocks in the if-else tree. In Python, indentation is used to delineate blocks of code throughout Python (e.g., if statements, for loops, functions, etc.). The indentation in the above example is not only to improve legibility of the code. It is necessary for the code to run correctly. As well, the number of spaces required to define the indentation is arbitrary, but it must be consistent throughout the code. For example, we could use 3 spaces (instead of the 4 used in the example above, but we could not use 3 for one of the blocks and 4 for another).\n", - "
\n", - "\n", - "Using the syntax above for the `if` statement, write the following code.\n", - "
\n", - "Inline Exercise:\n", - "
    \n", - "
  • set the value of the variable T_degC to 20
  • \n", - "
  • convert this from degrees Celsius to degrees Fahrenheit (use variable name T_degF)
  • \n", - "
  • write an `if` statement that prints a message if the degrees Fahrenheit are below 70
  • \n", - "
\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "T_degC = 20\n", - "# some other code\n", - "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", - "\n", - "# Todo: put the if statement here" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "T_degC = 20\n", - "# some other code\n", - "T_degF = (T_degC * 9.0 / 5.0) + 32.0\n", - "\n", - "# Todo: put the if statement here\n", - "if T_degF < 70:\n", - " print(\"The room is too cold.\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python list containers\n", - "\n", - "Now we will illustrate the use of lists in Python. Lists are similar to vectors or arrays in other languages. A list in Python is indexed by integers from 0 up to the length of the array minus 1. The list can contain standard types (int, float, string), or other objects.\n", - "\n", - "In the next inline exercise, we will create a list that contains the values from 0 to 50 by steps of 5 using a for loop. Note that the python function `range(n)` can be used to iterate from 0 to (n-1) in a for loop. Also note that lists have an `append` method which adds an entry to the end of the list (e.g., if the list `l` currently has 5 elements, then `l.append('temp')` will add the string \"temp\" as the sixth element). Print the new list after the for loop. If this is done correctly, you should see:\n", - "`[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]` printed after the cell.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Complete the code block below to create the desired list and print the result.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Create a list with the values 0 to 50 with steps of 5.\n", - "xlist = list()\n", - "for i in range(11):\n", - " # Todo: use the append method of list to append the correct value\n", - "\n", - "# Todo: print the value of xlist to verify the results\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Create a list with the values 0 to 50 with steps of 5.\n", - "xlist = list()\n", - "for i in range(11):\n", - " # Todo: use the append method of list to append the correct value\n", - " xlist.append(i * 5)\n", - "\n", - "# Todo: print the value of xlist to verify the results\n", - "print(xlist)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Python provides a short-hand notation for building lists called *list comprehensions*. An example of a list comprehension that creates all even numbers from 0 to 40 is:\n", - "\n", - "```python\n", - "values = [q*2 for q in range(21)]\n", - "```\n", - "\n", - "Note also that list comprehensions can include if clauses. For example, we could also implement the above example with the following code:\n", - "\n", - "```python\n", - "values = [q for q in range(41) if q % 2 == 0]\n", - "```\n", - "\n", - "Note that `%` is the modulus operator (it returns the remainder of the division). Therefore, in the above code, `q % 2` returns 0 if the value in `q` is exactly divisible by 2 (i.e., an even number).\n", - "\n", - "
\n", - "Inline Exercise:\n", - "In the cell below, create the same xlist that we created previously, but use the list comprehension notation. Verify that this result is correct by printing it.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: define the list comprehension" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: define the list comprehension\n", - "xlist = [i * 5 for i in range(11)]\n", - "print(xlist)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can easily check the length of a list using the python `len(l)` function.\n", - "
\n", - "Inline Exercise:\n", - "Print the length of `xlist`. It should be 11.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: print the len of the list" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: print the len of the list\n", - "print(len(xlist))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you have a list of values or objects, it is easy to iterate through that list in a for loop. In the next inline exercise, we will create another list, `ylist` where each of the values is equal to the corresponding value in `xlist` squared. That is, $y_i = x_i^2$.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Modify the code below to create ylist as described above. Print the values in ylist to check the result.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "ylist = list()\n", - "\n", - "# Todo: define the for loop to add elements to ylist using the values in xlist\n", - "\n", - "\n", - "print(ylist)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "ylist = list()\n", - "\n", - "# Todo: define the for loop to add elements to ylist using the values in xlist\n", - "for x in xlist:\n", - " ylist.append(x**2)\n", - "\n", - "print(ylist)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This same task could have been done with a list comprehension (using much less code).\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Write the list comprehension to compute the values of ylist. Print the values in ylist to check the result.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: create ylist using a list comprehension and print the result" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: create ylist using a list comprehension and print the result\n", - "ylist = [x**2 for x in xlist]\n", - "print(ylist)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python dictionary containers\n", - "\n", - "Another valuable data structure in Python are *dictionaries*. Dictionaries are an associative array; that is, a map from keys to values or objects. The keys can be *almost* anything, including floats, integers, and strings. The code below shows an example of creating a dictionary (here, to store the areas of some of the states).\n", - "
\n", - "Inline Exercise:\n", - "Execute the lines below to see the areas dictionary.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "areas = dict()\n", - "areas[\"South Dakota\"] = 199742\n", - "areas[\"Oklahoma\"] = 181035\n", - "print(areas)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Dictionaries can contain mixed types (i.e., it is valid to add `areas['Texas'] = 'Really big!'`) but this may lead to unpredictable behavior if the different types are unexpected in other parts of the code.\n", - "\n", - "You can loop through dictionaries in different ways. For example,\n", - "```python\n", - "d = {'A': 2, 'B': 4, 'D': 16}\n", - "for k in d.keys():\n", - " # loop through the keys in the dictionary\n", - " # access the value with d[k]\n", - " print('key=', k, 'value=', d[k])\n", - " \n", - "for v in d.values():\n", - " # loop through the values in the dictionary, ignoring the keys\n", - " print('value=', v)\n", - " \n", - "for k,v in d.items():\n", - " # loop through the entries in the dictionary, retrieving both\n", - " # the key and the value\n", - " print('key=', k, 'value=', v)\n", - "```\n", - "\n", - "
\n", - "Inline Exercise:\n", - "The areas listed above for the two states are in square kilometers. Modify the loop below to create a new dictionary that contains the areas in square miles. Print the new dictionary to verify the correct behavior. Note that 1 kilometer is equal to 0.62137 miles.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "areas_mi = dict()\n", - "for state_name, area in areas.items():\n", - " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", - " \n", - "print(areas_mi)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "areas_mi = dict()\n", - "for state_name, area in areas.items():\n", - " # Todo: convert the area to sq. mi and assign to the areas_mi dict.\n", - " areas_mi[state_name] = area * (0.62137**2)\n", - "print(areas_mi)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Python also supports dictionary comprehensions much like list comprehensions. For example:\n", - "```python\n", - "d = {'A': 2, 'B': 4, 'D': 16}\n", - "d2 = {k:v**2 for k,v in d.items()}\n", - "```\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Redo the conversion from square kilometers to square miles using a dictionary comprehension.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "# Todo: define areas_mi using a dictionary comprehension and print the result\n", - "\n", - "print(areas_mi)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: define areas_mi using a dictionary comprehension and print the result\n", - "areas_mi = {k: v * (0.62137**2) for k, v in areas.items()}\n", - "print(areas_mi)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Matplotlib for generating figures\n", - "\n", - "We will now briefly explore the use of the `matplotlib` package to generate figures. Before we do this, we will introduce some other helpful tools.\n", - "\n", - "Another effective way to create a list of evenly spaced numbers (e.g., for plotting or other computation) is to use the `linspace` function from the `numpy` package (more information [here](https://numpy.org/devdocs/)). Let's import the `numpy` package and use linspace function to create a list of 15 evenly spaced intervals (that is, 16 points) from 0 to 50 and store this in `xlist`. We will also create the `ylist` that corresponds to the square of the values in `xlist`. Note, we must first import the `numpy` package.\n", - "
\n", - "Inline Exercise:\n", - "Execute the next two cells to see the output.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xlist = list(np.linspace(0, 50, 16))\n", - "ylist = [x**2 for x in xlist]\n", - "print(xlist)\n", - "print(ylist)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This printed output is not a very effective way to communicate these results. Let's use matplotlib to create a figure of x versus y. A full treatment of the `matplotlib` package is beyond the scope of this tutorial, and further documentation can be found [here](https://matplotlib.org/). For now, we will import the plotting capability and show how to generate a straightforward figure. You can consult the documentation for matplotlib for further details.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the next two cells to see the output.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.plot(xlist, ylist)\n", - "plt.title(\"Embedded x vs y figure\")\n", - "plt.xlabel(\"x\")\n", - "plt.ylabel(\"y\")\n", - "plt.legend([\"data\"])\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will use what you have learned so far to create a plot of `sin(x)` for `x` from 0 to $2 \\pi$ with 100 points. Note, you can get the `sin` function and the value for $\\pi$ from the `math` package.\n", - "
\n", - "Inline Exercise:\n", - "Execute the import statement in the next cell, and then complete the missing code in the following cell to create the figure discussed above.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import math" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "x = list(np.linspace(0, 2 * math.pi, 100))\n", - "\n", - "# Todo: create the list for y\n", - "\n", - "\n", - "# Todo: Generate the figure" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "x = list(np.linspace(0, 2 * math.pi, 100))\n", - "\n", - "# Todo: create the list for y\n", - "y = [math.sin(xv) for xv in x]\n", - "\n", - "# Todo: Generate the figure\n", - "plt.plot(x, y)\n", - "plt.title(\"Trig: sin function\")\n", - "plt.xlabel(\"x in radians\")\n", - "plt.ylabel(\"sin(x)\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Importing and exporting data using Pandas\n", - "\n", - "Often, it is useful to output the data in a general format so it can be imported into other tools or presented in a familiar application. Python makes this easy with many great packages already available. The next code shows how to use the `pandas` package to create a dataframe and export the data to a csv file that we can import to excel. You could also consult [pandas documentation](https://pandas.pydata.org/pandas-docs/stable/) to see how to export the data directly to excel.\n", - "
\n", - "Inline Exercise:\n", - "Execute the code below that shows how to import some data into a DataFrame from the Pandas package and then export this data to a csv file.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "df_sin = pd.DataFrame({\"x\": x, \"sin(x) (radians)\": y})\n", - "print(df_sin)\n", - "df_sin.to_csv(\"sin_data.csv\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you go back to the browser tab that showed all the Jupyter notebook files and refresh, you will now see that there is a csv file with the x and y data. You can consult the Pandas documentation do learn about the many data analysis and statistical features of the `pandas` package.\n", - "\n", - "### Further Information\n", - "\n", - "Further information of the packages mentioned above can be found using the following links:\n", - "\n", - "* [numpy](https://numpy.org/devdocs/)\n", - "* [matplotlib](https://matplotlib.org/)\n", - "* [pandas](https://pandas.pydata.org/pandas-docs/stable/)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Introduction to Pyomo\n", - "\n", - "[Pyomo](https://www.pyomo.org) is an object-oriented, python-based package for equation-oriented (or *algebraic*) modeling and optimization, and the IDAES framework is built upon the Pyomo package. IDAES extends the Pyomo package and defines a class hierarchy for flowsheet based modeling, including definition of property packages, unit models, and flowsheets.\n", - "\n", - "The use of IDAES does not require extensive knowledge about Pyomo, however, it can be beneficial to have some familiarity with the Pyomo package for certain tasks:\n", - "* IDAES models are open, and you can interrogating the underlying Pyomo model to view the variables, constraints, and objective functions defined in the model.\n", - "* You can use Pyomo components to define your objective function or to create additional constraints.\n", - "* Since IDAES models **are** Pyomo models, any advanced meta-algorithms or analysis tools that can be developed and/or used on a Pyomo model can also be used on an IDAES model.\n", - "\n", - "A full tutorial on Pyomo is beyond the scope of this workshop, however in this section we will briefly cover the commands required to specify an objective function or add a constraint to an existing model.\n", - "\n", - "In the next cell, we will create a Pyomo model, and add a couple of variables to that model. When using IDAES, you will define a flowsheet and the addition of variables and model equations will be handled by the IDAES framework.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the following cell to create a Pyomo model with some variables that will be used later.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from pyomo.environ import ConcreteModel, Var\n", - "\n", - "model = ConcreteModel()\n", - "model.x = Var()\n", - "model.y = Var()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The Pyomo syntax to define a scalar objective function is shown below. This defines the objective function as $x^2$. By default Pyomo models (and IDAES models) seek to *minimize* the objective function.\n", - "```python\n", - "model.obj = Objective(expr=model.x**2)\n", - "```\n", - "To maximize a quantity, include the keyword argument `sense=maximize` as in the following:\n", - "```python\n", - "model.obj = Objective(expr=model.y, sense=maximize)\n", - "```\n", - "Note that `Objective` and `maximize` would need to be imported from `pyomo.environ`.\n", - "\n", - "The Pyomo syntax to define a scalar constraint is shown below. This code defines the equality constraint $x^2 + y^2 = 1$.\n", - "```python\n", - "model.on_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 == 1)\n", - "```\n", - "Pyomo also supports inequalities. For example, the code for the inequality constraint $x^2 + y^2 \\le 1$ is given as the following.\n", - "```python\n", - "model.inside_unit_circle_con = Constraint(expr=model.x**2 + model.y**2 <= 1)\n", - "```\n", - "Note that, as before, we would need to include the appropriate imports. In this case `Constraint` would need to be imported from `pyomo.environ`.\n", - "\n", - "Using the syntax shown above, we will now add the objective function: $\\min x^2 + y^2$ and the constraint $x + y = 1$.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Complete the missing code in the cell below. If this is done correctly, after executing the cell, you should see the log output from the solver and the printed solution should show that x, y, and the objective value are all equal to 0.5.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "exercise" - ] - }, - "outputs": [], - "source": [ - "from pyomo.environ import Objective, Constraint, value, SolverFactory\n", - "\n", - "# Todo: add the objective function here\n", - "\n", - "\n", - "# Todo: add the constraint here\n", - "\n", - "\n", - "# now solve the problem\n", - "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", - "\n", - "# print the values of x, y, and the objective function at the solution\n", - "# Note that the results are automatically stored in the model variables\n", - "print(\"x =\", value(model.x))\n", - "print(\"y =\", value(model.y))\n", - "print(\"obj =\", value(model.obj))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "from pyomo.environ import Objective, Constraint, value, SolverFactory\n", - "\n", - "# Todo: add the objective function here\n", - "model.obj = Objective(expr=model.x**2 + model.y**2)\n", - "\n", - "# Todo: add the constraint here\n", - "model.con = Constraint(expr=model.x + model.y == 1)\n", - "\n", - "# now solve the problem\n", - "status = SolverFactory(\"ipopt\").solve(model, tee=True) # tee=True shows the solver log\n", - "\n", - "# print the values of x, y, and the objective function at the solution\n", - "# Note that the results are automatically stored in the model variables\n", - "print(\"x =\", value(model.x))\n", - "print(\"y =\", value(model.y))\n", - "print(\"obj =\", value(model.obj))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that the code above also imported the `value` function. This is a Pyomo function that should be used to retrieve the value of variables in Pyomo (or IDAES) models. Note that you can display the complete list of all variables, objectives, and constraints (with their expressions) using `model.pprint()`. The `display` method is similar to the `pprint` method except that is shows the *values* of the constraints and objectives instead of the underlying expressions. The `pprint` and `display` methods can also be used on individual components.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the lines of code below to see the output from pprint and display for a Pyomo model.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# Check the solution\n", - "\n", - "assert value(model.obj) == 0.5\n", - "assert value(model.x) == 0.5\n", - "assert value(model.y) == 0.5" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"*** Output from model.pprint():\")\n", - "model.pprint()\n", - "\n", - "print()\n", - "print(\"*** Output from model.display():\")\n", - "model.display()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "celltoolbar": "Tags", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}