From 355c4b4bd35bdaf536744fc57c38a23fd7fc26c0 Mon Sep 17 00:00:00 2001 From: Kyle Gorkowski Date: Sat, 25 May 2024 11:32:04 -0600 Subject: [PATCH] abstracted builder checks and added draft examples --- docs/documentation/next/next_gas.ipynb | 412 +++++++++++++ .../documentation/next/next_gas_species.ipynb | 553 ++++++++++++++++++ .../next/next_vapor_pressure.ipynb | 19 +- .../gas/tests/vapor_pressure_builders_test.py | 10 +- .../tests/vapor_pressure_factories_test.py | 2 +- particula/next/gas/vapor_pressure_builders.py | 270 ++++++--- 6 files changed, 1176 insertions(+), 90 deletions(-) create mode 100644 docs/documentation/next/next_gas.ipynb create mode 100644 docs/documentation/next/next_gas_species.ipynb diff --git a/docs/documentation/next/next_gas.ipynb b/docs/documentation/next/next_gas.ipynb new file mode 100644 index 000000000..ae2e8ebf5 --- /dev/null +++ b/docs/documentation/next/next_gas.ipynb @@ -0,0 +1,412 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Gases\n", + "\n", + "**This may get cut, as calling GasSpecies may be enough for all use cases. We'll see after gas phase processes**\n", + "\n", + "Gases, alongside particles, constitute the essential components of an aerosol system. In their natural state, gases are collections of molecules that move freely, not bound to one another. We introduce the `Gas` class, a composite that aggregates multiple `GasSpecies` objects, each representing type of gas or gases.\n", + "\n", + "- **`Gas`**: Functions as a composite object capable of encompassing multiple `GasSpecies`, facilitating the management and operation of gas mixtures as coherent wholes.\n", + "Shared properties are `total_pressure` and `temperature`.\n", + "- **`GasBuilder`**: A builder class that simplifies the creation of `Gas` objects.\n", + "\n", + "We'll continue with our organics and water example, combining the two into a single `Gas` object." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# From particula\n", + "from particula.next.gas import Gas, GasBuilder\n", + "from particula.next.gas_vapor_pressure import vapor_pressure_factory\n", + "from particula.next.gas_species import GasSpeciesBuilder" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Build Gas Species\n", + "\n", + "First we will build the, `GasSpecies` objects for the organics and water. Following the same procedure from previously in [`Gas Species`](./next_gas_species.ipynb)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Define the coefficients for Butanol using the Antoine equation.\n", + "butanol_coefficients = {'a': 7.838, 'b': 1558.19, 'c': 196.881}\n", + "butanol_antione = vapor_pressure_factory(\n", + " strategy='antoine', **butanol_coefficients)\n", + "styrene_coefficients = {'a': 6.924, 'b': 1420, 'c': 226}\n", + "styrene_antione = vapor_pressure_factory(\n", + " strategy='antoine', **styrene_coefficients)\n", + "\n", + "# Water uses a different model for vapor pressure calculation called the Buck equation.\n", + "water_buck = vapor_pressure_factory(\n", + " strategy='water_buck')\n", + "\n", + "# Create the GasSpecies using the GasSpeciesBuilder\n", + "# water species\n", + "water_species = GasSpeciesBuilder() \\\n", + " .name(\"Water\") \\\n", + " .molar_mass(0.01801528) \\\n", + " .vapor_pressure_strategy(water_buck) \\\n", + " .condensable(True) \\\n", + " .concentration(0.017) \\\n", + " .build()\n", + "\n", + "# organic species\n", + "organic_molar_mass = np.array([0.074121, 104.15e-3])\n", + "organic_vapor_pressure = [butanol_antione, styrene_antione]\n", + "organic_concentration = np.array([2e-6, 1e-9])\n", + "organic_names = np.array([\"butanol\", \"styrene\"])\n", + "organic_species = GasSpeciesBuilder() \\\n", + " .name(organic_names) \\\n", + " .molar_mass(organic_molar_mass) \\\n", + " .vapor_pressure_strategy(organic_vapor_pressure) \\\n", + " .condensable([True, True]) \\\n", + " .concentration(organic_concentration) \\\n", + " .build()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## GasBuilder\n", + "\n", + "The `GasBuilder` class is a builder class that simplifies the creation of `Gas` objects. It provides a fluent interface for adding `GasSpecies` objects to the `Gas` object. We will use it to build the `Gas` object for the organics and water. The `GasBuilder` requries the following parameters:\n", + "\n", + "- `total_pressure`: The total pressure of the gas mixture, in Pascals.\n", + "- `temperature`: The temperature of the gas mixture, in Kelvin.\n", + "- `species`: A list of `GasSpecies` objects, representing the gases in the mixture. This can be added one by one using the `species` method.\n", + "\n", + "### Air\n", + "\n", + "Air is assumed to be the non-specified component of the gas mixture, making up the remainder of the gas mixture. We do not explicitly add air to the gas mixture, but it is implicitly included in most calculations." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Gas mixture at 300 K and 101325 Pa consisting of ['Water', \"['butanol' 'styrene']\"]\n" + ] + } + ], + "source": [ + "gas_mixture = GasBuilder() \\\n", + " .add_species(water_species) \\\n", + " .add_species(organic_species) \\\n", + " .temperature(300) \\\n", + " .total_pressure(101325) \\\n", + " .build()\n", + "\n", + "print(gas_mixture)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Iterating Over Gas Species\n", + "\n", + "Once the `Gas` object has been established, it enables us to iterate over each `GasSpecies` within the mixture. This functionality is particularly valuable for evaluating and adjusting properties dynamically, such as when changes in temperature and pressure occur due to environmental alterations.\n", + "\n", + "### Practical Example: Altitude Impact\n", + "\n", + "Consider a scenario where our gas mixture is transported from sea level to an altitude of 10 kilometers. Such a change in altitude significantly impacts both temperature and pressure, which in turn affects the behavior of each gas species in the mixture.\n", + "\n", + "#### Geopotential Height Equation\n", + "\n", + "The pressure and temperature changes with altitude can be approximated by using the geopotential height equation. Here's how you can calculate these changes:\n", + "\n", + "1. **Pressure Change**: The pressure at a given altitude can be estimated by:\n", + " \n", + "$$\n", + " P = P_0 \\left(1 - \\frac{L \\cdot h}{T_0}\\right)^{\\frac{g \\cdot M}{R \\cdot L}}\n", + "$$\n", + "\n", + " where:\n", + " - $ P $ is the pressure at altitude $ h $,\n", + " - $ P_0 $ is the reference pressure at sea level (101325 Pa),\n", + " - $ L $ is the standard temperature lapse rate (approximately 0.0065 K/m),\n", + " - $ h $ is the altitude in meters (10000 m for 10 km),\n", + " - $ T_0 $ is the reference temperature at sea level (288.15 K),\n", + " - $ g $ is the acceleration due to gravity (9.80665 m/s²),\n", + " - $ M $ is the molar mass of Earth's air (0.0289644 kg/mol),\n", + " - $ R $ is the universal gas constant (8.314 J/(mol·K)).\n", + "\n", + "1. **Temperature Change**: The temperature decreases linearly with altitude at the lapse rate $ L $:\n", + " \n", + " $$\n", + " T = T_0 - L h\n", + " $$\n", + "\n", + " Using this formula, we can estimate the temperature at an altitude of 10 km:\n", + " - $T$ = 288.15 K \n", + " - $L$ 0.0065 K/m\n", + " - $h$ = 10000 m\n", + "\n", + "### Application\n", + "By iterating through each `GasSpecies`, we can apply these formulas to adjust their properties based on the calculated pressure and temperature at 10 km altitude, aiding in simulations or real-world applications where altitude plays a crucial role in gas behavior.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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CpaX1zMjIwPPnz/HO++8AwC4ePGipqun5sCBA2jevLlaHyFjY2MMHToUDx8+xM2bN9/4WgAYP3682vQvv/wSAArcTpp4uV8TkNufydHREc7OznB3d4elpaXqV2Pef/Neo6Ojo+q/olQqERcXh5ycHDRt2lSjbRQXF4d///0XPXv2RHJyMp4/f47nz5/jxYsX8PPzw927d/H06VO11wwZMkTjfmf9+vVDRkYGdu3apZq2efNmAEDfvn1V017+t46Pj0diYiJat25d4Dp4eXnB09NT9dzZ2RkffvghDh8+DIVCAYVCgSNHjqBr166oXr26qp29vT369OmD06dPIykpqUjr9Lbb+20YGxsjOTm52Ja3Y8cOmJmZ4b333lP9uz9//hyenp4wNjZGYGCgWvuC9kc7duxA69atYWFhobYMX19fKBQKnDx5Uq39J598AgsLC9Xz1q1bA4DG+46C5OTkYNu2bfjkk08gkUgAAO3atYONjQ02bdpU5OWWhLx97eeff67W72zAgAEwMzNTa7tjxw7UqVMH7u7uatu2Xbt2AKD698k7Or9nz54iX4Fc2hiayrlmzZph165diI+PR0hICKZMmYLk5GT06NFD7Uv0zJkz8PX1hZGREczNzWFtba06/FtSoakgxV3Ho0ePAEB1+u9l7u7uqvl59PX1853+srCwQHx8vEbv5+LigqNHj+Lw4cNYtmwZHB0dERsbm6/TZVxcHL744gvY2trCwMAA1tbWqm1S1O396NGjAtcz73TFq+v66mulUilq1qypNt3Ozg7m5uZvfO2b1KtXD+bm5mrBKO+0lUQigZeXl9o8JycnODs7q16/fv16NGjQAPr6+rCysoK1tTX279+v0Ta6d+8ehBCYNm2aKsjmPWbMmAEg/wURr/tcFuT999+HpaWlKigBwJYtW9CwYUPUrVtXNW3fvn145513oK+vD0tLS9UproLWoVatWvmm1a5dG2lpaYiNjUVsbCzS0tJe+++sVCrx+PHjIq/T22zvt5GSkgITE5NiW97du3eRmJgIGxubfP/2KSkpGv273717F4cOHcr3el9fXwD5Pzsvf24BqAKUpvuOghw5cgSxsbFo3rw57t27h3v37iE8PBw+Pj7YsmVLmQoSefuIVz/Denp6agEfyN22N27cyLdta9euDeB/2/aTTz5By5Yt8dlnn8HW1ha9evXC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t2nTpq8d3DIrK0v8+OOPom7dukIulwsLCwvh6ekpZs6cqRrG49ixY+LDDz8UDg4OQiaTCQcHB9G7d+98w0CUJRIh3qIXGxERaUQikWDkyJH45ZdftF0KERUR+zQRERERaYChiYiIiEgDDE1EREREGuDVc0REpYDdR4nKPx5pIiIiItIAQxMRERGRBnh6rpgolUo8e/YMJiYmxX4bAiIiIioZQggkJyfDwcHhjYMEAwxNxebZs2dFvicUERERadfjx4/VbpNUEIamYmJiYgIgd6MX9d5QREREVLqSkpLg5OSk+h5/E4amYpJ3Ss7U1JShiYiIqJzRpGsNO4ITERERaYChiYiIiEgDPD1XyhQKBbKzs7VdRoUlk8n+8+oHIiKiomBoKiVCCERFRSEhIUHbpVRoUqkUrq6ukMlk2i6FiIgqGIamUpIXmGxsbGBoaMixnEpA3lhZkZGRcHZ25jYmIqJixdBUChQKhSowWVlZabucCs3a2hrPnj1DTk4O9PT0tF0OERFVIOz8UQry+jAZGhpquZKKL++0nEKh0HIlRERU0TA0lSKeLip53MZERFRSGJqIiIiINMDQRERERKQBrYamkydPonPnznBwcIBEIsHu3bvV5gshMH36dNjb28PAwAC+vr64e/euWpu4uDj07dsXpqamMDc3x+DBg5GSkqLW5urVq2jdujX09fXh5OSEefPm5atlx44dcHd3h76+PurXr48DBw4U+/oSERFR+aXV0JSamoqGDRvi119/LXD+vHnzsHTpUqxYsQLBwcEwMjKCn58fMjIyVG369u2LGzdu4OjRo9i3bx9OnjyJoUOHquYnJSWhQ4cOqFatGkJDQzF//nx8++23WLlyparN2bNn0bt3bwwePBiXLl1C165d0bVrV1y/fr3kVr4cWLFiBUxMTJCTk6OalpKSAj09PbRt21at7fHjxyGRSHD//v03LjOvHcerIiKiwhBCQKkUWi+iTAAg/vrrL9VzpVIp7OzsxPz581XTEhIShFwuF1u2bBFCCHHz5k0BQJw/f17V5uDBg0IikYinT58KIYRYtmyZsLCwEJmZmao2kyZNEm5ubqrnPXv2FP7+/mr1tGjRQgwbNuy19WZkZIjExETV4/HjxwKASExMzNc2PT1d3Lx5U6Snp2u4NcqG27dvCwAiKChINe3AgQOiatWqQl9fX219pk+f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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Constants for calculations\n", + "sea_level_pressure = 101325 # Reference pressure at sea level (Pa)\n", + "sea_level_temperature = 330 # Reference temperature at sea level (K)\n", + "gravity = 9.80665 # Acceleration due to gravity (m/s^2)\n", + "molar_mass_air = 0.0289644 # Molar mass of Earth's air (kg/mol)\n", + "universal_gas_constant = 8.314 # Universal gas constant (J/(mol·K))\n", + "temperature_lapse_rate = 0.0065 # Standard temperature lapse rate (K/m)\n", + "\n", + "# Generate an array of altitudes from sea level (0 meters) to 10 km (10000 meters), divided into 100 intervals\n", + "altitude_range = np.linspace(0, 10000, 100)\n", + "\n", + "# Calculate the temperature at each altitude based on the linear temperature lapse rate\n", + "temperature_at_altitudes = sea_level_temperature - temperature_lapse_rate * altitude_range\n", + "\n", + "# Calculate the pressure at each altitude using the barometric formula\n", + "pressure_at_altitudes = sea_level_pressure * (\n", + " (1 - temperature_lapse_rate * altitude_range / sea_level_temperature)\n", + " ** (gravity * molar_mass_air / (universal_gas_constant * temperature_lapse_rate)))\n", + "\n", + "\n", + "# Initialize a matrix to hold saturation ratios for each species at each\n", + "# altitude\n", + "saturation_ratio = np.zeros(len(altitude_range))\n", + "\n", + "# Loop over each altitude's temperature and pressure\n", + "for index, (temperature, pressure) in enumerate(zip(temperature_at_altitudes, pressure_at_altitudes)):\n", + " # Set the current temperature and pressure of the gas mixture\n", + " gas_mixture.temperature = temperature\n", + " gas_mixture.total_pressure = pressure\n", + "\n", + " # Loop over water\n", + " saturation_ratio[index] = gas_mixture.species[0].get_saturation_ratio(gas_mixture.temperature)\n", + "\n", + "\n", + "# Plot the saturation ratio of water vapor at each altitude\n", + "fig, ax = plt.subplots()\n", + "ax.plot(saturation_ratio, altitude_range, label='Water')\n", + "ax.set_xscale('log')\n", + "ax.set_ylabel('Altitude (m)')\n", + "ax.set_xlabel('Water Saturation Ratio')\n", + "ax.set_title('Saturation Ratio of Water Vapor at Different Altitudes')\n", + "ax.legend()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Summary\n", + "\n", + "In this notebook, we introduced the `Gas` class, a composite object that aggregates multiple `GasSpecies` objects. We also discussed the `GasBuilder` class, which simplifies the creation of `Gas` objects. Finally, we explored how to iterate over `GasSpecies` objects within a `Gas` object, enabling dynamic property adjustments based on environmental changes, such as temperature and pressure variations.\n", + "\n", + "We now need to combine this with particles to create an aerosol system.\n", + "\n", + "# Help\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on class GasBuilder in module particula.next.gas:\n", + "\n", + "class GasBuilder(builtins.object)\n", + " | A builder class for creating Gas objects with a fluent interface.\n", + " | \n", + " | Methods defined here:\n", + " | \n", + " | __init__(self)\n", + " | Initialize self. See help(type(self)) for accurate signature.\n", + " | \n", + " | add_species(self, species: particula.next.gas_species.GasSpecies)\n", + " | Add a gas species component to the gas mixture.\n", + " | \n", + " | build(self) -> particula.next.gas.Gas\n", + " | Build and return the Gas object.\n", + " | \n", + " | temperature(self, temperature: float)\n", + " | Set the temperature of the gas mixture, in Kelvin.\n", + " | \n", + " | total_pressure(self, total_pressure: float)\n", + " | Set the total pressure of the gas mixture, in Pascals.\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors defined here:\n", + " | \n", + " | __dict__\n", + " | dictionary for instance variables\n", + " | \n", + " | __weakref__\n", + " | list of weak references to the object\n", + "\n" + ] + } + ], + "source": [ + "help(GasBuilder)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on class Gas in module particula.next.gas:\n", + "\n", + "class Gas(builtins.object)\n", + " | Gas(temperature: float, total_pressure: float, species: list[particula.next.gas_species.GasSpecies] = ) -> None\n", + " | \n", + " | Represents a mixture of gas species, detailing properties such as\n", + " | temperature, total pressure, and the list of gas species in the mixture.\n", + " | \n", + " | Attributes:\n", + " | - temperature (float): The temperature of the gas mixture in Kelvin.\n", + " | - total_pressure (float): The total pressure of the gas mixture in Pascals.\n", + " | - species (List[GasSpecies]): A list of GasSpecies objects representing the\n", + " | species in the gas mixture.\n", + " | \n", + " | Methods:\n", + " | - add_species: Adds a gas species to the mixture.\n", + " | - remove_species: Removes a gas species from the mixture by index.\n", + " | \n", + " | Methods defined here:\n", + " | \n", + " | __eq__(self, other)\n", + " | Return self==value.\n", + " | \n", + " | __getitem__(self, index: int) -> particula.next.gas_species.GasSpecies\n", + " | Returns the gas species at the given index.\n", + " | \n", + " | __init__(self, temperature: float, total_pressure: float, species: list[particula.next.gas_species.GasSpecies] = ) -> None\n", + " | Initialize self. See help(type(self)) for accurate signature.\n", + " | \n", + " | __iter__(self)\n", + " | Allows iteration over the species in the gas mixture.\n", + " | \n", + " | __len__(self)\n", + " | Returns the number of species in the gas mixture.\n", + " | \n", + " | __repr__(self)\n", + " | Return repr(self).\n", + " | \n", + " | __str__(self)\n", + " | Returns a string representation of the Gas object.\n", + " | \n", + " | add_species(self, gas_species: particula.next.gas_species.GasSpecies) -> None\n", + " | Adds a gas species to the mixture.\n", + " | \n", + " | Parameters:\n", + " | - gas_species (GasSpecies): The GasSpecies object to be added to the\n", + " | mixture.\n", + " | \n", + " | remove_species(self, index: int) -> None\n", + " | Removes a gas species from the mixture by index.\n", + " | \n", + " | Parameters:\n", + " | - index (int): The index of the gas species to be removed from the\n", + " | list.\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors defined here:\n", + " | \n", + " | __dict__\n", + " | dictionary for instance variables\n", + " | \n", + " | __weakref__\n", + " | list of weak references to the object\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data and other attributes defined here:\n", + " | \n", + " | __annotations__ = {'species': list[particula.next.gas_species.GasSpeci...\n", + " | \n", + " | __dataclass_fields__ = {'species': Field(name='species',type=list[part...\n", + " | \n", + " | __dataclass_params__ = _DataclassParams(init=True,repr=True,eq=True,or...\n", + " | \n", + " | __hash__ = None\n", + " | \n", + " | __match_args__ = ('temperature', 'total_pressure', 'species')\n", + "\n" + ] + } + ], + "source": [ + "help(Gas)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ParticulaDev_py311", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/documentation/next/next_gas_species.ipynb b/docs/documentation/next/next_gas_species.ipynb new file mode 100644 index 000000000..247a6846b --- /dev/null +++ b/docs/documentation/next/next_gas_species.ipynb @@ -0,0 +1,553 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Gas Species\n", + "\n", + "The `GasSpecies` module is designed to define and manage the characteristics of individual gas species within a mixture. This module is crucial for tracking concentrations and defining material properties of each species efficiently and effectively.\n", + "\n", + "### Key Classes\n", + "\n", + "This module primarily consists of two classes:\n", + "\n", + "- **`GasSpecies`**: This class represents either an individual or an array of gas species. It includes properties such as the species' name, molar mass, vapor pressure, and whether it is condensable. The class provides methods to set and retrieve these properties, ensuring that each species is fully defined and manageable within simulations or calculations.\n", + "\n", + "- **`GasSpeciesBuilder`**: This class is used to construct `GasSpecies` objects. It facilitates a step-by-step definition of all necessary properties before finalizing the object creation. This builder pattern helps in ensuring that all properties are correctly set and validated before a `GasSpecies` object is used in further calculations. It provides a fluent interface that enhances readability and ease of use in setting up gas species.\n", + "\n", + "### Example Usage\n", + "\n", + "We utilize the `GasSpeciesBuilder` to create instances of `GasSpecies`. This approach not only ensures that the species properties are well-defined but also verifies the integrity of the data before the object is finalized. The builder pattern is particularly useful in scenarios where a species must meet certain criteria or possess specific properties for accurate simulation and analysis." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Particula imports\n", + "from particula.next.gas_vapor_pressure import vapor_pressure_factory\n", + "from particula.next.gas_species import GasSpecies, GasSpeciesBuilder" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define Vapor Pressure Strategies\n", + "\n", + "In this section, we'll focus on defining vapor pressure strategies for gas species, specifically Butanol, Styrene, and Water, which were used in our previous examples. To streamline our analysis, we will group Butanol and Styrene into a single organic category, and consider Water separately.\n", + "\n", + "### Strategy Assignment\n", + "\n", + "For calculating vapor pressures:\n", + "\n", + "- **Organics (Butanol and Styrene)**: We will utilize the Antoine equation, a widely recognized method for estimating the vapor pressure of organic compounds based on temperature.\n", + "- **Water**: We will apply the Buck equation, which is specifically tailored to accurately calculate the vapor pressure of water across a range of temperatures." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Define the coefficients for Butanol using the Antoine equation.\n", + "# 'a', 'b', and 'c' are coefficients specific to the Antoine equation used to calculate vapor pressure.\n", + "butanol_coefficients = {'a': 7.838, 'b': 1558.19, 'c': 196.881}\n", + "# Create a vapor pressure strategy for Butanol using the Antoine equation.\n", + "butanol_antione = vapor_pressure_factory(\n", + " strategy='antoine', **butanol_coefficients)\n", + "\n", + "# Define the coefficients for Styrene, similar to Butanol, using the\n", + "# Antoine equation.\n", + "styrene_coefficients = {'a': 6.924, 'b': 1420, 'c': 226}\n", + "# Create a vapor pressure strategy for Styrene using the Antoine equation.\n", + "styrene_antione = vapor_pressure_factory(\n", + " strategy='antoine', **styrene_coefficients)\n", + "\n", + "# Water uses a different model for vapor pressure calculation called the Buck equation.\n", + "# The Buck equation is particularly suited for water vapor calculations.\n", + "# No additional parameters are required to be passed for the Buck equation\n", + "# in this instance.\n", + "water_buck = vapor_pressure_factory(\n", + " strategy='water_buck')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using `GasSpeciesBuilder` to Construct Gas Species\n", + "\n", + "Now that we have defined the appropriate vapor pressure strategies for our gas species, we can proceed to construct the individual species using the `GasSpeciesBuilder`. This builder simplifies the process of defining and validating the properties of each gas species before their creation. We'll begin with Water, as it involves a straightforward application of the Buck equation.\n", + "\n", + "### Building the Water Gas Species\n", + "\n", + "The `GasSpeciesBuilder` facilitates a structured approach to setting up a gas species. To build a Water gas species, the builder requires the following properties to be set:\n", + "\n", + "1. **Name**: Identifies the species, which in this case is \"Water\".\n", + "2. **Molar Mass**: The molar mass of water, essential for calculations involving mass and moles.\n", + "3. **Vapor Pressure Strategy**: The specific strategy used to calculate vapor pressure; for Water, we use the Buck equation.\n", + "4. **Condensability**: Indicates whether the species can condense under certain atmospheric conditions. For Water, this is typically true.\n", + "5. **Concentration**: The initial concentration of Water in the mixture, which could vary based on the scenario.\n", + "\n", + "Here is how you can use the `GasSpeciesBuilder` to set up Water:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Water\n" + ] + } + ], + "source": [ + "# Create an instance of GasSpeciesBuilder\n", + "water_builder = GasSpeciesBuilder()\n", + "\n", + "# Configure the builder with the necessary properties\n", + "water_species = water_builder \\\n", + " .name(\"Water\") \\\n", + " .molar_mass(0.01801528) \\\n", + " .vapor_pressure_strategy(water_buck) \\\n", + " .condensable(True) \\\n", + " .concentration(0.017) \\\n", + " .build() # Finalize and create the GasSpecies object\n", + "# molar mass in kg/mol, concentration in kg/m3\n", + "print(water_species)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Building Gas Species for Organics\n", + "\n", + "Following Water, you can apply a similar process to build gas species for Organics like Butanol and Styrene. Each will have its set of properties based on the chemical's nature and the desired simulation context.\n", + "\n", + "When calling `.build()`, it checks that all required properties are set correctly, raising an error if any essential attribute is missing or improperly configured. This ensures that each `GasSpecies` instance is valid and ready usage." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['butanol' 'styrene']\n" + ] + } + ], + "source": [ + "# Define molar masses for organic species (Butanol and Styrene) in kilograms per mole (kg/mol).\n", + "organic_molar_mass = np.array([0.074121, 104.15e-3]) # Molar mass for Butanol and Styrene respectively.\n", + "\n", + "# List of vapor pressure strategies assigned to each organic species.\n", + "organic_vapor_pressure = [butanol_antione, styrene_antione] # Using Antoine's equation for both.\n", + "\n", + "# Define concentrations for each organic species in the mixture, in kilograms per cubic meter (kg/m^3).\n", + "organic_concentration = np.array([2e-6, 1e-9]) # Concentration values for Butanol and Styrene respectively.\n", + "\n", + "# Names of the organic species.\n", + "organic_names = np.array([\"butanol\", \"styrene\"])\n", + "\n", + "# Using GasSpeciesBuilder to construct a GasSpecies object for organics.\n", + "# Notice how we can directly use arrays to set properties for multiple species.\n", + "organic_species = GasSpeciesBuilder() \\\n", + " .name(organic_names) \\\n", + " .molar_mass(organic_molar_mass) \\\n", + " .vapor_pressure_strategy(organic_vapor_pressure) \\\n", + " .condensable([True, True]) \\\n", + " .concentration(organic_concentration) \\\n", + " .build() # Finalize and create the GasSpecies objects\n", + "\n", + "# The `build()` method validates all the properties are set and returns the constructed GasSpecies object(s).\n", + "# Here, organic_species will contain the built GasSpecies instances for Butanol and Styrene.\n", + "print(organic_species)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pure Vapor Pressures\n", + "\n", + "With the gas species defined, we can now calculate the pure vapor pressures of Butanol, Styrene, and Water using the respective strategies we assigned earlier. This will help us understand the vapor pressure behavior of each species individually, which is crucial for predicting their behavior in mixtures and under varying conditions." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkgAAAGwCAYAAABSN5pGAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB1bUlEQVR4nO3dd3hUZd7G8e+k90ZIQkhCQpHem6hIEaWoNBVXURHbWrBFfcVdxcIqrmtB0RXXhl2wgK4oiyJVkR6KdAiElkAI6T1z3j8OGZgkQBKSTCa5P9c1V+aUOfObE8zcPuc5z2MxDMNARERERGxcHF2AiIiISH2jgCQiIiJShgKSiIiISBkKSCIiIiJlKCCJiIiIlKGAJCIiIlKGApKIiIhIGW6OLsBZWa1WDh8+jL+/PxaLxdHliIiISCUYhkFWVhaRkZG4uJy5nUgBqZoOHz5MdHS0o8sQERGRajhw4ABRUVFn3K6AVE3+/v6AeYIDAgIcXI2IiIhURmZmJtHR0bbv8TNRQKqm0stqAQEBCkgiIiJO5lzdY9RJW0RERKQMBSQRERGRMhSQRERERMpQQBIREREpQwFJREREpAwFJBEREZEyFJBEREREylBAEhERESlDAUlERESkjEY9knZsbCwBAQG4uLgQHBzM4sWLHV2SiIiI1AONOiAB/P777/j5+Tm6DBEREalHdIlNREREpAynDUjLli3j6quvJjIyEovFwrx588rt89ZbbxEbG4uXlxd9+/Zl9erVdtstFgsDBgygd+/efPbZZ3VUuYiIiFTEMAxyi3I5nnecg1kHyS7MdlgtTnuJLScnh65du3LbbbcxduzYcttnz55NfHw8M2fOpG/fvkyfPp2hQ4eyY8cOwsLCAFixYgXNmzfnyJEjDBkyhM6dO9OlS5cK36+goICCggLbcmZmZu18MBERkXquxFpCfkk+uUW55BbnkluUS15xnt3z0uW84rwKt5fdVvo43fOXPM/IViMd8hmdNiANHz6c4cOHn3H7q6++yp133snEiRMBmDlzJvPnz+eDDz5g8uTJADRv3hyAZs2aMWLECNavX3/GgDRt2jSeffbZGv4UIiIitccwDAqthXZBpuxPW5g5w7bc4jLLRbnkl+TXeu3ebt6UWEtq/X3OxGkD0tkUFhaybt06nnjiCds6FxcXhgwZwsqVKwGzBcpqteLv7092dja//vor48aNO+Mxn3jiCeLj423LmZmZREdH196HEBGRRqewxAwzOcU55s+iHLOlpcgMKqXLpdvsgk0FASivKI9io7jW6nWxuODj5oO3mzc+7uZPbzdvfNx8yi17u3vb9i3dv+xy6b5ebl64WBzbC6hBBqTU1FRKSkoIDw+3Wx8eHs727dsBSElJYcyYMQCUlJRw55130rt37zMe09PTE09Pz9orWkREnIphGHaXjXKKcsoFmNOXbQHnZADKK8qzbS/9WWytvTDj5eplF1p83X3tgkzp8ulB5vTQUva5j5sPnq6eWCyWWqvZkRpkQKqMli1bsnHjRkeXISIidaiwpNAWXOwep7XY2ELMyfV2y2UCj9Ww1kqdnq6ep4KIuw++br62UFL2p6+7/bbTW2d83X1tocbVxbVWam2oGmRACg0NxdXVlZSUFLv1KSkpREREOKgqERGpKsMwKCgpILso2xZSSp9nF2VXHHZKg03hqeBTum9ttdCUhpHSQFL6vDS0lIaY0qBTdh9byDkZbNxcGuTXs1NpkL8BDw8PevbsyaJFixg9ejQAVquVRYsWMWnSJMcWJyLSCBRZi8qFmOzCbFvAsa07+bx0W9ntOUU5lBg131G39HKTn7vfqfDi7msLMKXh5fRgc3qIOX3Z283b4f1lpOY5bUDKzs5m9+7dtuXExEQSEhIICQkhJiaG+Ph4JkyYQK9evejTpw/Tp08nJyfHdlebiIiUV1RSRHZRti2kZBVmnQothTlkFWVVGHbKBp3auMupNMD4evjaBZTSkHN6oKko+Ph5+KmFRirNaf+FrF27lkGDBtmWS+8wmzBhArNmzeL666/n2LFjTJkyheTkZLp168aCBQvKddwWEWkIrIbVFlBKA06Fz0/7mVN0KvCUBqGCkoJzv1kVeLl62YUXPw8/WyuNv4d/uYBT+ryi0KNWGqlLFsMwDEcX4YwyMzMJDAwkIyODgIAAR5cjIk6s2FpsCynZRdnmz8Jssoqy7AJNVlGWrRWndH3pa3KKcmq0Jm83b/zc/fDz8LMLLaXBpmyIOX2dj7sP/u7msrure43WJXK+Kvv97bQtSCIi9YHVsJJblEtWYZYtuFT0vFzoOe15bnFujdXj5uKGv7u/LdjYfp7+vIJ1pa07pc91CUoaO/0XICKNWrG12BZkMosyTwWZwiwyCzPtWnUyCzNt27KLsm3LBjXTEO/l6mULKf4e/rYAc/rz0mDj72GGoNKWmtL9PFw8Guy4NCJ1SQFJRJxaibXEFlayCrNsj9LlsuvLrqup1hs3FzcCPALswkyAR0C5MHP6Tz8PPwLcA2zP3V10OUqkvlBAEhGHMgyD/JJ8M7gUZNoFG9ujoHzYOb11pyZ4u3nj7+6Pv8c5Hqftc3rY8XL1UsuNSAOigCQi5610yoXMwkwyCjLsgk2Fz8uEniJr0XnX4O3mjb+Hv10rToBngF2gKd1W9rlab0SkLAUkEbEpKCkgs8AMORmFGebzkz/PGn4KM897hGJXi6stuJSGlwDPgPLrKtju7+6vu6VEpEYpIIk0MFbDavbJORluMgoy7EJPacjJKDj1vDTsnO/gfqX9cAI8AgjwDDj1vOxyBdt83Hx0iUpE6g0FJJF6ympYySrMsgWZ9IJ0W8CxPU4PQKeFn/OZQNPF4kKARwCBnoHlAs251nm7eSvkiEiDoIAkUssMwyCnKOdUwMk/FXbSC9LtAlBmQaZtW2ZB5nndPu7l6kWApxlgAj3MEBPkFWQfajwDCPQItFv2c/fTiMUi0ugpIIlUQZG1yC7QpOenmz9Lg05hhm3d6a0+59M/x9vNmyDPIDPonAw7gZ6BtnWlwSbIM+hU2PEMwNPVswY/uYhI46KAJI1WYUmhLdycHnTSC9I5kX+i3LaMggyyirKq/X4eLh4EeQXZwk2Qp9maU/rcFoDKhB8PV48a/NQiIlIZCkjSIBRbi21h5kTBCVvAOT3onCg4YReEqjt3lQUL/h7+BHsF24Udu+DjeSr4lG7zdvOu4U8tIiK1RQFJ6h3DMMguyuZE/gnS8tNsQac04Nj9LEgnLT+NrMLqtey4WFxsASbY87TA4xVEsGfwqZDjFWTX6uPq4lrDn1pEROoTBSSpdSXWEruQk5afZj6vIACV/qxOnx0LFrtwE+gZSLCXGXKCPYNtIad0XZBnEP4e/uqQLCIi5SggSZWVXs46nnfcFmrS8tPKBZ/SbRkFGdW6G8vHzedUwPEKJtgz2PxZZl1pIFLLjoiI1BQFJMFqWMkoyLCFHLtHnhl0jucdt4WejIKMKr+HBYutRef0oHP68xDPELsA5OXmVQufVkRE5NwUkBqovOI80vLTbMHm9OfH84/bBaD0gnRKjJIqHb/0clawVzAhXiG2n6XPSwNP6XKgZyBuLvrnJiIizkHfWE7CMAwyCzM5nn+c43nHzZCTl2ZbtgWfk+vyivOq/B4BHgG2kGN7eIcQ7BlMiHeIXeAJ8gzS5SwREWmwFJDqmV+TfmXjsY22EGQLQ/lpVe647OHiQRPvJraw08S7CcFewTTxMtc18WpiBh8vMwRpsk8RERGTAlI9s/jAYubtnnfG7f7u/rbQc/rPJl4nH6cFIl93X82LJSIiUg0KSPXMxZEX4+fudyr0nPxZerlL00eIiIjUPothGNWfDbMRy8zMJDAwkIyMDAICAhxdjoiIiFRCZb+/NUKeiIiISBkKSCIiIiJlKCCJiIiIlKGAJCIiIlKGApKIiIhIGQpIIiIiImUoIImIiIiUoYAkIiIiUoYCkoiIiEgZCkgiIiIiZSggiYiIiJShgCQiIiJShgKSiIiISBkKSCIiIiJlKCCJiIiIlNGoA9KYMWMIDg7m2muvdXQpIiIiUo806oD04IMP8vHHHzu6DBEREalnGnVAGjhwIP7+/o4uQ0RERE5jtRocPJFLdkGxw2pw2oC0bNkyrr76aiIjI7FYLMybN6/cPm+99RaxsbF4eXnRt29fVq9eXfeFioiISDlWq8GRjDx+35PKZ6v28/z8rdzx0Vouf3Up7aYs4JJ/LmbpjmMOq8/NYe98nnJycujatSu33XYbY8eOLbd99uzZxMfHM3PmTPr27cv06dMZOnQoO3bsICwszAEVi4iINC6GYXAit4jE1Gz2HsshMfXUY9/xHPKLrGd8rburhbTcwjqs1p7TBqThw4czfPjwM25/9dVXufPOO5k4cSIAM2fOZP78+XzwwQdMnjy5yu9XUFBAQUGBbTkzM7PqRYuIiDRAeYUlJKbmsDc1m8STQWjvySCUkVd0xte5uliIDvYmNtSXuJOP2CbmIzLICzdXx13octqAdDaFhYWsW7eOJ554wrbOxcWFIUOGsHLlymodc9q0aTz77LM1VaKIiIhTsVoNjmTms/dYNnuOZrM3NYe9x3LYeyybwxn5Z31tZKAXcU1LQ5AfcaE+xIX6ERXsjbsDQ9DZNMiAlJqaSklJCeHh4Xbrw8PD2b59u215yJAhbNy4kZycHKKiovjqq6/o169fhcd84okniI+Pty1nZmYSHR1dOx9ARETEQXILi83gk5rDnqPZ7DmWfXI5+6yXxAK93Wl5MgS1aupn1yLk7eFah5+gZjTIgFRZv/zyS6X39fT0xNPTsxarERERqRuGYZCaXcjukwFo92lB6FB63hlf5+5qISbEh5ZN/WjZ1JdWoebPlk39CPZxx2Kx1OGnqF0NMiCFhobi6upKSkqK3fqUlBQiIiIcVJWIiEjdsloNDqXnsetoFruPZtsee46dvW9QiK8HLU+2BLUK86VlqB+twvyIDvZ2aL+gutQgA5KHhwc9e/Zk0aJFjB49GgCr1cqiRYuYNGmSY4sTERGpYcUlVvan5bIrJZvdR7PYdfRUq9CZLotZLBAd7EOrpr60DvOjVVM/Wof50bKpHyG+HnX8Ceofpw1I2dnZ7N6927acmJhIQkICISEhxMTEEB8fz4QJE+jVqxd9+vRh+vTp5OTk2O5qExERcTZFJVb2H89hZ0o2u1Ky2Xk0i90p2exNzaaoxKjwNR6uLsSFngxBYWYIan3yEpmXu/P1DaorThuQ1q5dy6BBg2zLpR2oJ0yYwKxZs7j++us5duwYU6ZMITk5mW7durFgwYJyHbdFRETqm+ISK/uO57IrJYudJ4PQrpQsElNzzhiEvN1dzfBz8tHm5M+YEJ9Gc1msJlkMw6j4TMtZZWZmEhgYSEZGBgEBAY4uR0REnFBpH6EdyVnsSMliZ0oWO5Kz2Hssh8KSii+N+Xq40jrcnzYnQ9AF4f60DvOjeZA3Li4Np5N0bans97fTtiCJiIg4k9TsAjMIlT5SzFahnMKSCvf3dnelTbgfbcL8uSDcDEJtwv2IDFQQqgsKSCIiIjUor7DE1hK0PTmLHSmZ7EjOIjW74mkzPFxdaNnUl7YR/lwQ7k/bcH/aRvirRcjBFJBERESqwZxxPo9tyZlsP5LF9mQzCCUez6GizisWC7QI8aFtRGkICqBthB8tmvjW29GkGzMFJBERkXPIKShme3IW245ksu1IptkylJxFdkFxhfs38fWgXTN/2oYH0C7CbBFqE+6Hj4e+dp2FflMiIiInGYbBkYx8th3JZOvhTLaeDET703IrbBXycHWhTbgf7SICaN/Mn3YRAbSN8Kepv2ZecHYKSCIi0igVlVjZeyyHPw9n2MLQ1iOZpOdWPMJ0mL8n7ZsFnHz4075ZAHGhujzWUCkgiYhIg5dbWMy2I1lsPZzBn4cz+fNwJjtSsigsLn8rvauLhTZhfrRvFkCH0wJREz+1CjUmCkgiItKgZOQW8efhDLacDENbDmWwN7XijtN+nm50aBZAh0gzBHWMDKR1mJ9GmBYFJBERcV7HswvYcjIEbTlkhqIDaRXPRt/U35OOkQEnH4F0jAwgOthHt9JLhRSQRETEKaRmF7D5UAZbDmaYPw9lcDgjv8J9o0O86XQyBHVsbv4M8/eq44rFmSkgiYhIvXMip5DNh8wgtOlgOlsOZXIoveKWobhQXzo1D6Rz84CToSiQQB/3Oq5YapxhmA8Xx3SCV0ASERGHyi4oZvPBDDYfSmfjwQw2H8wgKS233H4WixmGOjcPpHPzQDqdbBny91IYcnrWEkjdBcmbIXnTycdmGPsfaD3EISUpIImISJ0pKC5h+5EsNh5MZ+OBDDYeTGfPsewKO1DHNvGhU/NAukYF0TlKYajBKMqDlK2ngtCRTZDyJxRX0EKYvFkBSUREGhar1SDxeA4JSeknA1E6245kVThLfWSgF12igugSHUiX5kF0bq7LZA1CQZYZco5sPPnYBMe2g1HBBL3uvhDRCSI6n3x0gbD2dV/zSQpIIiJSI9JyCkk4cIINSekkHDADUWZ++ak4gn3c6RIVRNfoILpGBdIlKkgjTzcE+RlmCDqccDIMJcDxPUAFzYM+TcwA1KzLyZ9dIaQluNSf4RUUkEREpMoKi61sO5LJ+qQTJBxIZ0NSeoX9hjzdXOjcPNAMQ9FBdIsKIjrEG4tFt9Y7tdPD0OENZhhK21vxvv6RENnNDEGlYSgg0uxUVo8pIImIyDkdychj/f50NiSdYMOBdDYfyqhwFOpWTX3pFh1M95ggukUH0TbCX1NxOLvCnJNhaMOpx/HdFe8bFGMGoGbdzFAU0RX8mtZltTVGAUlEROwUFlvZeiSTdftPsD7pBOv3n+BIBeMNBfm40z06iO4xZiDqEhVEoLf6DTm14kJI2QKH1plB6NB6SN0BRvkwTGAMRHaFyO4nA1F38Amp85JriwKSiEgjl5ZTyLr9J8xAtP8EGw+mU1CmdcjFAu0iAujRIogeMcF0jwkmtomPLpU5M6vVbAk6tO7UI2ULlBSW39c/0gxAtkc38A2t85LrkgKSiEgjYhgGe47lsG5/Gmv3maFob2pOuf2CfNzpGRNMjxZm61DXqCB8PfWV4dSyUuDQWji49lQLUUFm+f28g6F5T4jsAc17mIHIP6Lu63Uw/WsXEWnACoutbD6Uzpp9J04GojRO5BaV2691mB89Y4LpGRtMzxbBtAz1VeuQMyvKM/sNHVxjBqKDayHzYPn93LzN1qDmPc0g1LwnBMfW+w7UdUEBSUSkAcnKL2J9UjprEtNYvS+NjQfKXy7zdHOha3QQvVoE0ys2mO7RwQT7ejioYjlvhgEn9p0MQycfyZvBWnaIBQs0bQdRPaF5L4jqBU3bg6uiQEV0VkREnFhqdoEtDK3Zl8bWw5lYyww7E+LrQc8WwfSODaZXbAidIgPxcNOdZU6rMNe8PHZwNRxYbQainGPl9/MNg6jepwJRZHfwCqj7ep2UApKIiBM5kpHH6sQ0ViWmsWrvcfYcK99/KCbEh96xIfSODaZ3XIgulzm7jENw4A8zDB1YVXHrkIu7eXt9VG+zZSi6DwRG61LZeVBAEhGpxw6k5drC0KrEtAoHY2wX4U/v2BD6xJmP8AAvB1QqNaKk2LyT7MAqSDoZiirqO+TfzAxD0X0gqo8Zjtz1e69JCkgiIvXIgbRc/th7nD/2pvHH3uMcSrefwNPFAp2aB9InNoS+LZvQOzaYIB/1H3JaBdnmJbKkPyBppXl3WWG2/T4WV3Nusui+ZiBS61CdUEASEXGgw+l5rNxznJV7j/PH3uMcPGEfiNxcLHSOCqRvXBP6tgyhV4tgzWjvzLKPmkFo/0rzZ/Lm8hO3egZCdG+IvhBi+pp3lnn4OqbeRkwBSUSkDh3LKuCPvcf5fc9xVu5JZd9x+0tmbi4WukQFcmHLJlzYsgk9WwRr/CFnZRiQvh/2/w77fzNDUdqe8vsFxkDMyTAU08+8s8xFnegdTf/ViYjUosz8Iv7YUxqIjrMjJctuu4sFOkcF0a9lE/q1akIvBSLnZRiQugv2rzgZin6HzENldrJAWAdo0c8MQzEXQmCUQ8qVs9N/hSIiNSi/qIT1+0+wYncqv+05zuaD6eVuu+/QLICLWpmBqE9ciC6ZOSurFY5th30rToWisrfbu7iZI1K36AcxF5mtRN7BjqlXqkQBSUTkPFitBluPZPLb7lRW7E5ldWJauYEZW4b6clHrJlzcKpS+LZsQokEZnZPVCse2mYFo3wrzslnucft93LzMu8taXAwtLjJvuVf/IaekgCQiUkWH0/NYsSuV5btT+W13Kmk59pN7hvl7cnHrUC5q1YSLW4cSGeTtoErlvBgGpO6ExGXmo6JA5O5j3l0WezG0uMScu8zN0zH1So1SQBIROYecgmJWJR5n2c5Ulu86Vm5wRl8PVy5s2YRL2oRySetQWof5aWBGZ3Vi36lAlLgMslPst9sC0SUQ298cndpNLYINkQKSiEgZVqvBtuRMlu48xvKdqazdn0ZRyamORC4W6BodRP82TenfJpRu0UG4u+quI6eUlXIyDC0xf6Yn2W938zLHHYq9FOL6m/2JFIgaBQUkEREgLaeQ5buOsXTnMZbtTCU1u8Bue1SwN5de0JRL24TSr1Uogd7qWO2U8jPNS2V7l5iPY9vtt7u4mX2I4i41W4ii++iSWSOlgCQijVKJ1WDTwXSW7DjGkp3H2HQwHeO0u818PFy5qFWTk6GoKS2a+OiymTMqKTJHqi4NRAfXlhmY0WKOUt1yAMQNNG+79/RzSKlSvyggiUijcSKnkGW7jrF4+1GW7jzGidwiu+3tIvwZ0LYpAy5oSs8WwXi6uTqoUqk2w4Dje2DPr+Zj3wootB97ipCWEDcAWg40W4p8QhxSqtRvCkgi0mAZhsGfhzNZvP0ov+44SsIB+1Yify83+rcJZeAFYVx6QVMiAjXZp1PKO2H2H9q9CPYshowy/Yi8Q8wWopaDzFAU3MIhZYpzabQBKT09nSFDhlBcXExxcTEPPvggd955p6PLEpHzlFNQzIrdqfy67SiLdxzlaJZ9X6L2zQIY2LYpg9qG0SMmCDd1rnY+1hI4vAF2/2KGokNrwTht7ClXD/NSWctB0GoQRHTV1B1SZY02IPn7+7Ns2TJ8fHzIycmhU6dOjB07liZNmji6NBGpooMncvl1+1F+2XaUP/Ycp7Dk1Jelj4crF7cOZXC7MAa2bUqzQI1J5JSyUmDPIjMU7fnVbDU6XWhbaDUYWl9mDtCowRnlPDXagOTq6oqPjw8ABQUFGIaBYRjneJWI1AdWq8GmQxn8sjWFX7alsD3Zvo9JdIg3l7ULZ3C7MPq2DFFfImdUUmy2DO1aCLt+huRN9ts9A83LZq2HmMEoKNoxdUqDVW8D0rJly/jXv/7FunXrOHLkCHPnzmX06NF2+7z11lv861//Ijk5ma5duzJjxgz69OlT6fdIT09nwIAB7Nq1i3/961+EhobW8KcQkZqSX1TCb7tT+XlrCou2H+XYaZfOXCzQq0UIg9uHcVm7MA3U6KxyUs0Wol0LzUtn+en225t1gzaXm6GoeS9wrbdfYdIAnNe/roKCAjw9a2d8iJycHLp27cptt93G2LFjy22fPXs28fHxzJw5k759+zJ9+nSGDh3Kjh07CAsLA6Bbt24UFxeXe+3ChQuJjIwkKCiIjRs3kpKSwtixY7n22msJDw+vsJ6CggIKCk79Qc7MzKyhTyoiZ3Iip5BF24/y89Zklu1MJa/o1O3Zfp5uDLigKUM6hDHwgjCCNb+Z8zEMOLLRDEQ7/weH1gGnteR7BZmXzFpfbv70C3NUpdIIWYwqXFf66aef+PLLL1m+fDkHDhzAarXi6+tL9+7dueKKK5g4cSKRkZE1X6TFUq4FqW/fvvTu3Zs333wTAKvVSnR0NPfffz+TJ0+u8nvce++9DB48mGuvvbbC7c888wzPPvtsufUZGRkEBARU+f1EpGIH0nL5eWsKC7cmszoxDetpf6EiA70Y0iGcIe3DubBlEzzc1PHW6RTmmuMR7VxgBqOsI/bbI7pAmyvMR/OeaiWSGpeZmUlgYOA5v78rFZDmzp3L448/TlZWFiNGjKBPnz5ERkbi7e1NWloaW7ZsYfny5axcuZJbb72VqVOn0rRp0xr7MGUDUmFhIT4+Pnz99dd2oWnChAmkp6fz3XffnfOYKSkp+Pj44O/vT0ZGBhdffDFffPEFnTt3rnD/ilqQoqOjFZBEzpNhGOw6ms2CLcn8789k/jxs3zrbvlkAV3QI5/IO4XSMDNClM2eUeRh2/GSGosRlUJx/apu7j3m32QVDzVAU0MxxdUqjUNmAVKlo/tJLL/Haa68xfPhwXCq4VXLcuHEAHDp0iBkzZvDpp5/y8MMPV7P0c0tNTaWkpKTc5bDw8HC2b99+hlfZ279/P3fddZetc/b9999/xnAE4OnpWWuXE0UaG8Mw2HgwwxaKElNPTf7qYoHesSEM7RjB5R3CiQ7xcWClUi2GAcmbzVC040c4kmC/PTAG2g6DNkPNSV/dNf6U1D+VCkgrV66s1MGaN2/Oiy++eF4F1ZU+ffqQkJDg6DJEGo0Sq8HafWn8dDIUHck41Yrg4eZC/9ahDO0UwZD24YSoP5HzKSky5zjbPt8MRhkHTttogahecMEwaDscwjqAWgKlnnPKi7uhoaG4urqSkpJitz4lJYWIiAgHVSUiZRWXWFmdmMaPW46wYEuK3QSwPh6uDGoXxvBOEQxsG4afp1P+OWrcCrLNu862z4dd/4P8jFPb3LzN2+/bDjcvn6mDtTiZav1FOnjwIN9//z1JSUkUFhbabXv11VdrpLCz8fDwoGfPnixatMjWB8lqtbJo0SImTZpU6+8vImdWXGJlVWIaP2w6wsI/kzmec+pvRICXG0M6hDO8UzP6twnFy13jEzmdnOPmZbPtP5jTepScNlK5T6gZiNpdaU7p4a5BOcV5VTkgLVq0iJEjR9KyZUu2b99Op06d2LdvH4Zh0KNHjxorLDs7m927d9uWExMTSUhIICQkhJiYGOLj45kwYQK9evWiT58+TJ8+nZycHCZOnFhjNYhI5ZRYDVYlHmf+piMs2GIfioJ83BnaIYLhnSO4qFWo7jxzRhmHzFaibd+bl9FOn9YjOM4MRO2vhqje4KLQKw1DlQPSE088waOPPsqzzz6Lv78/33zzDWFhYYwfP55hw4bVWGFr165l0KBBtuX4+HjAvFNt1qxZXH/99Rw7dowpU6aQnJxMt27dWLBgwRnHMRKRmmW1Gqzdf4IfNh3mx83JdpfPgn3cGdYpghGdm3Fhyya4a74z55OWaAaird+bI1qfLqIztLsa2l+l/kTSYFVpHCQw5zBLSEigVatWBAcHs2LFCjp27MjGjRsZNWoU+/btq6VS65fK3iYo0pCU3n32342Hmb/pCMmZpzpaB/m4M6xjBFd2UShyWqm7Ydt3sPU7cwBHGwtE9zVbidpfBcGxjqpQ5LzV6G3+p/P19bX1O2rWrBl79uyhY8eOgHn7vYg0PDtTsvg+4TDfbzxMUlqubb2/pxtXdIzgqq7NuKR1qEKRM0rdDVvnwp/zIGXLqfUWF/MW/PYjzWDkrxtgpHGpckC68MILWbFiBe3bt2fEiBE88sgjbN68mW+//ZYLL7ywNmoUEQc4eCKX7zce5vuEw3aTwXq7uzKkQzgju0Zy6QWhmgjWGR3fA3+WhqLNp9a7uEHcAOgwyuxX5Kv5KaXxqnJAevXVV8nOzgbg2WefJTs7m9mzZ9OmTZs6uYNNRGpPWk4h8zcf4fuEQ6zZd8K23t3VwoALwhjZLZIh7cPw8dAt+U7nxP6Toehb+8tnLm7mHWcdRpuhyCfEURWK1CtV+iuXmZnJnj17KCwspFmzZjRt2pSZM2fWVm0iUgfyi0r4ZVsK8zYcYsmOYxSfnPzMYoEL45owqlskwzs1I9DH3cGVSpVlJZuhaPPX9h2tLa7QcgB0HAPtrlIoEqlApQNSQkICI0aMICUlBcMw8Pf3Z86cOQwdOrQ26xORWmC1Gqzel8a36w/y0+ZksgqKbds6RgYwultzru4aSUSgpoBwOnknzDvPtnwN+1acdku+xexT1Gms2a9Il89EzqrSAenxxx8nLi6Ob775Bi8vL6ZOncqkSZPYtWtXbdYnIjVo77Fs5m44xLfrD3EoPc+2vnmQN6O7RzK6W3PahPs7sEKplsJccyLYzV/DroVgLTq1LaoPdLoGOo5WR2uRKqh0QFq3bh0LFy60DQb5wQcfEBISQmZmpm5zF6nHMvKK+GHTYb5ed5ANSem29f6eblzZpRljujend2wILi4ay8apWEsgcSlsmgPb/guF2ae2hXcyQ1GnayC4heNqFHFilQ5IaWlpREVF2ZaDgoLw9fXl+PHjCkgi9UyJ1WD5rmN8ve4gC7emUFhsXmZxdbFwaZtQxvaI4vIO4Zrqw9kYBiRvMkPR5q8hO/nUtsAY6HwtdL4Owjs4rkaRBqJKnbS3bt1KcvKp/yANw2Dbtm1kZZ26BbhLly41V52IVMneY9l8ve4g36w/SErmqZGt24b7c12vKEZ2iyTMX/2KnE7mYTMUbZoNR7eeWu8dDB3HQpdx5kCOGtFapMZUeiRtFxcXLBYLFe1eut5isVBSUlLjRdZHGklb6oucgmLmbzrCV+sO2N2aH+zjzqhuzbm2ZxQdIwOw6MvTuRTmmpfONn4Be5cAJ//2unpC22HQ5XpofTm4eTiyShGnU+MjaScmJtZIYSJy/gzDYMOBdGavPsAPmw6TU2j+j4mLBQZc0JRxvaIZ3D5Mgzg6G8OApJWQ8Bn8+R0UnmqdJ6YfdP2LOV6Rd5CjKhRpNCodkFq0UEc/EUc7kVPIN+sPMnvNAXYdPdUpNy7Ul2t7RnFNjyjdmu+MMg5CwhdmMDpx2v+MBsdC1xvM1qKQOIeVJ9IYVSogJSUlERMTU+mDHjp0iObNm1e7KBE5xTAMVu49zperD7BgSzKFJWaHay93F0Z0bsb1vaLpExeiS2jOpigftv9ghqI9i7FdQvPwM2/J7zbebDXS71XEISoVkHr37s3o0aO544476N27d4X7ZGRkMGfOHF5//XXuuusuHnjggRotVKSxOZ5dwNfrDvLlmgMkpubY1neMDOAvfWIY1S2SAC+Nbu10kjfD+o/NTtf56afWx/Y3Q1GHkeDh67DyRMRUqYC0detWnn/+eS6//HK8vLzo2bMnkZGReHl5ceLECbZu3cqff/5Jjx49eOmllxgxYkRt1y3SIBmGwarEND5flWTXWuTn6cbIbpHc0DuGzlGBDq5Sqiw/w7wtf8MncHjDqfUBUdDtRvOhS2gi9Uql72IDyMvLY/78+axYsYL9+/eTl5dHaGgo3bt3Z+jQoXTq1Kk2a61XdBeb1KSMvCK+XX+Qz1Ylsfu0vkVdogK5sU8MV3eNxNdTE8Q6FcOAg2tg3UfmBLFFueZ6F3dzUtgeN0PLQeCijvQidamy399VCkhyigKS1ITNBzP49I/9fL/xMHlF5p1oPh6ujOoWyY19Wqi1yBnlpZvjFa2bZT9mUdN20OMWs8O15kETcZgav81fRGpGQXEJ8zcd4eOV+0k4kG5bf0G4Hzdf2ILR3Zvjr75FzsUw4NA6WPsBbPkWik/Oc+fmDR3HQM9bIbqPOlyLOBEFJJE6cig9j8/+2M/sNQc4nlMIgLurheGdmnHThS3oHRusO9GcTUE2bJ4Daz6AlM2n1od1NENRl3Eas0jESSkgidSi0k7Xs37bx8KtyVhPXtBuFujF+L4xXN87hqb+no4tUqru6DZY8z5s/PLUYI6untBpLPScqNYikQZAAUmkFuQXlTBvwyFm/b6P7cmnRkPu17IJEy5qwZD24bi5ujiwQqmykiJz3KLV78L+306tD2kFvW83B3T0CXFcfSJSoxSQRGpQckY+H6/cxxerkziRWwSAt7srY3o0Z0K/WNpG+Du4QqmyrBRY/5HZvyjriLnO4grtRkCv2yFuALgo7Io0NNUKSJ988gkzZ84kMTGRlStX0qJFC6ZPn05cXByjRo2q6RpF6r0NSSf48Ld9/Lj5CMUnr6NFBXszoV8s43pFE+ijTtdO5+BaWDUT/pwHVjPs4htm9i3qeSsEarYAkYasygHp7bffZsqUKTz00EM8//zzlJSYtyYHBQUxffp0BSRpNEqsBgv/TOa9FYms23/Ctr5vXAi3XRLHkPbhuLqoH4pTKS6ErfPMYHRo3an10X2hz13QfiS4eTisPBGpO1UOSDNmzODdd99l9OjRvPjii7b1vXr14tFHH63R4kTqo+yCYuasOcCHvydyIM28ndvD1YWru0Zy2yWxdIzU2EVOJ/sYrPsQ1rwH2SnmOlcP6HydGYwiuzm0PBGpe1UOSImJiXTv3r3cek9PT3Jycip4hUjDkJyRz4e/J/L5qiSy8osBCPZx56YLW3BzvxaE+Xs5uEKpspQ/4Y9/w6avoKTAXOffzOx03eNW8Gvq0PJExHGqHJDi4uJISEigRYsWdusXLFhA+/bta6wwkfpiR3IW/1m2l+83HqKoxOxf1DLUl9v7xzG2exTeHpoqwqkYBuz+BVa+CXuXnFof2QP63QcdRoGr+oyJNHZVDkjx8fHcd9995OfnYxgGq1ev5osvvmDatGm89957tVGjSJ0rHb9o5tI9LNlxzLa+T2wId17aksvaheGi/kXOpSjfnALkj3/Dse3mOouL2a/owns1dpGI2KlyQLrjjjvw9vbmySefJDc3lxtvvJHIyEhef/11/vKXv9RGjSJ1xmo1WLg1hZlL99imAXGxwNCOEdx1aUu6xwQ7tkCputw0s2/R6v9Azsmw6+EPPSdA379CUIxj6xOReqlKAam4uJjPP/+coUOHMn78eHJzc8nOziYsLKy26hOpE4XFVuYlHGLm0j3sPWb2pfNwc+G6nlHc2b8lsaG+Dq5QquzEPlj5b9jwCRTlmusCouDCu81JY73UmV5EzqxKAcnNzY27776bbdu2AeDj44OPj0+tFCZSF/IKS/hyTRLvLtvL4Yx8AAK83LilXywTLorVNCDO6Mgm+G06/DkXDKu5LqIzXPQgdByt/kUiUilVvsTWp08fNmzYUK6Ttogzycwv4pOV+3l/RSJpJyeODfP35I7+cdzYtwV+nhpk3qkYBuxbAStegz2LTq1vNRguegBaDlT/IhGpkip/C9x777088sgjHDx4kJ49e+Lra3/poUuXLjVWnEhNS8sp5MPfEpn1+z7brfoxIT78dUBLrukRhZe77khzKlYr7PwJlr8Kh9aa6ywu0HEsXPwgNNPfIxGpHothGEZVXuBSwZxDFosFwzCwWCy2kbUbuszMTAIDA8nIyCAgIMDR5cg5HMsq4N3le/n0j/3kFpr/RtuE+XHfoNZc1aWZJo51NiXF5iW0Fa/C0a3mOjcv6H4T9JsEIXGOrU9E6q3Kfn9Xa6BIEWdxNDOfmUv38tmq/RQUm/1ROkYGcP/g1lzRIUK36jub4kLY+DmsmA4nTv4t8gwwB3a88F7w0w0jIlIzqhyQ1PdInEFyRj4zl+7h89VJFJ4MRt2ig3jgstYMahuGRf1RnEtRvnk32orpkHnQXOcdAv3uhd53gneQI6sTkQaoygHp448/Puv2W265pdrFiJyvo5n5/HuJfTDq2SKYBy9rQ/82oQpGzqYw15wj7bc3IDvZXOcXARc/AD1vBQ8NvyAitaPKfZCCg+0HyisqKiI3NxcPDw98fHxIS0ur0QJry44dO7j++uvtlr/44gtGjx5dqderD1L9cjQrn5lL7C+l9Y4N5qEhF3BRqyYKRs6mMBfWfmDerl86uGNAFFzyEHS/Gdw1752IVE+t9UE6ceJEuXW7du3innvu4bHHHqvq4Rymbdu2JCQkAJCdnU1sbCyXX365Y4uSKjuRU8jMZXv46Pd95BedajF6eMgFXNxawcjpVBSMglpA/0eg6w3g5uHQ8kSk8aiRwV7atGnDiy++yE033cT27dtr4pB16vvvv+eyyy4rN2SB1F8ZeUW8vyKRD1Ykkl1g3q7fLTqIhy+/gEt1Kc35FOWbl9KWvwo5R811QS3g0seg6180uKOI1Lkau7fZzc2Nw4cP19ThWLZsGVdffTWRkZFYLBbmzZtXbp+33nqL2NhYvLy86Nu3L6tXr67We82ZM8fucpvUX7mFxby1eDeXvrSYNxbtIrugmA7NAvjg1l7MvfciBlzQVOHImRQXwOp34Y1usGCyGY6CYmDkDLh/HfS4WeFIRByiyi1I33//vd2yYRgcOXKEN998k4svvrjGCsvJyaFr167cdtttjB07ttz22bNnEx8fz8yZM+nbty/Tp09n6NCh7NixwzY3XLdu3SguLi732oULFxIZGQmY1yJ///13vvzyyxqrXWpeYbGVL9ckMePX3RzLKgDMcYziL7+AoR11u77TKSk2b9df+hJkHDDXBUTBpY+aYxkpFImIg533QJEWi4WmTZsyePBgXnnlFZo1a1ajBZa+x9y5c+06UPft25fevXvz5ptvAmC1WomOjub+++9n8uTJlT72J598wv/+9z8+/fTTs+5XUFBAQUGBbTkzM5Po6Gh10q5lJVaD7zce4tWfd3IgLQ+A6BBvHh5yAaO6NcdVwci5WK2wdS4sfgGO7zbX+UWYwajHLeCmue9EpHbVWidtq9V6XoXVhMLCQtatW8cTTzxhW+fi4sKQIUNYuXJllY41Z84c7rrrrnPuN23aNJ599tkq1yrVYxgGS3Ye458/bWd7chYATf09eWBwa67vHYOHm0a+diqGAbsWwqKpkLLZXOfTBC6JNwd5dPd2bH0iImWcdyftkpISNm/eTIsWLcoNAVBbUlNTKSkpITw83G59eHh4lTqJZ2RksHr1ar755ptz7vvEE08QHx9vWy5tQZKatyHpBC/+tJ1VieaQEQFebtw9sBW3XhSLj4cmkXU6SX/AL89A0sn/efEMgIvuhwvvAU9/h5YmInImVf62eeihh+jcuTO33347JSUlXHrppaxcuRIfHx9++OEHBg4cWAtl1o7AwEBSUlIqta+npyeenmr+r037UnN46X/b+XGzOSCgh5sLEy+K5Z6BrQjy0e3dTidlKyx6zpxMFsy50vrcBZc8DD4hjq1NROQcqhyQvv76a2666SYA/vvf/7Jv3z62b9/OJ598wt///nd+++23Gi+yrNDQUFxdXcuFm5SUFCIiImr9/aVmpeUU8saiXXy2aj9FJQYuFrimRxQPX34BkUG69OJ0Mg7B4uch4XPAAIur2fF64GQIiHR0dSIilVLlgJSammoLIT/++CPXXXcdF1xwAbfddhuvv/56jRdYEQ8PD3r27MmiRYtsHbetViuLFi1i0qRJdVKDnL/8ohI+/G0f/168m6yTYxkNbNuUJ4a3p22ELr04nfwMc660P/4NxfnmuvYjYfBT0PQCh5YmIlJVVQ5I4eHhbN26lWbNmrFgwQLefvttAHJzc3F1da2xwrKzs9m9e7dtOTExkYSEBEJCQoiJiSE+Pp4JEybQq1cv+vTpw/Tp08nJyWHixIk1VoPUDsMw+O+mI/zzp+0cSjfvTOsYGcDfRrTn4tahDq5Oqqy40Bzkcek/Ife4uS7mIrhiKkT1cmxtIiLVVOWANHHiRMaNG0ezZs2wWCwMGTIEgFWrVtGuXbsaK2zt2rUMGjTItlzaQXrChAnMmjWL66+/nmPHjjFlyhSSk5Pp1q0bCxYsKNdxW+qX9UknmPrDVjYkpQPQLNCLx4a2ZXS35hrLyNkYBuz4ERY+BWl7zHWhF8CQZ6HtcNCAnSLixKo8DhKY/ZAOHDjAddddR1RUFAAfffQRQUFBjBo1qsaLrI80WW3VHErP48WftvPfjeZo6z4ertwzoBV39G+Jt0fNtTxKHTmcAP/7O+xfYS77NoVBf4Put4Cr7jQUkfqrst/f1QpIZaWnpxMUFHS+h3EqCkiVk1dYwsyle3hn2R7yi6xYLHBdzygeuaIt4QGakd3pZB4x70zb+AVgmHem9bvPvDNNt+yLiBOotYEi//nPfxIbG2ubu2zcuHF88803NGvWjB9//JEuXbpUv2ppMEr7Gb344zYOZ5gddvvEhTDlqg50ah7o4OqkyoryYOWbsPw1KMox13UeB5dNgSCNByYiDU+VA9LMmTP57LPPAPj555/5+eef+emnn5gzZw6PPvooCxcurPEixblsPZzJM9//yep95kCPzYO8+fuV7RneKUITyTobw4Ct82DhFMhIMtdF9YFhL0JUT4eWJiJSm6ockJKTk20jSP/www+MGzeOK664gtjYWPr27VvjBYrzSM8t5JWFO/ls1X6sBni7u3LPwFbcdWlLvNzVz8jppPwJPz0O+5abywHNzQ7Yna9VB2wRafCqHJCCg4M5cOAA0dHRLFiwgH/84x+AeUmlpKSkxguU+q/EajB7zQH+9b/tnMgtAuDKLs34+4j2GujRGeWdgMXTYM17YJSY/YwufggufgA8fB1dnYhInahyQBo7diw33ngjbdq04fjx4wwfPhyADRs20Lp16xovUOq3TQfTeWreFjYezACgbbg/T4/swEWtNJ6R07FaIeFTc9600vGM2o+Eoc9DUIxDSxMRqWtVDkivvfYasbGxHDhwgJdeegk/Pz8Ajhw5wr333lvjBUr9lJ5byL/+t4PPVydhGODv6cbDl1/ALf1a4Obq4ujypKoOb4D5j8KhteZyaFsY/k9oNejsrxMRaaBq5Db/xqix3uZvGAZfrzvItJ+2k5ZTCMCY7s15Yng7wnTbvvPJOwG//gPWvA8Y4OFvzpnW96/g6u7o6kREalyt3eYP8Mknn/DOO++wd+9eVq5cSYsWLZg+fTpxcXGNZqDIxmhXShZ/n7eF1Ynm3WltwvyYOroTF7Zs4uDKpMoMwxzLaOFTkJtqrut8HVw+FQKaObY2EZF6oMrXQt5++23i4+MZPnw46enpto7ZQUFBTJ8+vabrk3ogr7CElxZsZ/jry1mdmIa3uyuTh7fjxwf7Kxw5o2M7YNZVMO8eMxw1bQcTfoBr3lM4EhE5qcotSDNmzODdd99l9OjRvPjii7b1vXr14tFHH63R4sTxlu08xt/nbeZAmjmp7JD2YTwzsiNRwT4OrkyqrCgPlr0Mv70O1iJw84aBj0O/SbqcJiJSRpUDUmJiIt27dy+33tPTk5ycnBopShzveHYB/5i/jbkbDgHmpLLPjOzI0I4RDq5MqmXPr/DDw3Bin7l8wTAY/hIEt3BoWSIi9VWVA1JcXBwJCQm0aGH/h3XBggW0b9++xgoTxzAMg2/WH+If87eSnluEiwVuvSiOR664AF9PTULqdHJSzUllN31pLvtHwoiXoN1VGuxRROQsqvyNFx8fz3333Ud+fj6GYbB69Wq++OILpk2bxnvvvVcbNUodSTqey9/mbmbFbrPTbvtmAbw4tjNdo4McW5hUnWHAxi/hf3+DvDTAYt6ZNvhJTSorIlIJVQ5Id9xxB97e3jz55JPk5uZy4403EhkZyeuvv85f/vKX2qhRalmJ1WDW7/t4+X87yCsqwdPNhYcvv4DbL4nDXWMaOZ8T++G/D8LexeZyWEcY+QZE9XJsXSIiTqRKAam4uJjPP/+coUOHMn78eHJzc8nOziYsLKy26pNatisli//7ZhMbktIB6BsXwj+v6UJsqKaUcDpWK6z+Dyx6DopyzClCBjwOF92vTtgiIlVUpYDk5ubG3XffzbZt2wDw8fHBx0d3Mzmj4hIr7yzby+u/7KKwxIqfpxt/G9Gev/SOxsVFfVOczrGd8P0kOLDKXG5xMVz9BoRq+h8Rkeqo8iW2Pn36sGHDhnKdtMV5bE/O5LGvNrH5kDl/2uB2YTw/phPNAjWxrNMpKYaVM8zJZUsKwMMPLn8Wet4GLro8KiJSXVUOSPfeey+PPPIIBw8epGfPnvj62l+K6dKlS40VJzWrqMTKO0v38PqiXRSVGAR4ufHMyI6M6d4ci+5ocj7HdpiDPR5aZy63HgJXTYegaIeWJSLSEFR5LjaXCv6v1GKxYBgGFovFNrJ2Q+dsc7HtSskifs5GW6vRkPbhvDCmk+ZPc0ZlW408A2HYNOh2o27dFxE5h1qbiy0xMfG8CpO6VWI1eH/FXl5euJPCYiuB3u48O7Ijo7pFqtXIGaXuhnl3w8E15nLry8071AIiHVuXiEgDU6WAlJmZyc6dOyksLKRPnz40bdq0tuqSGrD/eA6PfbWJ1fvMyWUHtm3KP6/pQrhajZyP1Qpr3oOfp0BxHngGnGw1Gq9WIxGRWlDpgJSQkMCIESNISUnBMAz8/f2ZM2cOQ4cOrc36pBoMw+DLNQeY+sNWcgtL8PVw5amrOnB972i1GjmjjIMw715IXGoutxwIo96CwCiHliUi0pBVOiA9/vjjxMXF8c033+Dl5cXUqVOZNGkSu3btqs36pIpSswuY/M0mftl2FDDHNXr5uq5Eh2g4BqdjGLBpDvz4KBRkmpPLXjEVet2uO9RERGpZpQPSunXrWLhwIT169ADggw8+ICQkhMzMTKfopNwY/LI1hce/2cTxnEI8XF14bGhbbr8kTuMaOaO8E/BDPPz5rbkc1RtGz9S4RiIidaTSASktLY2oqFNN+kFBQfj6+nL8+HEFJAfLLSxm6g/b+GJ1EgDtIvx57fputG+m34tT2rvUvH0/8xBYXGHgE3DJw+CqyYJFROpKlf7ibt26leTkZNuyYRhs27aNrKws2zqNg1S3thzK4IEvN7D3WA4WC9xxSRyPXNEWL3dXR5cmVVVcCL8+B7+/CRgQ0grGvgtRPR1dmYhIo1PpcZBcXFxs4x2VO4jGQarz97daDd5fkchL/9tOUYlBeIAnr43rxkWtQ+u8FqkBqbvhm9vgyEZzueetMPQF8NCceCIiNanGx0HS+Ef1x9GsfB6Zs5Hlu1IBuKJDOP+8pgvBvh4OrkyqzDAg4XP48TFzglnvYPMOtXZXOroyEZFGrdIBSXOv1Q9Ldx7jkTkJpGYX4uXuwpSrOnJDH92+75TyM+CHh2HLN+ZybH8Y+x8N+igiUg+o16eTKCqx8vLCHbyzdC9gdsSecUN32oT7O7gyqZZD6+CriZC+3+yIPfjvcPFD4KK+YyIi9YECkhM4kJbL/V9sIOFAOgA3XRjDk1d2UEdsZ2QY8Me/4eenwVoEQTFwzQcQ3dvRlYmIyGkUkOq5//2ZzKNfbSQrvxh/LzdeuqYLwzs3c3RZUh25aeaI2Dt/Mpfbj4SRM8A7yKFliYhIeVUKSIZhcODAAcLCwvDy0nxetamw2Mo/F2zn/RVm5/hu0UHMuKG7RsR2VgfWwFe3QuZBcPUw71DrfYfmURMRqaeqHJBat27Nn3/+SZs2bWqrpkbvUHoekz5fz4akdMAc2+j/hrXDw03TSzgdw4BVM2Hhk2AtNsc2um4WNNN4YSIi9VmVApKLiwtt2rTh+PHjCki15NftKcTP2Uh6bhH+Xm68fF1XhnaMcHRZUh35mfDdfbDte3O5w2jzkpqXRjgXEanvqtwk8eKLL/LYY4+xZcuW2qinUTMMg1m/7yc9t4guUYH8+EB/hSNnlbwF/jPQDEcu7jD8JbPlSOFIRMQpVHok7VLBwcHk5uZSXFyMh4cH3t7edtvT0tJqtMD6qrZG0k7NLuDD3xJ54LI2eLrpLjWntGkOfP8AFOdBQBSM+wiiejm6KhERoRZG0i41ffr086nLIcaMGcOSJUu47LLL+Prrryu9zRFC/Tx5bGg7R5ch1VFcaPY1Wv2OudxqMFzzPviEOLYuERGpsiq3IDmjJUuWkJWVxUcffVQuBJ1t29k4ei42qWeykmHOBDjwh7l86WMw8AkN/CgiUs/UWgsSQElJCfPmzWPbtm0AdOzYkZEjR+LqWj+/DAYOHMiSJUuqvE2kUpJWwZybITsFPANgzDvQboSjqxIRkfNQ5U7au3fvpn379txyyy18++23fPvtt9x000107NiRPXv2VLmAZcuWcfXVVxMZGYnFYmHevHnl9nnrrbeIjY3Fy8uLvn37snr16iq/j0itWDcLZl1phqOwDnDXEoUjEZEGoMoB6YEHHqBVq1YcOHCA9evXs379epKSkoiLi+OBBx6ocgE5OTl07dqVt956q8Lts2fPJj4+nqeffpr169fTtWtXhg4dytGjR237dOvWjU6dOpV7HD58uMr1nElBQQGZmZl2D2nEigvhh3j474PmlCEdRsHtP0OTVo6uTEREakCVL7EtXbqUP/74g5CQUx1PmzRpwosvvsjFF19c5QKGDx/O8OHDz7j91Vdf5c4772TixIkAzJw5k/nz5/PBBx8wefJkABISEqr8vlU1bdo0nn322Vp/H3EC2UfN/kZJvwMWc6LZ/o9qVGwRkQakyi1Inp6eZGVllVufnZ2Nh4dHjRRVqrCwkHXr1jFkyBDbOhcXF4YMGcLKlStr9L3O5YknniAjI8P2OHDgQJ2+v9QTRzbBfwaZ4cgzAG740uyQrXAkItKgVDkgXXXVVdx1112sWrUKwzAwDIM//viDu+++m5EjR9ZocampqZSUlBAeHm63Pjw8nOTk5EofZ8iQIVx33XX8+OOPREVF2YWrs207naenJwEBAXYPaWS2/Rc+GGrOpxbSCu5YBG2HOboqERGpBVW+xPbGG28wYcIE+vXrh7u7OwDFxcWMHDmS119/vcYLrAm//PJLtbaJAOZ8astfgV+nmsstB5qjYnsHO7IqERGpRVUOSEFBQXz33Xfs2rWLbdu2YbFYaN++Pa1bt67x4kJDQ3F1dSUlJcVufUpKChERmoJD6kBRPnx/P2yeYy73+SsMfQFcqzVChoiIOIlq/5Vv06aNLRRZaqn/hYeHBz179mTRokWMHj0aAKvVyqJFi5g0aVKtvKeITU4qfHEDHFwNLm4w4l/Q6zZHVyUiInWgyn2QAN5//306deqEl5cXXl5edOrUiffee69aBWRnZ5OQkGC7Ey0xMZGEhASSkpIAiI+P59133+Wjjz5i27Zt3HPPPeTk5NjuahOpFcd2wnuXmeHIKxBu+lbhSESkEalyC9KUKVN49dVXuf/+++nXrx8AK1eu5OGHHyYpKYnnnnuuSsdbu3YtgwYNsi3Hx8cDMGHCBGbNmsX111/PsWPHmDJlCsnJyXTr1o0FCxaU67gtUmP2LjVHxs7PgOBYuPEraHqBo6sSEZE6VOW52Jo2bcobb7zBDTfcYLf+iy++4P777yc1NbVGC6yvNBdbA7Xh05ODPxZDdF/4y+fgG+roqkREpIbU2lxsRUVF9OrVq9z6nj17UlxcXNXDidQPhgFLXoSlL5rLna6BUf8Gdy/H1iUiIg5R5T5IN998M2+//Xa59f/5z38YP358jRQlUqdKiuC7SafCUf9HYOx7CkciIo1Yte5ie//991m4cCEXXnghAKtWrSIpKYlbbrnF1ocIzGlCROq1gixz2pA9i8DiAle+Cr10A4CISGNX5YC0ZcsWevToAcCePXsAc7yi0NBQtmzZYtuvtm79F6kxWcnw2XWQvAncfeDaDzUytoiIANUISIsXL66NOkTq1vE98MkYSN8Pvk3hxtnQvKejqxIRkXpCwwFL43N4A3x6LeSmQnAc3PwthLR0dFUiIlKPVCsgrV27ljlz5pCUlERhYaHdtm+//bZGChOpFXsWw+yboDAbmnWF8V+DX5ijqxIRkXqmynexffnll1x00UVs27aNuXPnUlRUxJ9//smvv/5KYGBgbdQoUjO2fGP2OSrMhrgBMOEHhSMREalQlQPSCy+8wGuvvcZ///tfPDw8eP3119m+fTvjxo0jJiamNmoUOX9r3oevbwdrEXQcA+O/Ai8N8CkiIhWrckDas2cPV155JWBOJpuTk4PFYuHhhx/mP//5T40XKHLelr8K8+MBA3rfAde8D26ejq5KRETqsSoHpODgYLKysgBo3ry57db+9PR0cnNza7Y6kfNhGPDz07DoWXO5/6Mw4mVwcXVsXSIiUu9VuZP2pZdeys8//0znzp257rrrePDBB/n111/5+eefueyyy2qjRpGqs5bAj4/C2g/M5cufg4sfdGxNIiLiNCodkLZs2UKnTp148803yc/PB+Dvf/877u7u/P7771xzzTU8+eSTtVaoSKWVFMO8e2DzHMACV0+Hnrc6uCgREXEmFsMwjMrs6OLiQu/evbnjjjv4y1/+gr+/f23XVq9VdjZgqWPFhfDN7bDte3Bxg7H/MSeeFRERofLf35Xug7R06VI6duzII488QrNmzZgwYQLLly+vkWJFakRRPsy52QxHrh5w/acKRyIiUi2VDkj9+/fngw8+4MiRI8yYMYN9+/YxYMAALrjgAv75z3+SnJxcm3WKnF1hLnzxF9i5ANy84IYvoO1wR1clIiJOqsp3sfn6+jJx4kSWLl3Kzp07ue6663jrrbeIiYlh5MiRtVGjyNkVZJsDQO5dDO6+5ujYrYc4uioREXFile6DdCY5OTl89tlnPPHEE6Snp1NSUlJTtdVr6oNUT5SGo6TfwTPADEcxfR1dlYiI1FOV/f6u9mS1y5Yt44MPPuCbb77BxcWFcePGcfvtt1f3cCJVV5B1MhytBM9AuHkuRPV0dFUiItIAVCkgHT58mFmzZjFr1ix2797NRRddxBtvvMG4cePw9fWtrRpFyivIgk+vhQN/mOHolrnQXOFIRERqRqUD0vDhw/nll18IDQ3llltu4bbbbqNt27a1WZtIxRSORESkllU6ILm7u/P1119z1VVX4eqqqRrEQUr7HB34A7wC4eZ50LyHo6sSEZEGptIB6fvvv6/NOkTOrfRWflufo3kKRyIiUiuqfJu/iEMU5cPs8bBvOXj4w83fKhyJiEitUUCS+q+4EL6aAHt+PTnO0VcQ1cvRVYmISAOmgCT1W0kxfHPbqRGyb/wSWvRzdFUiItLAKSBJ/WW1wnf3wrb/mnOr/eVziLvU0VWJiEgjoIAk9ZNhwI+PwqbZ4OIG4z6G1pc5uioREWkkFJCkflr0LKx9H7DAmHc08ayIiNQpBSSpf5a/CiteM59f9Rp0vtax9YiISKOjgCT1y5r3zNYjgMufg14THVuPiIg0SgpIUn9s+RbmP2o+7/8oXPygY+sREZFGSwFJ6oe9S+DbuwADet0Og590dEUiItKIKSCJ4x3eAF+OB2sRdBgFI/4FFoujqxIRkUZMAUkc6/ge+PRaKMw2xzga+y64aDJkERFxLAUkcZysZPhkNOSmQrOucP1n4Obp6KpEREQUkMRBCrLgs+sgPQmC42D81+AV4OiqREREgEYSkMaMGUNwcDDXXlt+PJ3Y2Fi6dOlCt27dGDRokAOqa4RKiuCrWyF5E/iEws3fgl+Yo6sSERGxcXN0AXXhwQcf5LbbbuOjjz6qcPvvv/+On59fHVfVSBkG/PAQ7P4F3H1g/BwIaenoqkREROw0ihakgQMH4u/v7+gyBGDpS7DhU7C4wLUfQvOejq5IRESkHIcHpGXLlnH11VcTGRmJxWJh3rx55fZ56623iI2NxcvLi759+7J69eoae3+LxcKAAQPo3bs3n332WY0dVyqw4TNY8oL5fMTL0HaYY+sRERE5A4dfYsvJyaFr167cdtttjB07ttz22bNnEx8fz8yZM+nbty/Tp09n6NCh7Nixg7Aws99Kt27dKC4uLvfahQsXEhkZedb3X7FiBc2bN+fIkSMMGTKEzp0706VLl5r5cHLK3qXw3wfM55fEQ+/bHVuPiIjIWTg8IA0fPpzhw888U/urr77KnXfeycSJ5pxcM2fOZP78+XzwwQdMnjwZgISEhGq/f/PmzQFo1qwZI0aMYP369RUGpIKCAgoKCmzLmZmZ1X7PRid1F8y5GazF0OkauGyKoysSERE5K4dfYjubwsJC1q1bx5AhQ2zrXFxcGDJkCCtXrjzv4+fk5JCVlQVAdnY2v/76Kx07dqxw32nTphEYGGh7REdHn/f7Nwo5x83b+fMzIKoPjPq3RskWEZF6r14HpNTUVEpKSggPD7dbHx4eTnJycqWPM2TIEK677jp+/PFHoqKibOEqJSWFSy65hK5du3LhhRdyyy230Lt37wqP8cQTT5CRkWF7HDhwoPofrLEoLoDZ4+FEIgS1gBu+AHcvR1clIiJyTg6/xFYXfvnllwrXt2zZko0bN1bqGJ6ennh6apTnSjMM+P5+SFoJnoFw4xzwDXV0VSIiIpVSr1uQQkNDcXV1JSUlxW59SkoKERERDqpKKmX5y7BpNlhcYdxHENbO0RWJiIhUWr0OSB4eHvTs2ZNFixbZ1lmtVhYtWkS/fv0cWJmc1fb58Os/zOdXvgytNEK5iIg4F4dfYsvOzmb37t225cTERBISEggJCSEmJob4+HgmTJhAr1696NOnD9OnTycnJ8d2V5vUMyl/wjd3ms/73AW9bnNsPSIiItXg8IC0du1auznQ4uPjAZgwYQKzZs3i+uuv59ixY0yZMoXk5GS6devGggULynXclnog5zh88RcoyoG4S2HoC46uSEREpFoshmEYji7CGWVmZhIYGEhGRgYBAZqFnuJC+GQM7F8BwXFw56/gE+LoqkREROxU9vu7XvdBEiey4HEzHHn4ww1fKhyJiIhTU0CS87duFqz9ALDANe/pjjUREXF6Ckhyfg6uhR8fM58PflIT0IqISIOggCTVl30UZt8MJYXQ7iro/4ijKxIREakRCkhSPSVFMGcCZB2G0Atg9NuaY01ERBoMBSSpnoVPQtLvZqfsv3wOXrqTT0REGg4FJKm6jbNh1Uzz+dh3ILSNY+sRERGpYQpIUjUpW+GHh8znlz4G7a50aDkiIiK1QQFJKq8gC+bcAkW50HIQDHzC0RWJiIjUCgUkqRzDgO/vh+O7wD/SHO/IxdXRVYmIiNQKBSSpnNXvwp9zwcUNrpsFvqGOrkhERKTWKCDJuR1cC//7m/n88qkQ09ex9YiIiNQyN0cXIPVcbpo53pG1CNqPhAvvcXRFIiL1TklJCUVFRY4uQwB3d3dcXc+/C4gCkpyZYcB390HmQQhpCaPe1GCQIiKnMQyD5ORk0tPTHV2KnCYoKIiIiAgs5/GdpYAkZ7bqHdjxI7h6mP2OvAIdXZGISL1SGo7CwsLw8fE5ry9kOX+GYZCbm8vRo0cBaNasWbWPpYAkFTucAD8/ZT6/4h/QrKtDyxERqW9KSkps4ahJkyaOLkdO8vb2BuDo0aOEhYVV+3KbOmlLeQVZ8PXEU5PQ9rnL0RWJiNQ7pX2OfHx8HFyJlFX6OzmffmEKSGLPMOCHhyFtLwREwcgZ6nckInIWuqxW/9TE70QBSewlfAabvwKLK1z7PviEOLoiERGROqeAJKcc3wM//p/5fNDfIOZCx9YjIiK1YuDAgTz00EOOLqPa6qJ+BSQxlRTBN3dAUQ7E9odL4h1dkYiI1FP79u3DYrGQkJDg6FJqjQKSmJa8CIfXg1cQjJkJLvqnISIijZe+BQX2/QbLXzGfXz0dAqMcWo6IiLMyDIPcwuI6fxiGUeVai4uLmTRpEoGBgYSGhvLUU0/ZjmOxWJg3b57d/kFBQcyaNQuAuLg4ALp3747FYmHgwIEArFmzhssvv5zQ0FACAwMZMGAA69evtzuOxWLhvffeY8yYMfj4+NCmTRu+//57u32WLl1Knz598PT0pFmzZkyePJni4uIqf8bzoXGQGru8dJj7V8CAbjdBxzGOrkhExGnlFZXQYcr/6vx9tz43FB+Pqn2lf/TRR9x+++2sXr2atWvXctdddxETE8Odd955zteuXr2aPn368Msvv9CxY0c8PDwAyMrKYsKECcyYMQPDMHjllVcYMWIEu3btwt/f3/b6Z599lpdeeol//etfzJgxg/Hjx7N//35CQkI4dOgQI0aM4NZbb+Xjjz9m+/bt3HnnnXh5efHMM89U6TOeDwWkxswwYH48ZByA4DgY/qKjKxIRkToSHR3Na6+9hsVioW3btmzevJnXXnutUgGpadOmADRp0oSIiAjb+sGDB9vt95///IegoCCWLl3KVVddZVt/6623csMNNwDwwgsv8MYbb7B69WqGDRvGv//9b6Kjo3nzzTexWCy0a9eOw4cP8/jjjzNlyhRc6qgLiAJSY7b5a9jyjXlL/zXvgaf/uV8jIiJn5O3uytbnhjrkfavqwgsvtBsvqF+/frzyyiuUlJRUu46UlBSefPJJlixZwtGjRykpKSE3N5ekpCS7/bp06WJ77uvrS0BAgG16kG3bttGvXz+72i6++GKys7M5ePAgMTEx1a6vKhSQGqvMw/DjI+bzAY9DVC/H1iMi0gBYLJYqX+qqjywWS7l+TZUZlXrChAkcP36c119/nRYtWuDp6Um/fv0oLCy028/d3b3c+1mt1vMvvAapk3ZjZBjw3STIz4DIHtD/EUdXJCIidWzVqlV2y3/88Qdt2rTB1dWVpk2bcuTIEdu2Xbt2kZuba1su7XNUtrXpt99+44EHHmDEiBF07NgRT09PUlNTq1RX+/btWblypV1A++233/D39ycqqu5uIlJAaozWfgB7FoGbF4x5B1yd//92RESkapKSkoiPj2fHjh188cUXzJgxgwcffBAw+xK9+eabbNiwgbVr13L33XfbtfqEhYXh7e3NggULSElJISMjA4A2bdrwySefsG3bNlatWsX48eNtk8dW1r333suBAwe4//772b59O9999x1PP/008fHxddb/CBSQGp+0vbDwKfP5ZU9D0wscW4+IiDjELbfcQl5eHn369OG+++7jwQcf5K67zMnJX3nlFaKjo+nfvz833ngjjz76qN2kvG5ubrzxxhu88847REZGMmrUKADef/99Tpw4QY8ePbj55pt54IEHCAsLq1JdzZs358cff2T16tV07dqVu+++m9tvv50nn3yy5j58JViM6gyeIGRmZhIYGEhGRgYBAQGOLqdyrCXw4Qg48Ic5WvYt32tASBGRasrPzycxMZG4uDi8vLwcXY6c5my/m8p+f+vbsTFZ+aYZjjz8YdRbCkciIiJnoG/IxuLYTvj1efP5sGkQ3MKx9YiIiNRjCkiNgbUEvrsPSgqg9eXQ/SZHVyQiIlKvKSA1BqtmwsHV5qW1q6fDaYNviYiISHkKSA3d8T2waKr5/IqpmohWRESkEhSQGjKrFb6/H4rzIG4A9LzV0RWJiIg4BQWkhmzt+7D/N3D3hZFv6NKaiIhIJTWKgDRmzBiCg4O59tpry217+eWX6dixI506deLTTz91QHW15MR++Plp8/mQZyA41pHViIiIOJVGEZAefPBBPv7443LrN2/ezOeff866detYs2YNb775Junp6XVfYE0zDJgfD0U5ENMPet/h6IpEREScSqMISAMHDsTf37/c+m3bttGvXz+8vLzw9vama9euLFiwwAEV1rAt38DuX8DVA0bO0ICQIiIiVeTwb85ly5Zx9dVXExkZicViYd68eeX2eeutt4iNjcXLy4u+ffuyevXqGnnvTp06sWTJEtLT0zlx4gRLlizh0KFDNXJsh8lNgwWTzeeXPgahbRxbj4iIOI1bb72V0aNHO7qMesHh07jn5OTQtWtXbrvtNsaOHVtu++zZs4mPj2fmzJn07duX6dOnM3ToUHbs2GGbAK9bt24UFxeXe+3ChQuJjIw843t36NCBBx54gMGDBxMYGMiFF16Iq6trhfsWFBRQUFBgW87MzKzqR60bPz8FOcegaTu4+CFHVyMiIo1QYWEhHh4eji7j/Bj1CGDMnTvXbl2fPn2M++67z7ZcUlJiREZGGtOmTavSsRcvXmxcc801Z93n9ttvN3744YcKtz399NMGUO6RkZFRpTpq1d6lhvF0gPnYv9LR1YiINGh5eXnG1q1bjby8vFMrrVbDKMiu+4fVWqXav/rqK6NTp06Gl5eXERISYlx22WXGo48+Wu47bvHixcagQYPsvocNwzCOHj1quLu7G7/88othGIbRokUL47nnnjNuvvlmw9/f35gwYYJhGIaxfPly45JLLjG8vLyMqKgo4/777zeys7Ntx2nRooXx/PPPGxMnTjT8/PyM6Oho45133rF7r6SkJOO6664zAgMDjeDgYGPkyJFGYmJi1X83J2VkZFTq+9vhLUhnU1hYyLp163jiiSds61xcXBgyZAgrV66skfc4evQoYWFh7Nixg9WrVzNz5swK93viiSeIj4+3LWdmZhIdHV0jNdSIonz470Pm8163QcyFDi1HRKRRKsqFF8585aLW/O0wePhWatcjR45www038NJLLzFmzBiysrJYvnw5t9xyC0lJSWRmZvLhhx8CEBISwh133MGkSZN45ZVX8PT0BODTTz+lefPmDB482Hbcl19+mSlTpvD00+Yd1Hv27GHYsGH84x//4IMPPuDYsWNMmjSJSZMm2Y4P8MorrzB16lT+9re/8fXXX3PPPfcwYMAA2rZtS1FREUOHDqVfv34sX74cNzc3/vGPfzBs2DA2bdpUq61U9TogpaamUlJSQnh4uN368PBwtm/fXunjDBkyhI0bN5KTk0NUVBRfffUV/fr1A2DUqFFkZGTg6+vLhx9+iJtbxafE09PT9g+jXlr+MqTtAb8I87Z+ERGRChw5coTi4mLGjh1LixbmxOWdO3cGwNvbm4KCAiIiImz7jx07lkmTJvHdd98xbtw4AGbNmsWtt96K5bTx9QYPHswjjzxiW77jjjsYP348Dz30EABt2rThjTfeYMCAAbz99tt4eXkBMGLECO69914AHn/8cV577TUWL15M27ZtmT17Nlarlffee8/2Xh9++CFBQUEsWbKEK664opbOUj0PSDXll19+OeO2mmqJcqhjO2HFdPP5iH+BV6BDyxERabTcfczWHEe8byV17dqVyy67jM6dOzN06FCuuOIKrr32WoKDgyvc38vLi5tvvpkPPviAcePGsX79erZs2cL3339vt1+vXr3sljdu3MimTZv47LPPbOsMw8BqtZKYmEj79u0B6NKli227xWIhIiKCo0eP2o6xe/fucnei5+fns2fPnkp/5uqo1wEpNDQUV1dXUlJS7NanpKTYpdtGzTDgx0fAWgRthkL7qx1dkYhI42WxVPpSl6O4urry888/8/vvv7Nw4UJmzJjB3//+d1atWnXG19xxxx1069aNgwcP8uGHHzJ48GBb61MpX1/7z52dnc1f//pXHnjggXLHi4mJsT13d3e322axWLBa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bt268fHHH3PZZZexZcsW2rRpo7/PtUgBqRG577772LJli93/fQA89dRTpKen88svvxAaGsq8efMYN24cy5cvp3Pnzg6q1vm0bduWhIQEMjIy+Prrr5kwYQJLly51dFkN0pnO9ekhKTMzkyuvvJIOHTrwzDPPOK5YJ3am87x7925+/fVXu36KUn1nOs9WqxWAv/71r0ycOBGA7t27s2jRIj744AOmTZvmyLIbPAWkRmLSpEm2zntRUVG29Xv27OHNN99ky5YtdOzYEYCuXbuyfPly3nrrLWbOnElERARHjx61O15xcTFpaWkVNq03Vh4eHrZWt549e7JmzRpef/11rr/+egoLC0lPT7drRUpJSbGdv4iICFavXm13vNK73HSOyzvTuX7nnXcAyMrKYtiwYfj7+zN37lzc3d1tr9W5rrwznWdvb2/27NlTrlX0mmuuoX///ixZskTnuQrOdJ4nT54MUK51tH379iQlJQHo73MtUh+kBs4wDCZNmsTcuXP59ddfiYuLs9uem5sLYHdHBICrq6vt/1769etHeno669ats23/9ddfsVqt9O3bt5Y/gfOyWq0UFBTQs2dP3N3dWbRokW3bjh07SEpKsvXn6NevH5s3b7b7Q/fzzz8TEBBQ4aUjsVd6rsFsObriiivw8PDg+++/x8vLy25fnevqKz3PkydPZtOmTSQkJNgeAK+99hoffvghoPN8PkrPc2xsLJGRkeWGZtm5cyctWrQA9Pe5Vjm6l7jUrnvuuccIDAw0lixZYhw5csT2yM3NNQzDMAoLC43WrVsb/fv3N1atWmXs3r3bePnllw2LxWLMnz/fdpxhw4YZ3bt3N1atWmWsWLHCaNOmjXHDDTc46mPVO5MnTzaWLl1qJCYmGps2bTImT55sWCwWY+HChYZhGMbdd99txMTEGL/++quxdu1ao1+/fka/fv1sry8uLjY6depkXHHFFUZCQoKxYMECo2nTpsYTTzzhqI9Ub53tXGdkZBh9+/Y1OnfubOzevdvu33xxcbFhGDrXlXWuf9NlUeYuNp3nyjnXeX7ttdeMgIAA46uvvjJ27dplPPnkk4aXl5exe/du2zH097l2KCA1cECFjw8//NC2z86dO42xY8caYWFhho+Pj9GlS5dyt/0fP37cuOGGGww/Pz8jICDAmDhxopGVlVXHn6b+uu2224wWLVoYHh4eRtOmTY3LLrvM7oskLy/PuPfee43g4GDDx8fHGDNmjHHkyBG7Y+zbt88YPny44e3tbYSGhhqPPPKI7dZ0OeVs53rx4sVn/DefmJhoO4bO9bmd6990WWUDkmHoPFdGZc7ztGnTjKioKMPHx8fo16+fsXz5crvt+vtcOyyGYRiOaLkSERERqa/UB0lERESkDAUkERERkTIUkERERETKUEASERERKUMBSURERKQMBSQRERGRMhSQRERERMpQQBIREREpQwFJRMTJPPXUU9x1111Ves1f/vIXXnnllVqqSKThUUASkWqxWCxnfTzzzDOOLrHGxcbGMn36dIfWkJyczOuvv87f//5327pbb72V0aNH2+339ddf4+XlZQtFTz75JM8//zwZGRl1Wa6I01JAEpFqOXLkiO0xffp0AgIC7NY9+uijji6xUgzDoLi4uE7fs7CwsNqvfe+997joootss7mfaZ/x48fz9ttv88gjjwDQqVMnWrVqxaefflrt9xZpTBSQRKRaIiIibI/AwEAsFovdui+//JL27dvj5eVFu3bt+Pe//2177b59+7BYLMyZM4f+/fvj7e1N79692blzJ2vWrKFXr174+fkxfPhwjh07ZntdaUvJs88+S9OmTQkICODuu++2CxxWq5Vp06YRFxeHt7c3Xbt25euvv7ZtX7JkCRaLhZ9++omePXvi6enJihUr2LNnD6NGjSI8PBw/Pz969+7NL7/8YnvdwIED2b9/Pw8//LCtlQzgmWeeoVu3bnbnZvr06cTGxpar+/nnnycyMpK2bdsCcODAAcaNG0dQUBAhISGMGjWKffv2nfW8f/nll1x99dVn3P7SSy9x//338+WXXzJx4kS7bVdffTVffvnlWY8vIiYFJBGpcZ999hlTpkzh+eefZ9u2bbzwwgs89dRTfPTRR3b7Pf300zz55JOsX78eNzc3brzxRv7v//6P119/neXLl7N7926mTJli95pFixaxbds2lixZwhdffMG3337Ls88+a9s+bdo0Pv74Y2bOnMmff/7Jww8/zE033cTSpUvtjjN58mRefPFFtm3bRpcuXcjOzmbEiBEsWrSIDRs2MGzYMK6++mqSkpIA+Pbbb4mKiuK5556ztZJVxaJFi9ixYwc///wzP/zwA0VFRQwdOhR/f3+WL1/Ob7/9hp+fH8OGDTtjC1NaWhpbt26lV69eFW5//PHHmTp1Kj/88ANjxowpt71Pnz6sXr2agoKCKtUu0igZIiLn6cMPPzQCAwNty61atTI+//xzu32mTp1q9OvXzzAMw0hMTDQA47333rNt/+KLLwzAWLRokW3dtGnTjLZt29qWJ0yYYISEhBg5OTm2dW+//bbh5+dnlJSUGPn5+YaPj4/x+++/27337bffbtxwww2GYRjG4sWLDcCYN2/eOT9Xx44djRkzZtiWW7RoYbz22mt2+zz99NNG165d7da99tprRosWLezqDg8PNwoKCmzrPvnkE6Nt27aG1Wq1rSsoKDC8vb2N//3vfxXWs2HDBgMwkpKS7NZPmDDB8PDwKHf+ytq4caMBGPv27TvjPiJicnNkOBORhicnJ4c9e/Zw++23c+edd9rWFxcXExgYaLdvly5dbM/Dw8MB6Ny5s926o0eP2r2ma9eu+Pj42Jb79etHdnY2Bw4cIDs7m9zcXC6//HK71xQWFtK9e3e7dWVbYbKzs3nmmWeYP38+R44cobi4mLy8PFsL0vnq3LkzHh4etuWNGzeye/du/P397fbLz89nz549FR4jLy8PAC8vr3LbunTpQmpqKk8//TR9+vTBz8+v3D7e3t4A5ObmVvtziDQWCkgiUqOys7MBePfdd+nbt6/dNldXV7tld3d32/PSPj1l11mt1iq/9/z582nevLndNk9PT7tlX19fu+VHH32Un3/+mZdffpnWrVvj7e3Ntddee84O1S4uLhiGYbeuqKio3H5l3y87O5uePXvy2Wefldu3adOmFb5XaGgoACdOnCi3T/Pmzfn6668ZNGgQw4YN46effioXvtLS0s56fBE5RQFJRGpUeHg4kZGR7N27l/Hjx9f48Tdu3EheXp6tNeSPP/7Az8+P6OhoQkJC8PT0JCkpiQEDBlTpuL/99hu33nqrre9OdnZ2uQ7THh4elJSU2K1r2rQpycnJGIZhC3kJCQnnfL8ePXowe/ZswsLCCAgIqFSNrVq1IiAggK1bt3LBBReU296iRQuWLl1qC0kLFiywC0lbtmwhKirKFrRE5MzUSVtEatyzzz7LtGnTeOONN9i5cyebN2/mww8/5NVXXz3vYxcWFnL77bezdetWfvzxR55++mkmTZqEi4sL/v7+PProozz88MN89NFH7Nmzh/Xr1zNjxoxyHcTLatOmDd9++y0JCQls3LiRG2+8sVzrVWxsLMuWLePQoUOkpqYC5t1tx44d46WXXmLPnj289dZb/PTTT+f8HOPHjyc0NJRRo0axfPlyEhMTWbJkCQ888AAHDx6s8DUuLi4MGTKEFStWnPG40dHRLFmyhKNHjzJ06FAyMzNt25YvX84VV1xxztpERAFJRGrBHXfcwXvvvceHH35I586dGTBgALNmzSIuLu68j33ZZZfRpk0bLr30Uq6//npGjhxpNyjl1KlTeeqpp5g2bRrt27dn2LBhzJ8//5zv/eqrrxIcHMxFF13E1VdfzdChQ+nRo4fdPs899xz79u2jVatWtstU7du359///jdvvfUWXbt2ZfXq1ZUaA8rHx4dly5YRExPD2LFjad++Pbfffjv5+flnbVG64447+PLLL8966TEqKoolS5aQmppqC0n5+fnMmzfPrl+YiJyZxSh78VxEpJ669dZbSU9PZ968eY4uxWEMw6Bv3748/PDD3HDDDZV+3dtvv83cuXNZuHBhLVYn0nCoBUlExIlYLBb+85//VHn0b3d3d2bMmFFLVYk0PGpBEhGnoRYkEakrCkgiIiIiZegSm4iIiEgZCkgiIiIiZSggiYiIiJShgCQiIiJShgKSiIiISBkKSCIiIiJlKCCJiIiIlKGAJCIiIlLG/wMTpflFxdHa+gAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "temperature_range = np.linspace(273.15, 373.15, 100) # Temperature range from 0 to 100 degrees Celsius.\n", + "\n", + "organic_pure_vapor_pressure = organic_species.get_pure_vapor_pressure(temperature_range)\n", + "water_pure_vapor_pressure = water_species.get_pure_vapor_pressure(temperature_range)\n", + "\n", + "# Plotting the vapor pressure curves for the organic species.\n", + "fig, ax = plt.subplots()\n", + "for i in range(len(organic_names)):\n", + " ax.plot(temperature_range, organic_pure_vapor_pressure[i], label=organic_names[i])\n", + "ax.plot(temperature_range, water_pure_vapor_pressure, label=\"Water\")\n", + "ax.set_xlabel(\"Temperature (K)\")\n", + "ax.set_ylabel(\"Vapor Pressure (Pa)\")\n", + "ax.set_yscale('log')\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Saturation Ratios\n", + "\n", + "Now that we have established the concentration of each gas species within the mixture, we can proceed to calculate the saturation ratio for each species. The saturation ratio is an essential parameter in determining the condensation behavior of gas species within a mixture.\n", + "\n", + "- **Above 1**: A saturation ratio greater than 1 indicates that the species is supersaturated and is likely to condense.\n", + "- **Below 1**: Conversely, a saturation ratio below 1 suggests that the species will likely remain in the gas phase.\n", + "\n", + "### Future Exploration\n", + "\n", + "In subsequent sections of this notebook series, we will delve deeper into how these saturation ratios reach equilibrium with a liquid phase, enhancing our understanding of the phase behavior under different conditions." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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4l824n+GYdSr+8VKS5curfW8ZkxJSEgISUlJZGZmet7bsmULJSUHuzkdDgfAYa0vixcv5uWXX2bEiBEAZGRksG/fvnrV1blzZ/773/9imqanVWXx4sXExMTQsmXLeh3rZKnrR0SCl5e6fqIdodS0cBeq+0f8aMeOHYwfP57Nmzfz4Ycf8sILL3D33XcD7rEmL774IqtWrWLFihWMHTu2VitIcnIyERERfPPNN+zZs4f8/HwAOnTowLvvvsvGjRtZunQp11xzjWeTwLq67bbbyMjI4M4772TTpk189tlnPPzww4wfP96v41NAQUVEgpmXBtPabAYxYZqiLP533XXXUVpayumnn87tt9/O3XffzR//+EcAnn76aVJTUznrrLO4+uqruffee2ttvhgaGsrzzz/Pq6++SvPmzRk5ciQA//73v8nNzaV379784Q9/4K677iI5ObledbVo0YKZM2eybNkyevTowdixY7npppt44IEHvPfD15Fh1ncuVQApKCggNjaW/Px8nE6n1eWIiL/l/grPdXevp/JA1kkd6sx/zmFnbinTbxtAr1bxXipQfK2srIz09HTS0tIIDw+3uhw5xLH+29Tn72+1qIhI8KppUakqhZMcBHhwGX11/YgEEgUVEQle9kP63U92B2VtTCgSkBRURCR4HRpUvLQxoRZ9EwksCioiErxsIRDinqJ5smupeJbR12BakYCioCIiwc1bq9OGawdlkUCkoCIiwc1LU5Rj1aIiEpAUVEQkuHl7vx+NUREJKAoqIhLcvLWMvqYniwQkBRURCW6hBxaS8tJ+P2pREQksCioiEtw8XT8nN0bFGa4l9EUCkYKKiAQ3z+q0J7vgm2b9SGAYM2YMl1xyidVlBAwFFREJbl4bTHuw6yeIt0AT8aioqLC6BK9QUBGR4Oblrp+KahflVSe3b5BIXXzyySd069aNiIgImjRpwrnnnstf/vIX3n77bT777DMMw8AwDObNm8c555zDHXfcUev7e/fuxeFwMHv2bADatGnDY489xnXXXYfT6fTswrxo0SLOOussIiIiSE1N5a677qK4uNhznDZt2vDEE09w4403EhMTQ6tWrXjttddqnSsjI4MrrriCuLg4EhISGDlyJNu3b/ftBTpAQUVEgpuXWlSiHKHYDPdjDagNcqYJFcXW3OrYGpeZmcno0aO58cYb2bhxI/PmzeOyyy7j4Ycf5oorrmD48OFkZmaSmZnJgAEDuPnmm/nggw8oLy/3HOO9996jRYsWnHPOOZ7XnnrqKXr06MGqVat48MEH2bZtG8OHD2fUqFGsXbuWjz76iEWLFh0Wep5++mn69u3LqlWruO2227j11lvZvHkzAJWVlZx//vnExMSwcOFCFi9eTHR0NMOHD/dLq02oz88gIuJLXpqebLMZOCPs5JVUUlBWSbIz/PhfksBUWQJPNLfm3H/bDY6o434sMzOTqqoqLrvsMlq3bg1At27dAIiIiKC8vJyUlBTP5y+77DLuuOMOPvvsM6644goA3nrrLcaMGYNhGJ7PnXPOOfz5z3/2PL/55pu55ppruOeeewDo0KEDzz//PIMGDWLKlCmEh7v/nI8YMYLbbrsNgPvuu4/Jkyczd+5cOnbsyEcffYTL5eKNN97wnOvNN98kLi6OefPmcd55553o1aoTtaiISHDzUosKHLoxoQbUim/16NGDoUOH0q1bNy6//HJef/11cnNzj/r58PBw/vCHP/Cf//wHgJUrV7J+/XrGjBlT63N9+/at9XzNmjW89dZbREdHe27nn38+LpeL9PR0z+e6d+/ueWwYBikpKWRnZ3uOsXXrVmJiYjzHSEhIoKysjG3btp3spTgutaiISHDzrKNycmNU4JDVaTVFObjZI90tG1aduw5CQkKYNWsWS5Ys4dtvv+WFF17g73//O0uXLj3qd26++WZ69uzJzp07efPNNznnnHM8rTE1oqJqt+YUFRXxpz/9ibvuuuuw47Vq1epg2XZ7rfcMw8DlcnmO0adPH95///3DjpGUlHT8H/YkKaiISHDzUtcPHLoxoYJKUDOMOnW/WM0wDAYOHMjAgQN56KGHaN26NdOnT8fhcFBdXX3Y57t160bfvn15/fXX+eCDD3jxxRePe47evXuzYcMG2rdvf8J19u7dm48++ojk5GScTucJH+dEqetHRIJbTdfPSa6jAlpGX/xn6dKlPPHEE6xYsYIdO3bw6aefsnfvXjp37kybNm1Yu3YtmzdvZt++fVRWHgzON998M08++SSmaXLppZce9zz33XcfS5Ys4Y477mD16tVs2bKFzz777LDBtMdyzTXXkJiYyMiRI1m4cCHp6enMmzePu+66i507d57Qz18fCioiEty8tHsyaGNC8R+n08mCBQsYMWIEp5xyCg88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rcyioiLPZ4YNG2aedtpp5tKlS81t27aZjz32mGmz2cyVK1d6PjN8+HCzR48e5g8//GAuXLjQbN++vTl69GgrfqSA9fnnn5tfffWV+fPPP5ubN282//a3v5l2u91cv369aZqmOXbsWDM1NdWcPXu2uWLFCvOMM84wBwwY4Pl+VVWVeeqpp5rnnnuuuWrVKnPmzJlmYmKief/991v1IwWkY13ndevWmZdddpn5+eefm1u3bjVnz55tdujQwRw1apTn+7rOdXO8P881nnnmGfOCCy4wAXP69Ome13Wd6+Z413nJkiWm0+k0J02aZK5fv97ctGmT+dFHH5llZWWeY+j3s+8oqFggOzvbBMz58+d7XouKijLfeeedWp9LSEgwX3/9ddM0TXPDhg0mYC5fvtzz/tdff20ahmHu2rXLP4UHqfj4ePONN94w8/LyTLvdbn788cee9zZu3GgC5vfff2+apmnOnDnTtNlsZlZWluczU6ZMMZ1Op1leXu732oNJzXU+kmnTppkOh8OsrKw0TVPX+WT89jqvWrXKbNGihZmZmXlYUNF1PnGHXud+/fqZDzzwwFE/q9/PvqWuHwvUNIEnJCR4XhswYAAfffQROTk5uFwupk6dSllZGYMHDwbczY5xcXH07dvX851zzz0Xm83G0qVL/Vp/sKiurmbq1KkUFxfTv39/fvzxRyorKzn33HM9n+nUqROtWrXi+++/B9zXuVu3brUWHDz//PMpKCjgp59+8vvPEAx+e52PJD8/H6fTSWioe41JXef6O9J1Likp4eqrr+all1464v5ous7199vrnJ2dzdKlS0lOTmbAgAE0bdqUQYMGsWjRIs939PvZtyxfmbaxcblc3HPPPQwcOJBTTz3V8/q0adO48soradKkCaGhoURGRjJ9+nTat28PuMewJCcn1zpWaGgoCQkJZGVl+fVnCHTr1q2jf//+lJWVER0dzfTp0+nSpQurV6/G4XActpFl06ZNPdcwKyvrsFWRa57rOtd2tOv8W/v27eOxxx7jj3/8o+c1Xee6O9Z1HjduHAMGDGDkyJFH/K6uc90d7Tr/8MMPADzyyCM89dRT9OzZk3feeYehQ4eyfv16OnTooN/PPqag4me3334769evr5XGAR588EHy8vL47rvvSExMZMaMGVxxxRUsXLiQbt26WVRtcOrYsSOrV68mPz+fTz75hOuvv5758+dbXVaDc7TrfGhYKSgo4MILL6RLly488sgj1hUbxI52nbdu3cqcOXNYtWqV1SU2CEe7zi6XC4A//elPnj3oevXqxezZs/nPf/7DpEmTrCy7UVBQ8aM77riDL7/8kgULFtCyZUvP69u2bePFF19k/fr1dO3aFYAePXqwcOFCXnrpJV555RVSUlLIzs6udbyqqipycnKO2OTbmDkcDk9LVJ8+fVi+fDnPPfccV155JRUVFeTl5dVqVdmzZ4/nGqakpLBs2bJax6uZFaTrXNvRrvOrr74KQGFhIcOHDycmJobp06djt9s939V1rrujXeeIiAi2bdt2WAvhqFGjOOuss5g3b56ucz0c7TpPmDAB4LDWws6dO7Njxw4A/X72MY1R8QPTNLnjjjuYPn06c+bMIS0trdb7JSUlANhstf9zhISEeNJ8//79ycvL48cff/S8P2fOHFwuF/369fPxTxDcXC4X5eXl9OnTB7vdzuzZsz3vbd68mR07dnj6/Pv378+6detq/dKZNWsWTqfziN0aclDNdQZ3S8p5552Hw+Hg888/Jzw8vNZndZ1PXM11njBhAmvXrmX16tWeG8DkyZN58803AV3nk1Fzndu0aUPz5s0PW1Li559/pnXr1oB+P/uc1aN5G4Nbb73VjI2NNefNm2dmZmZ6biUlJaZpmmZFRYXZvn1786yzzjKXLl1qbt261XzqqadMwzDMr776ynOc4cOHm7169TKXLl1qLlq0yOzQoYOmv/3GhAkTzPnz55vp6enm2rVrzQkTJpiGYZjffvutaZru6cmtWrUy58yZY65YscLs37+/2b9/f8/3a6Zznnfeeebq1avNb775xkxKStJ0zt841nXOz883+/XrZ3br1s3cunVrrT/zVVVVpmnqOtfV8f48/xZHmZ6s63xsx7vOkydPNp1Op/nxxx+bW7ZsMR944AEzPDzc3Lp1q+cY+v3sOwoqfgAc8fbmm296PvPzzz+bl112mZmcnGxGRkaa3bt3P2y68v79+83Ro0eb0dHRptPpNG+44QazsLDQzz9NYLvxxhvN1q1bmw6Hw0xKSjKHDh1a65d6aWmpedttt5nx8fFmZGSkeemll5qZmZm1jrF9+3bzggsuMCMiIszExETzz3/+s2darbgd6zrPnTv3qH/m09PTPcfQdT6+4/15/q3fBhXT1HWui7pc50mTJpktW7Y0IyMjzf79+5sLFy6s9b5+P/uOYZqmaUVLjoiIiMjxaIyKiIiIBCwFFREREQlYCioiIiISsBRUREREJGApqIiIiEjAUlARERGRgKWgIiIiIgFLQUVE5AQ8+OCDtXaErourrrqKp59+2kcViTRMCioiQcwwjGPeGuKOxW3atOHZZ5+1tIasrCyee+45/v73v3teGzNmDJdcckmtz33yySeEh4d7wskDDzzA448/Tn5+vj/LFQlqCioiQSwzM9Nze/bZZ3E6nbVeu/fee60usU5M06Sqqsqv56yoqDjh777xxhsMGDDAsynd0T5zzTXXMGXKFP785z8DcOqpp9KuXTvee++9Ez63SGOjoCISxFJSUjy32NhYDMOo9drUqVPp3Lkz4eHhdOrUiZdfftnz3e3bt2MYBtOmTeOss84iIiKC0047jZ9//pnly5fTt29foqOjueCCC9i7d6/nezUtBxMnTiQpKQmn08nYsWNr/cXvcrmYNGkSaWlpRERE0KNHDz755BPP+/PmzcMwDL7++mv69OlDWFgYixYtYtu2bYwcOZKmTZsSHR3Naaedxnfffef53uDBg/n1118ZN26cp9UI4JFHHqFnz561rs2zzz5LmzZtDqv78ccfp3nz5nTs2BGAjIwMrrjiCuLi4khISGDkyJFs3779mNd96tSpXHTRRUd9/1//+hd33nknU6dO5YYbbqj13kUXXcTUqVOPeXwROUhBRaSBev/993nooYd4/PHH2bhxI0888QQPPvggb7/9dq3PPfzwwzzwwAOsXLmS0NBQrr76av7617/y3HPPsXDhQrZu3cpDDz1U6zuzZ89m48aNzJs3jw8//JBPP/2UiRMnet6fNGkS77zzDq+88go//fQT48aN49prr2X+/Pm1jjNhwgSefPJJNm7cSPfu3SkqKmLEiBHMnj2bVatWMXz4cC666CJ27NgBwKeffkrLli159NFHPa1G9TF79mw2b97MrFmz+PLLL6msrOT8888nJiaGhQsXsnjxYqKjoxk+fPhRW1xycnLYsGEDffv2PeL79913H4899hhffvkll1566WHvn3766Sxbtozy8vJ61S7SaFm8KaKIeMmbb75pxsbGep63a9fO/OCDD2p95rHHHjP79+9vmqZppqenm4D5xhtveN7/8MMPTcCcPXu257VJkyaZHTt29Dy//vrrzYSEBLO4uNjz2pQpU8zo6GizurraLCsrMyMjI80lS5bUOvdNN93k2fa+ZoflGTNmHPfn6tq1q/nCCy94nrdu3dqcPHlyrc88/PDDZo8ePWq9NnnyZLN169a16m7atKlZXl7uee3dd981O3bsaLpcLs9r5eXlZkREhPm///3viPWsWrXKBMwdO3bUev366683HQ7HYdfvt9asWWMC5vbt24/6GRE5KNTKkCQivlFcXMy2bdu46aabuOWWWzyvV1VVERsbW+uz3bt39zxu2rQpAN26dav1WnZ2dq3v9OjRg8jISM/z/v37U1RUREZGBkVFRZSUlDBs2LBa36moqKBXr161Xvttq0RRURGPPPIIX331FZmZmVRVVVFaWuppUTlZ3bp1w+FweJ6vWbOGrVu3EhMTU+tzZWVlbNu27YjHKC0tBSA8PPyw97p3786+fft4+OGHOf3004mOjj7sMxEREQCUlJSc8M8h0pgoqIg0QEVFRQC8/vrr9OvXr9Z7ISEhtZ7b7XbP45oxH799zeVy1fvcX331FS1atKj1XlhYWK3nUVFRtZ7fe++9zJo1i6eeeor27dsTERHB73//++MOfLXZbJimWeu1ysrKwz732/MVFRXRp08f3n///cM+m5SUdMRzJSYmApCbm3vYZ1q0aMEnn3zCkCFDGD58OF9//fVhISgnJ+eYxxeR2hRURBqgpk2b0rx5c3755ReuueYarx9/zZo1lJaWeloHfvjhB6Kjo0lNTSUhIYGwsDB27NjBoEGD6nXcxYsXM2bMGM/YjqKiosMGtjocDqqrq2u9lpSURFZWFqZpesLW6tWrj3u+3r1789FHH5GcnIzT6axTje3atcPpdLJhwwZOOeWUw95v3bo18+fP94SVb775plZYWb9+PS1btvQEHhE5Ng2mFWmgJk6cyKRJk3j++ef5+eefWbduHW+++SbPPPPMSR+7oqKCm266iQ0bNjBz5kwefvhh7rjjDmw2GzExMdx7772MGzeOt99+m23btrFy5UpeeOGFwwby/laHDh349NNPWb16NWvWrOHqq68+rDWnTZs2LFiwgF27drFv3z7APRto7969/Otf/2Lbtm289NJLfP3118f9Oa655hoSExMZOXIkCxcuJD09nXnz5nHXXXexc+fOI37HZrNx7rnnsmjRoqMeNzU1lXnz5pGdnc35559PQUGB572FCxdy3nnnHbc2EXFTUBFpoG6++WbeeOMN3nzzTbp168agQYN46623SEtLO+ljDx06lA4dOnD22Wdz5ZVXcvHFF9daXO6xxx7jwQcfZNKkSXTu3Jnhw4fz1VdfHffczzzzDPHx8QwYMICLLrqI888/n969e9f6zKOPPsr27dtp166dp/ukc+fOvPzyy7z00kv06NGDZcuW1WkNmcjISBYsWECrVq247LLL6Ny5MzfddBNlZWXHbGG5+eabmTp16jG7xFq2bMm8efPYt2+fJ6yUlZUxY8aMWuOGROTYDPO3HbsiIscwZswY8vLymDFjhtWlWMY0Tfr168e4ceMYPXp0nb83ZcoUpk+fzrfffuvD6kQaFrWoiIjUk2EYvPbaa/VeTddut/PCCy/4qCqRhkktKiJSL2pRERF/UlARERGRgKWuHxEREQlYCioiIiISsBRUREREJGApqIiIiEjAUlARERGRgKWgIiIiIgFLQUVEREQCloKKiIiIBCwFFREREQlY/w9Y2kDPvJL7IAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Saturation ratio calculation\n", + "organic_saturation_ratio = organic_species.get_saturation_ratio(temperature_range)\n", + "water_saturation_ratio = water_species.get_saturation_ratio(temperature_range)\n", + "\n", + "# Plotting the saturation ratio curves for the organic species.\n", + "fig, ax = plt.subplots()\n", + "for i in range(len(organic_names)):\n", + " ax.plot(temperature_range, organic_saturation_ratio[i], label=organic_names[i])\n", + "ax.plot(temperature_range, water_saturation_ratio, label=\"Water\")\n", + "ax.set_ylim(0, 5)\n", + "ax.set_xlabel(\"Temperature (K)\")\n", + "ax.set_ylabel(\"Saturation Ratio\")\n", + "ax.legend()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Summary\n", + "\n", + "The `GasSpecies` module, along with the `GasSpeciesBuilder`, provides a robust framework for defining and managing gas species within a mixture. By assigning specific vapor pressure strategies and other essential properties, we can accurately model the behavior of individual species and their interactions in various scenarios. This module serves as a foundational component for more advanced simulations and analyses involving gas mixtures, condensation, and phase equilibrium.\n", + "\n", + "The next section is one more layer of abstraction, where we will define the `GasMixture` class to manage multiple gas species within a single mixture. This class will enable us to handle complex gas mixtures effectively and efficiently, paving the way particle to gas interactions.\n", + "\n", + "# Help Calls\n", + "\n", + "Below are the help calls for the `GasSpecies` and `GasSpeciesBuilder` classes, which provide detailed information on their properties and methods for further exploration and understanding." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on class GasSpeciesBuilder in module particula.next.gas_species:\n", + "\n", + "class GasSpeciesBuilder(builtins.object)\n", + " | Builder class for GasSpecies objects, allowing for a more fluent and\n", + " | readable creation of GasSpecies instances with optional parameters.\n", + " | \n", + " | Methods:\n", + " | - name: Set the name of the gas species.\n", + " | - molar_mass: Set the molar mass of the gas species.\n", + " | - vapor_pressure_strategy: Set the vapor pressure strategy for the gas\n", + " | species.\n", + " | - condensable: Set the condensable property of the gas species.\n", + " | - build: Validate and return the GasSpecies object.\n", + " | \n", + " | Returns:\n", + " | - GasSpecies: The built GasSpecies object.\n", + " | \n", + " | Methods defined here:\n", + " | \n", + " | __init__(self)\n", + " | Initialize self. See help(type(self)) for accurate signature.\n", + " | \n", + " | build(self) -> particula.next.gas_species.GasSpecies\n", + " | Validate and return the GasSpecies object.\n", + " | \n", + " | concentration(self, concentration: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]])\n", + " | Set the concentration of the gas species in the mixture,\n", + " | in kg/m^3.\n", + " | \n", + " | condensable(self, condensable: Union[bool, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]])\n", + " | Set the condensable bool of the gas species.\n", + " | \n", + " | molar_mass(self, molar_mass: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]])\n", + " | Set the molar mass of the gas species. Units in kg/mol.\n", + " | \n", + " | name(self, name: Union[str, numpy.ndarray[Any, numpy.dtype[numpy.str_]]])\n", + " | Set the name of the gas species.\n", + " | \n", + " | vapor_pressure_strategy(self, strategy: Union[particula.next.gas_vapor_pressure.VaporPressureStrategy, list[particula.next.gas_vapor_pressure.VaporPressureStrategy]])\n", + " | Set the vapor pressure strategy for the gas species.\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors defined here:\n", + " | \n", + " | __dict__\n", + " | dictionary for instance variables\n", + " | \n", + " | __weakref__\n", + " | list of weak references to the object\n", + "\n" + ] + } + ], + "source": [ + "help(GasSpeciesBuilder)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on class GasSpecies in module particula.next.gas_species:\n", + "\n", + "class GasSpecies(builtins.object)\n", + " | GasSpecies represents an individual or array of gas species with\n", + " | properties like name, molar mass, vapor pressure, and condensability.\n", + " | \n", + " | Attributes:\n", + " | - name (str): The name of the gas species.\n", + " | - molar_mass (float): The molar mass of the gas species.\n", + " | - pure_vapor_pressure_strategy (VaporPressureStrategy): The strategy for\n", + " | calculating the pure vapor pressure of the gas species.\n", + " | - condensable (bool): Indicates whether the gas species is condensable.\n", + " | \n", + " | Methods defined here:\n", + " | \n", + " | __init__(self)\n", + " | Initialize self. See help(type(self)) for accurate signature.\n", + " | \n", + " | __str__(self)\n", + " | Return a string representation of the GasSpecies object.\n", + " | \n", + " | add_concentration(self, added_concentration: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]])\n", + " | Add concentration to the gas species.\n", + " | \n", + " | Args:\n", + " | - added_concentration (float): The concentration to add to the gas\n", + " | species.\n", + " | \n", + " | get_concentration(self) -> Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]\n", + " | Get the concentration of the gas species in the mixture, in kg/m^3.\n", + " | \n", + " | Returns:\n", + " | - concentration (float or NDArray[np.float_]): The concentration of the\n", + " | gas species in the mixture.\n", + " | \n", + " | get_condensable(self) -> Union[bool, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]]\n", + " | Check if the gas species is condensable or not.\n", + " | \n", + " | Returns:\n", + " | - condensable (bool): True if the gas species is condensable, False\n", + " | otherwise.\n", + " | \n", + " | get_molar_mass(self) -> Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]\n", + " | Get the molar mass of the gas species in kg/mol.\n", + " | \n", + " | Returns:\n", + " | - molar_mass (float or NDArray[np.float_]): The molar mass of the gas\n", + " | species, in kg/mol.\n", + " | \n", + " | get_partial_pressure(self, temperature: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]) -> Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]\n", + " | Calculate the partial pressure of the gas based on the vapor\n", + " | pressure strategy. This method accounts for multiple strategies if\n", + " | assigned and calculates partial pressure for each strategy based on\n", + " | the corresponding concentration and molar mass.\n", + " | \n", + " | Parameters:\n", + " | - temperature (float or NDArray[np.float_]): The temperature in\n", + " | Kelvin at which to calculate the partial pressure.\n", + " | \n", + " | Returns:\n", + " | - partial_pressure (float or NDArray[np.float_]): Partial pressure\n", + " | of the gas in Pascals.\n", + " | \n", + " | Raises:\n", + " | - ValueError: If the vapor pressure strategy is not set.\n", + " | \n", + " | get_pure_vapor_pressure(self, temperature: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]) -> Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]\n", + " | Calculate the pure vapor pressure of the gas species at a given\n", + " | temperature in Kelvin.\n", + " | \n", + " | This method supports both a single strategy or a list of strategies\n", + " | for calculating vapor pressure.\n", + " | \n", + " | Args:\n", + " | - temperature (float or NDArray[np.float_]): The temperature in\n", + " | Kelvin at which to calculate vapor pressure.\n", + " | \n", + " | Returns:\n", + " | - vapor_pressure (float or NDArray[np.float_]): The calculated pure\n", + " | vapor pressure in Pascals.\n", + " | \n", + " | Raises:\n", + " | ValueError: If no vapor pressure strategy is set.\n", + " | \n", + " | get_saturation_concentration(self, temperature: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]) -> Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]\n", + " | Calculate the saturation concentration of the gas based on the vapor\n", + " | pressure strategy. This method accounts for multiple strategies if\n", + " | assigned and calculates saturation concentration for each strategy\n", + " | based on the molar mass.\n", + " | \n", + " | Parameters:\n", + " | - temperature (float or NDArray[np.float_]): The temperature in\n", + " | Kelvin at which to calculate the partial pressure.\n", + " | \n", + " | Returns:\n", + " | - saturation_concentration (float or NDArray[np.float_]): The\n", + " | saturation concentration of the gas\n", + " | \n", + " | Raises:\n", + " | - ValueError: If the vapor pressure strategy is not set.\n", + " | \n", + " | get_saturation_ratio(self, temperature: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]) -> Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]]\n", + " | Calculate the saturation ratio of the gas based on the vapor\n", + " | pressure strategy. This method accounts for multiple strategies if\n", + " | assigned and calculates saturation ratio for each strategy based on\n", + " | the corresponding concentration and molar mass.\n", + " | \n", + " | Parameters:\n", + " | - temperature (float or NDArray[np.float_]): The temperature in\n", + " | Kelvin at which to calculate the partial pressure.\n", + " | \n", + " | Returns:\n", + " | - saturation_ratio (float or NDArray[np.float_]): The saturation ratio\n", + " | of the gas\n", + " | \n", + " | Raises:\n", + " | - ValueError: If the vapor pressure strategy is not set.\n", + " | \n", + " | set_concentration(self, concentration: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]])\n", + " | Set the concentration of the gas species in the mixture, in kg/m^3.\n", + " | \n", + " | Args:\n", + " | - concentration (float or NDArray[np.float_]): The concentration of the\n", + " | gas species in the mixture.\n", + " | \n", + " | set_condensable(self, condensable: Union[bool, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]])\n", + " | Set the condensable bool of the gas species.\n", + " | \n", + " | set_molar_mass(self, molar_mass: Union[float, numpy.ndarray[Any, numpy.dtype[numpy.float64]]])\n", + " | Set the molar mass of the gas species in kg/mol.\n", + " | \n", + " | Args:\n", + " | - molar_mass (float or NDArray[np.float_]): The molar mass of the gas\n", + " | species in kg/mol.\n", + " | \n", + " | set_name(self, name: Union[str, numpy.ndarray[Any, numpy.dtype[numpy.str_]]])\n", + " | Set the name of the gas species.\n", + " | \n", + " | Args:\n", + " | - name (str or NDArray[np.str_]): The name of the gas species.\n", + " | \n", + " | set_vapor_pressure_strategy(self, strategy: Union[particula.next.gas_vapor_pressure.VaporPressureStrategy, list[particula.next.gas_vapor_pressure.VaporPressureStrategy]])\n", + " | Set the vapor pressure strategies for the gas species.\n", + " | \n", + " | Args:\n", + " | - strategy (VaporPressureStrategy): The strategy for calculating the\n", + " | pure vapor pressure of the gas species. either a single strategy or\n", + " | a list of strategies.\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors defined here:\n", + " | \n", + " | __dict__\n", + " | dictionary for instance variables\n", + " | \n", + " | __weakref__\n", + " | list of weak references to the object\n", + "\n" + ] + } + ], + "source": [ + "help(GasSpecies)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ParticulaDev_py311", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/documentation/next/next_vapor_pressure.ipynb b/docs/documentation/next/next_vapor_pressure.ipynb index c06be8bc8..354a24f83 100644 --- a/docs/documentation/next/next_vapor_pressure.ipynb +++ b/docs/documentation/next/next_vapor_pressure.ipynb @@ -168,19 +168,27 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[ERROR|vapor_pressure_builders|L106]: Missing parameters: b, c\n" + ] + }, { "ename": "ValueError", - "evalue": "Missing coefficients: c", + "evalue": "Missing parameters: b, c", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[3], line 6\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# failed build due to missing parameters\u001b[39;00m\n\u001b[0;32m 2\u001b[0m styrene_fail \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m 3\u001b[0m \u001b[43mvapor_pressure_builders\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mAntoineBuilder\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 4\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_a\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstyrene_coefficients\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43ma\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 5\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_b\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstyrene_coefficients\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mb\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m----> 6\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbuild\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 7\u001b[0m )\n", - "File \u001b[1;32mC:\\GitHub\\particula\\particula\\next\\gas\\vapor_pressure_builders.py:91\u001b[0m, in \u001b[0;36mAntoineBuilder.build\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 89\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m [\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39ma, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mb, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mc]:\n\u001b[0;32m 90\u001b[0m missing \u001b[38;5;241m=\u001b[39m [p \u001b[38;5;28;01mfor\u001b[39;00m p \u001b[38;5;129;01min\u001b[39;00m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ma\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mc\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(\u001b[38;5;28mself\u001b[39m, p) \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m]\n\u001b[1;32m---> 91\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMissing coefficients: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(missing)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 92\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m AntoineVaporPressureStrategy(\n\u001b[0;32m 93\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39ma, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mb, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mc)\n", - "\u001b[1;31mValueError\u001b[0m: Missing coefficients: c" + "Cell \u001b[1;32mIn[5], line 5\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# failed build due to missing parameters\u001b[39;00m\n\u001b[0;32m 2\u001b[0m styrene_fail \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m 3\u001b[0m \u001b[43mvapor_pressure_builders\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mAntoineBuilder\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 4\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_a\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstyrene_coefficients\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43ma\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m----> 5\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbuild\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 6\u001b[0m )\n", + "File \u001b[1;32mC:\\GitHub\\particula\\particula\\next\\gas\\vapor_pressure_builders.py:198\u001b[0m, in \u001b[0;36mAntoineBuilder.build\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 193\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Build the AntoineVaporPressureStrategy object with the set\u001b[39;00m\n\u001b[0;32m 194\u001b[0m \u001b[38;5;124;03mcoefficients.\"\"\"\u001b[39;00m\n\u001b[0;32m 195\u001b[0m \u001b[38;5;66;03m# if None in [self.a, self.b, self.c]:\u001b[39;00m\n\u001b[0;32m 196\u001b[0m \u001b[38;5;66;03m# missing = [p for p in ['a', 'b', 'c'] if getattr(self, p) is None]\u001b[39;00m\n\u001b[0;32m 197\u001b[0m \u001b[38;5;66;03m# raise ValueError(f\"Missing coefficients: {', '.join(missing)}\")\u001b[39;00m\n\u001b[1;32m--> 198\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpre_build_check\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 199\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m AntoineVaporPressureStrategy(\n\u001b[0;32m 200\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39ma, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mb, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mc)\n", + "File \u001b[1;32mC:\\GitHub\\particula\\particula\\next\\gas\\vapor_pressure_builders.py:107\u001b[0m, in \u001b[0;36mBuilderBase.pre_build_check\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 105\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m missing:\n\u001b[0;32m 106\u001b[0m logger\u001b[38;5;241m.\u001b[39merror(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMissing parameters: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(missing))\n\u001b[1;32m--> 107\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMissing parameters: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(missing)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;31mValueError\u001b[0m: Missing parameters: b, c" ] } ], @@ -189,7 +197,6 @@ "styrene_fail = (\n", " vapor_pressure_builders.AntoineBuilder()\n", " .set_a(styrene_coefficients['a'])\n", - " .set_b(styrene_coefficients['b'])\n", " .build()\n", ")" ] diff --git a/particula/next/gas/tests/vapor_pressure_builders_test.py b/particula/next/gas/tests/vapor_pressure_builders_test.py index df27b4a61..6904033f0 100644 --- a/particula/next/gas/tests/vapor_pressure_builders_test.py +++ b/particula/next/gas/tests/vapor_pressure_builders_test.py @@ -25,7 +25,7 @@ def test_antoine_set_parameters_with_missing_key(): builder = AntoineBuilder() with pytest.raises(ValueError) as excinfo: builder.set_parameters({'a': 10, 'b': 2000}) - assert "Missing coefficient 'c'." in str(excinfo.value) + assert "Missing required parameter(s): c" in str(excinfo.value) def test_antoine_build_without_all_coefficients(): @@ -33,7 +33,7 @@ def test_antoine_build_without_all_coefficients(): builder = AntoineBuilder().set_a(10).set_b(2000) with pytest.raises(ValueError) as excinfo: builder.build() - assert "Missing coefficients: c" in str(excinfo.value) + assert "Required parameter(s) not set: c" in str(excinfo.value) def test_clausius_set_latent_heat_positive(): @@ -118,7 +118,8 @@ def test_clausius_build_failure(): builder.set_latent_heat(2260, 'J/kg').set_temperature_initial(373, 'K') with pytest.raises(ValueError) as excinfo: builder.build() - assert "Missing parameters: pressure_initial" in str(excinfo.value) + assert "Required parameter(s) not set: pressure_initial" in str( + excinfo.value) def test_constant_set_vapor_pressure_positive(): @@ -159,7 +160,8 @@ def test_constant_build_failure(): builder = ConstantBuilder() with pytest.raises(ValueError) as excinfo: builder.build() - assert "Missing parameter: vapor_pressure" in str(excinfo.value) + assert "Required parameter(s) not set: vapor_pressure" in str( + excinfo.value) def test_build_water_buck(): diff --git a/particula/next/gas/tests/vapor_pressure_factories_test.py b/particula/next/gas/tests/vapor_pressure_factories_test.py index a3006f55e..2c4a63ef1 100644 --- a/particula/next/gas/tests/vapor_pressure_factories_test.py +++ b/particula/next/gas/tests/vapor_pressure_factories_test.py @@ -72,4 +72,4 @@ def test_factory_with_incomplete_parameters(): with pytest.raises(ValueError) as excinfo: vapor_pressure_factory(strategy="antoine", parameters=parameters) # Assuming builders check and raise for missing params - assert "Missing coefficient 'c'." in str(excinfo.value) + assert "Missing required parameter(s): c" in str(excinfo.value) diff --git a/particula/next/gas/vapor_pressure_builders.py b/particula/next/gas/vapor_pressure_builders.py index 1a4463355..9b493604a 100644 --- a/particula/next/gas/vapor_pressure_builders.py +++ b/particula/next/gas/vapor_pressure_builders.py @@ -1,6 +1,7 @@ """Builders to create vapor pressure models for gas species.""" -from typing import Optional +from abc import ABC, abstractmethod +from typing import Optional, Any import logging from particula.next.gas.vapor_pressure_strategies import ( AntoineVaporPressureStrategy, @@ -13,7 +14,124 @@ logger = logging.getLogger("particula") -class AntoineBuilder(): +class BuilderBase(ABC): + """Abstract base class for builders with common methods to check keys and + set parameters from dict.""" + + def __init__( + self, + required_parameters: Optional[list[str]] = None + ): + self.required_parameters = required_parameters or [] + + def check_keys( + self, + parameters: dict[str, Any], + ): + """Check if the keys you want to set are present in the + self.required_parameters dictionary. + + Args: + ---- + - parameters (dict): The parameters dictionary to check. + - required_keys (list): List of required keys to be checked in the + parameters. + + Returns: + ------- + - None + + Raises: + ------ + - ValueError: If you are trying to set an invalid parameter. + """ + # check if all required keys are present + missing = [p for p in self.required_parameters if p not in parameters] + if missing: + logger.error( + "Missing required parameter(s): %s", ', '.join(missing)) + raise ValueError( + f"Missing required parameter(s): {', '.join(missing)}") + # check if all keys in parameters are valid, account for _units + valid_keys = set( + self.required_parameters + + [f"{key}_units" for key in self.required_parameters] + ) + key_to_set = [key for key in parameters + if key not in valid_keys] + if key_to_set: + logger.error( + "Trying to set an invalid parameter(s) '%s'. " + "The valid parameter(s) '%s'.", + key_to_set, valid_keys + ) + raise ValueError( + f"Trying to set an invalid parameter(s) '{key_to_set}'." + f" The valid parameter(s) '{valid_keys}'." + ) + + def set_parameters(self, parameters: dict[str, Any]): + """Set coefficients from a dictionary including optional units. + + Args: + ---- + - parameters (dict): The parameters dictionary to set. + + Returns: + ------- + - self: The builder object with the set parameters. + + Raises: + ------ + - ValueError: If any required key is missing. + - Warning: If using default units for any parameter. + """ + self.check_keys(parameters) # check if all required keys are present + for key in self.required_parameters: # set the parameters + unit_key = f'{key}_units' + if unit_key in parameters: + # build the set call set with units, from keys + # e.g. self.set_a(params['a'], params['a_units']) + getattr(self, f'set_{key}')( + parameters[key], parameters[unit_key] + ) + else: + logger.warning( + "Using default units for coefficient '%s'.", key) + # build set call, e.g. self.set_a(params['a']) + getattr(self, f'set_{key}')(parameters[key]) + return self + + def pre_build_check(self): + """Check if all required attribute parameters are set before building. + + Returns: + ------- + - None + + Raises: + ------ + - ValueError: If any required parameter is missing. + """ + missing = [p for p in self.required_parameters + if getattr(self, p) is None] + if missing: + logger.error( + "Required parameter(s) not set: %s", ', '.join(missing)) + raise ValueError( + f"Required parameter(s) not set: {', '.join(missing)}") + + @abstractmethod + def build(self) -> Any: + """Build and return the strategy object with the set parameters. + + Returns: + ------- + - strategy: The built strategy object. + """ + + +class AntoineBuilder(BuilderBase): """Builder class for AntoineVaporPressureStrategy. It allows setting the coefficients 'a', 'b', and 'c' separately and then building the strategy object. @@ -33,6 +151,9 @@ class AntoineBuilder(): """ def __init__(self): + required_parameters = ['a', 'b', 'c'] + # Call the base class's __init__ method + super().__init__(required_parameters) self.a = None self.b = None self.c = None @@ -63,37 +184,15 @@ def set_c(self, c: float, c_units: str = 'K'): self.c = c * convert_units(c_units, 'K') return self - def set_parameters(self, parameters: dict): # type: ignore - """Set coefficients from a dictionary including optional units.""" - required_keys = ['a', 'b', 'c'] - for key in required_keys: - if key not in parameters: - raise ValueError(f"Missing coefficient '{key}'.") - unit_key = f'{key}_units' - if unit_key in parameters: - # build the call set call - # e.g. self.set_a(params['a'], params['a_units']) - getattr(self, f'set_{key}')( - parameters[key], parameters[unit_key] - ) - else: - logger.warning( - "Using default units for coefficient '%s'.", key) - # call, e.g. self.set_a(params['a']) - getattr(self, f'set_{key}')(parameters[key]) - return self - def build(self): """Build the AntoineVaporPressureStrategy object with the set coefficients.""" - if None in [self.a, self.b, self.c]: - missing = [p for p in ['a', 'b', 'c'] if getattr(self, p) is None] - raise ValueError(f"Missing coefficients: {', '.join(missing)}") + self.pre_build_check() return AntoineVaporPressureStrategy( self.a, self.b, self.c) # type: ignore -class ClausiusClapeyronBuilder(): +class ClausiusClapeyronBuilder(BuilderBase): """Builder class for ClausiusClapeyronStrategy. This class facilitates setting the latent heat of vaporization, initial temperature, and initial pressure with unit handling and then builds the strategy object. @@ -117,6 +216,11 @@ class ClausiusClapeyronBuilder(): """ def __init__(self): + required_keys = [ + 'latent_heat', + 'temperature_initial', + 'pressure_initial'] + super().__init__(required_keys) self.latent_heat = None self.temperature_initial = None self.pressure_initial = None @@ -159,41 +263,42 @@ def set_pressure_initial( pressure_initial_units, 'Pa') return self - def set_parameters(self, parameters: dict): # type: ignore - """Set parameters from a dictionary including optional units.""" - required_keys = [ - 'latent_heat', - 'temperature_initial', - 'pressure_initial'] - for key in required_keys: - if key not in parameters: - raise ValueError(f"Missing coefficient '{key}'.") - unit_key = f'{key}_units' - if unit_key in parameters: - # units provided - getattr(self, f'set_{key}')( - parameters[key], parameters[unit_key] - ) - else: - # no units provided - logger.warning( - "Using default units for coefficient '%s'.", key) - getattr(self, f'set_{key}')(parameters[key]) - return self + # def set_parameters(self, parameters: dict): # type: ignore + # """Set parameters from a dictionary including optional units.""" + # required_keys = [ + # 'latent_heat', + # 'temperature_initial', + # 'pressure_initial'] + # for key in required_keys: + # if key not in parameters: + # raise ValueError(f"Missing coefficient '{key}'.") + # unit_key = f'{key}_units' + # if unit_key in parameters: + # # units provided + # getattr(self, f'set_{key}')( + # parameters[key], parameters[unit_key] + # ) + # else: + # # no units provided + # logger.warning( + # "Using default units for coefficient '%s'.", key) + # getattr(self, f'set_{key}')(parameters[key]) + # return self def build(self): """Build and return a ClausiusClapeyronStrategy object with the set parameters.""" - if None in [self.latent_heat, self.temperature_initial, - self.pressure_initial]: - missing = [ - p for p in [ - 'latent_heat', - 'temperature_initial', - 'pressure_initial'] if getattr( - self, - p) is None] - raise ValueError(f"Missing parameters: {', '.join(missing)}") + # if None in [self.latent_heat, self.temperature_initial, + # self.pressure_initial]: + # missing = [ + # p for p in [ + # 'latent_heat', + # 'temperature_initial', + # 'pressure_initial'] if getattr( + # self, + # p) is None] + # raise ValueError(f"Missing parameters: {', '.join(missing)}") + self.pre_build_check() return ClausiusClapeyronStrategy( self.latent_heat, # type: ignore self.temperature_initial, # type: ignore @@ -201,7 +306,7 @@ def build(self): ) -class ConstantBuilder(): +class ConstantBuilder(BuilderBase): """Builder class for ConstantVaporPressureStrategy. This class facilitates setting the constant vapor pressure and then building the strategy object. @@ -219,6 +324,8 @@ class ConstantBuilder(): """ def __init__(self): + required_keys = ['vapor_pressure'] + super().__init__(required_keys) self.vapor_pressure = None def set_vapor_pressure( @@ -233,34 +340,35 @@ def set_vapor_pressure( vapor_pressure_units, 'Pa') return self - def set_parameters(self, parameters: dict): # type: ignore - """Set parameters from a dictionary including optional units.""" - required_keys = ['vapor_pressure'] - for key in required_keys: - if key not in parameters: - raise ValueError(f"Missing coefficient '{key}'.") - unit_key = f'{key}_units' - if unit_key in parameters: - # units provided - getattr(self, f'set_{key}')( - parameters[key], parameters[unit_key] - ) - else: - # no units provided - logger.warning( - "Using default units for coefficient '%s'.", key) - getattr(self, f'set_{key}')(parameters[key]) - return self + # def set_parameters(self, parameters: dict): # type: ignore + # """Set parameters from a dictionary including optional units.""" + # required_keys = ['vapor_pressure'] + # for key in required_keys: + # if key not in parameters: + # raise ValueError(f"Missing coefficient '{key}'.") + # unit_key = f'{key}_units' + # if unit_key in parameters: + # # units provided + # getattr(self, f'set_{key}')( + # parameters[key], parameters[unit_key] + # ) + # else: + # # no units provided + # logger.warning( + # "Using default units for coefficient '%s'.", key) + # getattr(self, f'set_{key}')(parameters[key]) + # return self def build(self): """Build and return a ConstantVaporPressureStrategy object with the set parameters.""" - if self.vapor_pressure is None: - raise ValueError("Missing parameter: vapor_pressure") + # if self.vapor_pressure is None: + # raise ValueError("Missing parameter: vapor_pressure") + self.pre_build_check() return ConstantVaporPressureStrategy(self.vapor_pressure) -class WaterBuckBuilder(): # pylint: disable=too-few-public-methods +class WaterBuckBuilder(BuilderBase): # pylint: disable=too-few-public-methods """Builder class for WaterBuckStrategy. This class facilitates the building of the WaterBuckStrategy object. Which as of now has no additional parameters to set. But could be extended in the future for @@ -270,6 +378,10 @@ class WaterBuckBuilder(): # pylint: disable=too-few-public-methods -------- - build(): Build the WaterBuckStrategy object. """ + + def __init__(self): + super().__init__() + def build(self): """Build and return a WaterBuckStrategy object.""" return WaterBuckStrategy()