{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial\n", "\n", "This tutorial will guide you in the basic use of ThermoState. The ThermoState\n", "package is designed to ease the evaluation of thermodynamic properties for\n", "common substances used in Mechanical Engineering courses. Rather than looking up\n", "the information in a table and interpolating, we can input properties for the\n", "states directly, and all unknown values are automatically calculated." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ThermoState uses [CoolProp](http://www.coolprop.org/) and [Pint](https://pint.readthedocs.io) to enable easy property evaluation in any unit system. The first thing we need to do is import the parts of ThermoState that we will use. This adds them to the set of local variables" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "scrolled": true }, "outputs": [], "source": [ "from thermostate import State, Q_, units" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pint and Units\n", "\n", "Now that the interface has been imported, we can create some properties. For instance, let's say we're given the pressure and temperature properties for water, and asked to determine the specific volume. First, let's create variables that set the pressure and temperature. We will use the Pint `Quantity` function, which we have called `Q_`. The syntax for the `Q_` function is `Q_(value, 'units')`." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "scrolled": true }, "outputs": [], "source": [ "p_1 = Q_(101325, \"Pa\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use whatever units we'd like, Pint supports a wide variety of units." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "scrolled": true }, "outputs": [], "source": [ "p_1 = Q_(1.01325, \"bar\")\n", "p_1 = Q_(14.7, \"psi\")\n", "p_1 = Q_(1.0, \"atm\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another way to specify the units is to use the `units` class that we imported. This class has a number of attributes (text following a period) that can be used to create a quantity with units by multiplying a number with the unit. \n", "\n", "```python\n", "units.degR\n", "# ^^^^\n", "# This is the attribute\n", "```\n", "\n", "Let's set the temperature now. The available units of temperature are `degF` (`fahrenheit`), `degR` (`rankine`), `degC` (`celsius`), and `K` (`kelvin`)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "scrolled": true }, "outputs": [], "source": [ "T_1 = 460 * units.degR\n", "T_1 = 25 * units.degC\n", "T_1 = 75 * units.degF\n", "T_1 = 400 * units.K" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The two ways of creating the units are equivalent. The following cell should print `True` to demonstrate this." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Q_(101325, \"Pa\") == 1.0 * units.atm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note the convention we are using here: the variables are named with the property, followed by an underscore, then the number of the state. In this case, we are setting properties for state 1, hence `T_1` and `p_1`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ThermoState\n", "\n", "Now that we have defined two properties with units, let's define a state. First, we create a variable to hold the `State` and tell ThermoState what substance we want to use with that state. The available substances are:\n", "\n", "* `water`\n", "* `air`\n", "* `R134a`\n", "* `R22`\n", "* `propane`\n", "* `ammonia`\n", "* `isobutane`\n", "* `carbondioxide`\n", "* `oxygen`\n", "* `nitrogen`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the name of the substance is case-insensitive (it doesn't matter whether you use lower case or upper case). It is often easiest to set the name of the substance in a variable, like:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "substance = \"water\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we need to create the `State` and assign values for the properties. Properties of the state are set as arguments to the `State` class, and they must always be set in pairs, we cannot set a single property at a time. The syntax is\n", "\n", " st = State(substance, property_1=value, property_2=value)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Warning**\n", "\n", "Remember that two independent and intensive properties are required to set the state!\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To demonstrate, we will set the `T` and `p` properties of the state and set them equal to the temperature and pressure we defined above. Note that the capitalization of the properties is important! The `p` is lower case while the `T` is upper case (lower case `t` means time)." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "T = 400 kelvin, p = 1.0 standard_atmosphere\n" ] } ], "source": [ "print(\"T = {}, p = {}\".format(T_1, p_1))" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": true }, "outputs": [], "source": [ "st_1 = State(substance, T=T_1, p=p_1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note again the convention we are using here: The state is labeled by `st`, then an underscore, then the number of the state.\n", "\n", "The variables that we use on the right side of the equal sign in the `State` function can be named anything we want. For instance, the following code is exactly equivalent to what we did before." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Does luke equal p_1? True\n", "Does leia equal T_1? True\n", "Does st_starwars equal st_1? True\n" ] } ], "source": [ "luke = Q_(1.0, \"atm\")\n", "leia = Q_(400.0, \"K\")\n", "print(\"Does luke equal p_1?\", luke == p_1)\n", "print(\"Does leia equal T_1?\", leia == T_1)\n", "st_starwars = State(substance, T=leia, p=luke)\n", "print(\"Does st_starwars equal st_1?\", st_starwars == st_1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Warning**\n", "\n", "To avoid confusing yourself, name your variables to something useful. For instance, use the property symbol, then an underscore, then the state number, as in `p_1 = Q_(1.0, 'atm')` to indicate the pressure at state 1. In my notes and solutions, this is the convention that I will follow, and I will use `st_#` to indicate a `State` (e.g., `st_1` is state 1, `st_2` is state 2, and so forth).\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In theory, any two pairs of independent properties can be used to set the state. In reality, the pairs of properties available to set the state is slightly limited because of the way the equation of state is written. The available pairs of properties are\n", "\n", "* `Tp`\n", "* `Ts`\n", "* `Tv`\n", "* `Tx`\n", "* `pu`\n", "* `ps`\n", "* `pv`\n", "* `ph`\n", "* `px`\n", "* `uv`\n", "* `sv`\n", "* `hs`\n", "* `hv`\n", "\n", "The reverse of any of these pairs is also possible and totally equivalent.\n", "\n", "By setting two properties in this way, the `State` class will calculate all the other properties we might be interested in. We can access the value of any property by getting the attribute for that property. The available properties are `T` (temperature), `p` (pressure), `v` (mass-specific volume), `u` (mass-specific internal energy), `h` (mass-specific enthalpy), `s` (mass-specific entropy), `x` (quality), `cp` (specific heat at constant pressure), `cv` (specific heat at constant volume), and `phase` (the phase of this state). The syntax is\n", "\n", " State.property\n", " \n", "or\n", "\n", " st_1.T # Gets the temperature\n", " st_1.p # Gets the pressure\n", " st_1.v # Gets the specific volume\n", " st_1.u # Gets the internal energy\n", " st_1.h # Gets the enthalpy\n", " st_1.s # Gets the entropy\n", " st_1.x # Gets the quality\n", " st_1.cp # Gets the specific heat at constant pressure\n", " st_1.cv # Gets the specific heat at constant volume\n", " st_1.phase # Gets the phase at this state\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Note**\n", "\n", "Capitalization is important! The temperature has upper case `T`, while the other properties are lower case to indicate that they are mass-specific quantities.\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "T_1 = 400.0 kelvin\n", "p_1 = 101324.99999999953 pascal\n", "v_1 = 1.801983936953226 meter ** 3 / kilogram\n", "u_1 = 2547715.3635084038 joule / kilogram\n", "h_1 = 2730301.3859201893 joule / kilogram\n", "s_1 = 7496.2021523754065 joule / kelvin / kilogram\n", "x_1 = None\n", "cp_1 = 2009.2902478486988 joule / kelvin / kilogram\n", "cv_1 = 1509.1482452129906 joule / kelvin / kilogram\n", "phase_1 = gas\n" ] } ], "source": [ "print(\"T_1 = {}\".format(st_1.T))\n", "print(\"p_1 = {}\".format(st_1.p))\n", "print(\"v_1 = {}\".format(st_1.v))\n", "print(\"u_1 = {}\".format(st_1.u))\n", "print(\"h_1 = {}\".format(st_1.h))\n", "print(\"s_1 = {}\".format(st_1.s))\n", "print(\"x_1 = {}\".format(st_1.x))\n", "print(\"cp_1 = {}\".format(st_1.cp))\n", "print(\"cv_1 = {}\".format(st_1.cv))\n", "print(\"phase_1 = {}\".format(st_1.phase))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, the value for the quality is the special Python value `None`. This is because at 400 K and 101325 Pa, the state of water is a **superheated vapor** and the quality is **undefined** except in the vapor dome. To access states in the vapor dome, we cannot use `T` and `p` as independent properties, because they are not independent inside the vapor dome. Instead, we have to use the pairs involving the other properties (possibly including the quality) to set the state. When we define the quality, the units are `dimensionless` or `percent`. For instance:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "T_2 = 373.15 kelvin\n", "p_2 = 101417.99665788242 pascal\n", "v_2 = 0.16811572834411828 meter ** 3 / kilogram\n", "u_2 = 627756.5746698529 joule / kilogram\n", "h_2 = 644806.535045544 joule / kilogram\n", "s_2 = 1911.9019425021506 joule / kelvin / kilogram\n", "x_2 = 0.1 dimensionless\n" ] } ], "source": [ "T_2 = Q_(100.0, \"degC\")\n", "x_2 = Q_(0.1, \"dimensionless\")\n", "st_2 = State(\"water\", T=T_2, x=x_2)\n", "print(\"T_2 = {}\".format(st_2.T))\n", "print(\"p_2 = {}\".format(st_2.p))\n", "print(\"v_2 = {}\".format(st_2.v))\n", "print(\"u_2 = {}\".format(st_2.u))\n", "print(\"h_2 = {}\".format(st_2.h))\n", "print(\"s_2 = {}\".format(st_2.s))\n", "print(\"x_2 = {}\".format(st_2.x))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition, whether you use the `'dimensionless'` \"units\" for the quality as above, or use the `'percent'` \"units\", the result is exactly equivalent. The next cell should print `True` to the screen to demonstrate this." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x_2 == Q_(10.0, \"percent\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "From these results, we can see that the units of the units of the properties stored in the `State` are always SI units - Kelvin, Pascal, m3/kg, J/kg, and J/(kg-Kelvin). We can use the `to` function to convert the units to anything we want, provided the dimensions are compatible. The syntax is `State.property.to('units')`." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "211.99999999999991 degree_Fahrenheit\n", "0.4566498699316826 british_thermal_unit / degree_Rankine / pound\n" ] } ], "source": [ "print(st_2.T.to(\"degF\"))\n", "print(st_2.s.to(\"BTU/(lb*degR)\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Note**\n", "\n", "The values are always converted in the `State` to SI units, no matter what the input units are. Therefore, if you want EE units as an output, you have to convert.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we try to convert to a unit with incompatible dimensions, Pint will raise a `DimenstionalityError` exception.\n", "\n", "
\n", "\n", "**Warning**\n", "\n", "If you get a `DimensionalityError`, examine your conversion very closely. The error message will tell you why the dimensions are incompatible!\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "scrolled": false }, "outputs": [ { "ename": "DimensionalityError", "evalue": "Cannot convert from 'kelvin' ([temperature]) to 'joule' ([length] ** 2 * [mass] / [time] ** 2)", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mDimensionalityError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mst_2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mT\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'joule'\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[0m", "\u001b[1;31mDimensionalityError\u001b[0m: Cannot convert from 'kelvin' ([temperature]) to 'joule' ([length] ** 2 * [mass] / [time] ** 2)" ] } ], "source": [ "print(st_2.T.to(\"joule\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we have tried to convert from `'kelvin'` to `'joule'` and the error message **which is the last line** says\n", " \n", " DimensionalityError: Cannot convert from 'kelvin' ([temperature]) to 'joule' ([length] ** 2 * [mass] / [time] ** 2)\n", " \n", "The dimensions of a temperature are, well, temperature. The formula for energy (Joule) is $m*a*d$ (mass times acceleration times distance), and in terms of dimensions, $M*L/T^2*L = L^2*M/T^2$ (where in dimensions, capital $T$ is time). Clearly, these dimensions are incompatible. A more subtle case might be trying to convert **energy** to **power** (again, not allowed):" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "scrolled": false }, "outputs": [ { "ename": "DimensionalityError", "evalue": "Cannot convert from 'joule' ([length] ** 2 * [mass] / [time] ** 2) to 'watt' ([length] ** 2 * [mass] / [time] ** 3)", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mDimensionalityError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mQ_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1000.0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'joule'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'watt'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;31m## Other Common Errors\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mDimensionalityError\u001b[0m: Cannot convert from 'joule' ([length] ** 2 * [mass] / [time] ** 2) to 'watt' ([length] ** 2 * [mass] / [time] ** 3)" ] } ], "source": [ "Q_(1000.0, \"joule\").to(\"watt\") ## Other Common Errors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Default Units" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Default units can be set either through the `set_default_units(\"units\")` function, when creating a state, or after a state has been set to change the units of the state. Units can be set either with `\"SI\"` or `\"EE\"` for the corresponding sets of units, or `None` to reset the default units." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.7566087533509436 british_thermal_unit / degree_Rankine / pound\n", "7.354570555884304 kilojoule / kelvin / kilogram\n", "7354.570555884259 joule / kelvin / kilogram\n" ] } ], "source": [ "from thermostate import set_default_units\n", "\n", "set_default_units(\"EE\")\n", "\n", "st_3 = State(\"water\", T=Q_(100, \"degC\"), p=Q_(1.0, \"atm\"))\n", "print(\"These will be EE units because we set the default for all states above:\", st_3.s)\n", "\n", "st_4 = State(\"water\", T=Q_(100, \"degC\"), p=Q_(1.0, \"atm\"), units=\"SI\")\n", "print(\n", " \"These will be pseudo-SI units that use kJ, which were set as the default when creating this state:\",\n", " st_4.s,\n", ")\n", "\n", "st_4.units = None\n", "print(\n", " \"These will be true SI units, because we reset the default units for this state:\",\n", " st_4.s,\n", ")\n", "\n", "# Calling this again with None will reset the default units for all created states to true SI\n", "set_default_units(None)\n", "\n", "st_5 = State(\"water\", T=Q_(100.0, \"degC\"), p=Q_(1.0, \"atm\"))\n", "print(\"These are true SI units, set by the set_default_units:\", st_5.s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Other Common Errors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other common errors generated from using ThermoState will raise `StateErrors`. These errors may be due to\n", "\n", "1. Not specifying enough properties to fix the state, or specifying too many properties to fix the state\n", "2. Specifying a pair of properties that are not independent at the desired condtions\n", "3. Entering an unsupported pair of property inputs (the currently unsupported pairs are `Tu`, `Th`, and `us`, due to limitations in CoolProp)\n", "4. Specifying a `Quantity` with incorrect dimensions for the property input\n", "\n", "An example demonstrating #4 from above:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "ename": "StateError", "evalue": "The dimensions for v must be [length] ** 3 / [mass]", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mStateError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mState\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'water'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mv\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mQ_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1000.0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'degC'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mQ_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1.0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'bar'\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[0m", "\u001b[1;32mc:\\users\\user\\documents\\github\\thermostate\\src\\thermostate\\thermostate.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, substance, label, units, **kwargs)\u001b[0m\n\u001b[0;32m 317\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 318\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_props\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m>\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 319\u001b[1;33m \u001b[0msetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0minput_props\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0minput_props\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0minput_props\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\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[0m\u001b[0;32m 320\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 321\u001b[0m \u001b[1;33m@\u001b[0m\u001b[0mproperty\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32mc:\\users\\user\\documents\\github\\thermostate\\src\\thermostate\\thermostate.py\u001b[0m in \u001b[0;36m__setattr__\u001b[1;34m(self, key, value)\u001b[0m\n\u001b[0;32m 222\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;31m# pragma: no cover, for typing\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 223\u001b[0m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Must pass a tuple of Quantities\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 224\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_dimensions\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 225\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_values\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 226\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_set_properties\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32mc:\\users\\user\\documents\\github\\thermostate\\src\\thermostate\\thermostate.py\u001b[0m in \u001b[0;36m_check_dimensions\u001b[1;34m(self, properties, values)\u001b[0m\n\u001b[0;32m 387\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mvalid\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 388\u001b[0m raise StateError(\n\u001b[1;32m--> 389\u001b[1;33m \u001b[1;34mf\"The dimensions for {p} must be {self._dimensions[p]}\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 390\u001b[0m )\n\u001b[0;32m 391\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mStateError\u001b[0m: The dimensions for v must be [length] ** 3 / [mass]" ] } ], "source": [ "State(\"water\", v=Q_(1000.0, \"degC\"), p=Q_(1.0, \"bar\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "\n", "In summary, we need to use two (2) **independent and intensive** properties to fix the state of any simple compressible system. We need to define these quantities with units using Pint, and then use them to set the conditions of a State. Then, we can access the other properties of the State by using the attributes." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "T_5 = 666.0536816976219 kelvin\n", "p_5 = 669560197.2594488 pascal\n", "v_5 = 0.0010136928689306796 meter ** 3 / kilogram\n", "u_5 = 1321271.6027173044 joule / kilogram\n", "h_5 = 1999999.9999990265 joule / kilogram\n", "s_5 = 3099.999999999998 joule / kelvin / kilogram\n", "x_5 = None\n" ] } ], "source": [ "h_5 = Q_(2000.0, \"kJ/kg\")\n", "s_5 = Q_(3.10, \"kJ/(kg*K)\")\n", "st_5 = State(\"water\", h=h_5, s=s_5)\n", "print(\"T_5 = {}\".format(st_5.T))\n", "print(\"p_5 = {}\".format(st_5.p))\n", "print(\"v_5 = {}\".format(st_5.v))\n", "print(\"u_5 = {}\".format(st_5.u))\n", "print(\"h_5 = {}\".format(st_5.h))\n", "print(\"s_5 = {}\".format(st_5.s))\n", "print(\"x_5 = {}\".format(st_5.x))" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": ".venv", "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.7" }, "vscode": { "interpreter": { "hash": "fb7bc785118bb4360cab2bc3a7c18a4172b91ba838a1a0de23ea670f85cf526f" } } }, "nbformat": 4, "nbformat_minor": 2 }