{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Working with parameters\n", "\n", "## Goal\n", "\n", "- Read in parameters for pure substances and mixtures from json files, and\n", "- create parameters for pure substances and mixtures within Python.\n", "- For both regular parameters as well as via the homo-segmented group contribution method.\n", "- Learn how to access information stored in parameter objects." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parameters and the equation of state\n", "\n", "Before we can start to compute physical properties, two steps are needed:\n", "\n", "1. Build a parameter object.\n", "2. Instatiate the equation of state using the parameter object.\n", "\n", "In principle, every implementation of an equation of state can manage parameters differently but typically the workflow is similar for each implementation.\n", "\n", "For `pcsaft` we first generate the parameters object, `PcSaftParameters`, which we then use to generate the equation of state object using `EquationOfState.pcsaft()`.\n", "The `PcSaftParameters` object is part of the `feos.pcsaft` module while `EquationOfState` is part of the `feos.eos` module." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from feos.pcsaft import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Read parameters from json file(s)\n", "\n", "The easiest way to create the `PcSaftParameters` object is to read information from one or more json files.\n", "\n", "- To read information from a single file, use `PcSaftParameters.from_json`\n", "- To read information from multiple files, use `PcSaftParameters.from_multiple_json`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From a single file\n", "\n", "#### Pure substance\n", "\n", "Querying a substance from a file requires an *identifier*.\n", "This identifier can be one of `Name`, `Cas`, `Inchi`, `IupacName`, `Formula`, or `Smiles` with `Name` (common english name) being the default.\n", "We can change the identifier type usig the `identifier_option` argument with an `IdentifierOption` object. Given a list of identifiers and a path to the parameter file, we can conveniently generate our object." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# path to parameter file for substances that are non-associating, i.e. defined by three parameters: m, sigma, and epsilon_k.\n", "file_na = '../parameters/pcsaft/gross2001.json' \n", "\n", "# a system containing a single substance, \"methane\", using \"Name\" as identifier (default)\n", "parameters = PcSaftParameters.from_json(['methane'], pure_path=file_na)\n", "parameters" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# a system containing a single substance, \"methane\", using \"Smiles\" (\"C\") as identifier\n", "parameters = PcSaftParameters.from_json(['C'], pure_path=file_na, identifier_option=IdentifierOption.Smiles)\n", "parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Mixtures\n", "\n", "Reading parameters for more than one substance from a single file is very straight forward: simply add more identifiers to the list.\n", "Note that the **order** in which which identifiers are provided **is important**. When computing vector valued properties, **the order of the physical properties matches the order of the substances within the parameter object**." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", "|hexane|86.177|3.0576|3.7983|236.77|0|0|0|0|0|0|0|\n", "|dodecane|170.338|5.306|3.8959|249.21|0|0|0|0|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# a system containing a ternary mixture\n", "parameters = PcSaftParameters.from_json(\n", " ['methane', 'hexane', 'dodecane'], \n", " pure_path=file_na\n", ")\n", "parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From multiple files\n", "\n", "There may be cases where we have to split our parameter information across different files. For example, the `feos` repository has parameters stored in different files where each file corresponds to the parameter's original publication. Constructing the parameter object using multiple different json files is a bit more complicated. We can provide a list tuples, each of which contains the list of substances and the file where parameters are stored.\n", "\n", "In the example below, we define a 4 component mixture from three input files:\n", "\n", "- methane is read from a file containing non-associating substance parameters.\n", "- parameters for 1-butanol and water are read from a file containing associating substances, and\n", "- acetone parameters are read from a file that contains substances modelled with dipolar interactions." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|\n", "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|0|\n", "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# na = non-associating\n", "# assoc = associating\n", "file_na = '../parameters/pcsaft/gross2001.json'\n", "file_assoc = '../parameters/pcsaft/gross2002.json'\n", "file_dipolar = '../parameters/pcsaft/gross2006.json'\n", "\n", "parameters = PcSaftParameters.from_multiple_json(\n", " [\n", " (['C'], file_na), \n", " (['CCCCO', 'O'], file_assoc), \n", " (['CC(C)=O'], file_dipolar)\n", " ], \n", " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### With binary interaction parameters\n", "\n", "Some mixtures cannot be adequately described with combination rules from pure substance parameters.\n", "In PC-SAFT, we can use a binary interaction parameter, `k_ij`, to enhance the description of mixture behavior.\n", "These interaction parameters can be supplied from a json file via the `binary_path` option.\n", "\n", "This parameter is not shown in the default representation of the parameter object. You can access the matrix of `k_ij` via the getter, `PcSaftParameters.k_ij`." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "file_na = '../parameters/pcsaft/gross2001.json'\n", "file_assoc = '../parameters/pcsaft/gross2002.json'\n", "file_binary = '../parameters/pcsaft/gross2002_binary.json'\n", "\n", "parameters = PcSaftParameters.from_multiple_json(\n", " [\n", " (['CCCC'], file_na), \n", " (['CCCCO',], file_assoc)\n", " ],\n", " binary_path=file_binary,\n", " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0. , 0.015],\n", " [0.015, 0. ]])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parameters.k_ij" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Building parameters in Python\n", "\n", "Building `PcSaftParameters` in Python is a bit more involved since the `PcSaftParameters` object is built from multiple intermediate objects.\n", "We need\n", "\n", "- the `Identifier` object that stores information about how a substance can be identified,\n", "- the `PcSaftRecord` object that stores our SAFT parameters,\n", "- and the `PureRecord` object that bundles identifier and parameters together with the molar weight.\n", "\n", "All these objects are imported from the `feos.pcsaft` module." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "from feos.pcsaft import Identifier, PcSaftRecord, PureRecord" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Identifier(cas=106-97-8, name=butane, iupac_name=butane, smiles=CCCC, inchi=InChI=1/C4H10/c1-3-4-2/h3-4H2,1-2H3, formula=C4H10)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "identifier = Identifier(\n", " cas='106-97-8',\n", " name='butane',\n", " iupac_name='butane',\n", " smiles='CCCC',\n", " inchi='InChI=1/C4H10/c1-3-4-2/h3-4H2,1-2H3',\n", " formula='C4H10'\n", ")\n", "identifier" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `PcSaftRecord` contains the model parameters for a pure substance. *Mandatory* parameters are\n", "\n", "- the number of segments, `m`, which is a dimensionless floating point number,\n", "- the Lennard-Jones structure parameter (diameter), `sigma`, in units of Angstrom, and\n", "- the Lennard-Jones energy parameter, `epsilon_k`, in units of Kelvin.\n", "\n", "*Optional* parameters are\n", "\n", "- the dipole moment, `mu`, in units of Debye used to model dipolar substances,\n", "- the quadrupole moment, `q`, in units of Debye used to model quadrupolar substances,\n", "- parameters to model association:\n", " - `kappa_ab`, `epsilon_k_ab`, `na`, `nb`\n", "- and parameters for entropy scaling:\n", " - `viscosity`, `diffusion`, and `thermal_conductivity`\n", " - each of which is a list containing coefficients for the respective correlation functions." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "PcSaftRecord(m=2.3316, sigma=3.7086, epsilon_k=222.88)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# parameters for a non-associating, non-polar substance (butane)\n", "psr = PcSaftRecord(m=2.3316, sigma=3.7086, epsilon_k=222.88)\n", "psr" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A `PureRecord` is built from an `Identifier`, the molar weight (in gram per mole) and a `PcSaftRecord`. Optionally, but not shown in this example, we can provide an `ideal_gas_record` depending on the ideal gas model used in the equation of state. We will not discuss this contribution here but address the topic in a different example." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "PureRecord(\n", "\tidentifier=Identifier(cas=106-97-8, name=butane, iupac_name=butane, smiles=CCCC, inchi=InChI=1/C4H10/c1-3-4-2/h3-4H2,1-2H3, formula=C4H10),\n", "\tmolarweight=58.123,\n", "\tmodel_record=PcSaftRecord(m=2.3316, sigma=3.7086, epsilon_k=222.88),\n", ")" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "butane = PureRecord(identifier, molarweight=58.123, model_record=psr)\n", "butane" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### `PcSaftParameters` for a single component \n", "\n", "For a single substance, we can use the `PcSaftParameters.new_pure` constructor." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parameters = PcSaftParameters.new_pure(butane)\n", "parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### `PcSaftParameters` for binary mixtures\n", "\n", "We can create another `PureRecord` for a second component. Then, the `PcSaftParameters.new_binary` constructor let's us build the parameters. Optionally, we can also directly provide a `k_ij` value for this system. Here, we build a record for an associating substance." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "butan_1_ol = PureRecord(\n", " identifier=Identifier(\n", " cas='71-36-3',\n", " name='1-butanol',\n", " iupac_name='butan-1-ol',\n", " smiles='CCCCO',\n", " inchi='InChI=1/C4H10O/c1-2-3-4-5/h5H,2-4H2,1H3',\n", " formula='C4H10O'\n", " ), \n", " molarweight=74.123, \n", " model_record=PcSaftRecord(\n", " m=2.7515, \n", " sigma=3.6139, \n", " epsilon_k=259.59, \n", " kappa_ab=0.006692, \n", " epsilon_k_ab=2544.6\n", " )\n", ")" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parameters = PcSaftParameters.new_binary([butane, butan_1_ol], binary_record=0.015)\n", "parameters" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0. , 0.015],\n", " [0.015, 0. ]])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parameters.k_ij" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### `PcSaftParameters` for mixtures with more than two components\n", "\n", "For mixtures with more than two components, we can use the `PcSaftParameters.from_records` constructor which takes a list of `PureRecords` and a `numpy.ndarray` containing the matrix of `k_ij` values." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "\n", "k_ij = np.zeros((2, 2))\n", "k_ij[0, 1] = k_ij[1, 0] = 0.015\n", "\n", "parameters = PcSaftParameters.from_records(\n", " [butane, butan_1_ol], \n", " binary_records=k_ij\n", ")\n", "parameters" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0. , 0.015],\n", " [0.015, 0. ]])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parameters.k_ij" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Parameters from homo-segmented group contribution (homo-GC)\n", "\n", "An alternative to substance specific parameters are parameters that combine information from functional groups (molecule *segments*).\n", "A simple variant that only uses the *number of segments* (*not* how these segments are connected to form the molecule) is the so-called homo-segmented group contribution method (homo-GC).\n", "\n", "As with regular SAFT parameters, we can build a `PcSaftParameters` object from json or from Python - using segment information." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From json files\n", "\n", "We need at least two files: \n", "\n", "- `pure_path`: a file containing the substance identifiers *and* the segments that form the molecule\n", "- `segments_path`: a file that contains the segments (identifier and model parameters)\n", "\n", "As before, we can specify our substance identifier using `identifier_option` and we can provide binary interaction parameters (segment-segment `k_ij`) via the `binary_path` argument." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|0|0|0|\n", "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|1|1|0|" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pure_path = '../parameters/pcsaft/gc_substances.json'\n", "segments_path = '../parameters/pcsaft/sauer2014_homo.json'\n", "\n", "parameters = PcSaftParameters.from_json_segments(\n", " ['CCCC', 'CCCCO'], \n", " pure_path, \n", " segments_path, \n", " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From Python\n", "\n", "Building parameters in Python follows a similar approach as for regular parameters. To build `PcSaftParameters` from segments, we need to specify:\n", "\n", "- The `ChemicalRecord` which contains the `Identifier` and the segments (as list of `str`s),\n", "- and the `SegmentRecord` which specifies the identifier of the segment (has to be the same as in the list of the `ChemicalRecord`), the molar weight and the `PcSaftRecord` for the segment.\n", "\n", "If both are available, we can use the `PcSaftParameters.from_segments` constructor to build the parameters." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "from feos.pcsaft import ChemicalRecord, SegmentRecord\n", "\n", "cr1 = ChemicalRecord(\n", " identifier=Identifier(\n", " cas='106-97-8',\n", " name='butane',\n", " iupac_name='butane',\n", " smiles='CCCC',\n", " inchi='InChI=1/C4H10/c1-3-4-2/h3-4H2,1-2H3',\n", " formula='C4H10'\n", "),\n", " segments=['CH3', 'CH2', 'CH2', 'CH3']\n", ")\n", "\n", "cr2 = ChemicalRecord(\n", " identifier=Identifier(\n", " cas='71-36-3',\n", " name='1-butanol',\n", " iupac_name='butan-1-ol',\n", " smiles='CCCCO',\n", " inchi='InChI=1/C4H10O/c1-2-3-4-5/h5H,2-4H2,1H3',\n", " formula='C4H10O'\n", " ),\n", " segments=['CH3', 'CH2', 'CH2', 'CH2', 'OH']\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each segment has a `PcSaftRecord` which can be constructed just like we did before for a substance." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "ch3 = SegmentRecord(\n", " 'CH3', \n", " molarweight=15.0345, \n", " model_record=PcSaftRecord(m=0.61198, sigma=3.7202, epsilon_k=229.90)\n", ")\n", "ch2 = SegmentRecord(\n", " 'CH2', \n", " molarweight=14.02658, \n", " model_record=PcSaftRecord(m=0.45606, sigma=3.8900, epsilon_k=239.01)\n", ")\n", "oh = SegmentRecord(\n", " 'OH', \n", " molarweight=17.00734, \n", " model_record=PcSaftRecord(\n", " m=0.40200, \n", " sigma=3.2859, \n", " epsilon_k=488.66,\n", " epsilon_k_ab=2517.0, \n", " kappa_ab=0.006825\n", " )\n", ")" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|0|0|0|\n", "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parameters = PcSaftParameters.from_segments(\n", " chemical_records=[cr1, cr2], \n", " segment_records=[ch3, ch2, oh]\n", ")\n", "parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Accessing information from parameter objects\n", "\n", "Once the `PcSaftParameter` object is constructed, within a jupyter notebook, we get a nice representation in form of a markdown table.\n", "Sometimes, however you might want to access information not presented in this table or you might want to store information in a variable.\n", "\n", "Let's build parameters for the four-component mixture we looked at earlier:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", "|-|-|-|-|-|-|-|-|-|-|-|-|\n", "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|\n", "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|0|\n", "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|0|0|0|" ], "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "file_na = '../parameters/pcsaft/gross2001.json'\n", "file_assoc = '../parameters/pcsaft/gross2002.json'\n", "file_dipolar = '../parameters/pcsaft/gross2006.json'\n", "\n", "parameters = PcSaftParameters.from_multiple_json(\n", " [\n", " (['C'], file_na), \n", " (['CCCCO', 'O'], file_assoc), \n", " (['CC(C)=O'], file_dipolar)\n", " ], \n", " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we've seen before, we can directly access the binary interaction parameter, `k_ij`, which is zero here for all binary interactions (we did not provide a file)." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "parameters.k_ij" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Get `PureRecord`s via `parameters.pure_records`\n", "\n", "We have seen above that it is possible to generate parameters in Python using intermediate objects, such as `Identifier`, `PcSaftRecord` and `PureRecord`.\n", "You can generate these objects for all substances via the `pure_records` method (getter).\n", "This getter returns `PureRecord` objects which can be further deconstructed to yield the `Identifier` and `PcSaftRecord` objects and the molar weight.\n", "\n", "Note that the order in which substances are returned matches the order in which we specified the substances above." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[PureRecord(\n", " \tidentifier=Identifier(cas=74-82-8, name=methane, iupac_name=methane, smiles=C, inchi=InChI=1/CH4/h1H4, formula=CH4),\n", " \tmolarweight=16.043,\n", " \tmodel_record=PcSaftRecord(m=1, sigma=3.7039, epsilon_k=150.03, association_record=AssociationRecord(kappa_ab=0, epsilon_k_ab=0)),\n", " ),\n", " PureRecord(\n", " \tidentifier=Identifier(cas=71-36-3, name=1-butanol, iupac_name=butan-1-ol, smiles=CCCCO, inchi=InChI=1/C4H10O/c1-2-3-4-5/h5H,2-4H2,1H3, formula=C4H10O),\n", " \tmolarweight=74.123,\n", " \tmodel_record=PcSaftRecord(m=2.7515, sigma=3.6139, epsilon_k=259.59, association_record=AssociationRecord(kappa_ab=0.006692, epsilon_k_ab=2544.6, na=1, nb=1)),\n", " ),\n", " PureRecord(\n", " \tidentifier=Identifier(cas=7732-18-5, name=water, iupac_name=oxidane, smiles=O, inchi=InChI=1/H2O/h1H2, formula=H2O),\n", " \tmolarweight=18.015,\n", " \tmodel_record=PcSaftRecord(m=1.0656, sigma=3.0007, epsilon_k=366.51, association_record=AssociationRecord(kappa_ab=0.034868, epsilon_k_ab=2500.7, na=1, nb=1)),\n", " ),\n", " PureRecord(\n", " \tidentifier=Identifier(cas=67-64-1, name=acetone, iupac_name=propan-2-one, smiles=CC(C)=O, inchi=InChI=1/C3H6O/c1-3(2)4/h1-2H3, formula=C3H6O),\n", " \tmolarweight=58.08,\n", " \tmodel_record=PcSaftRecord(m=2.7447, sigma=3.2742, epsilon_k=232.99, mu=2.88, association_record=AssociationRecord(kappa_ab=0, epsilon_k_ab=0)),\n", " )]" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parameters.pure_records" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "σ (methane)\t = 3.7039 A\n", "σ (1-butanol)\t = 3.6139 A\n", "σ (water)\t = 3.0007 A\n", "σ (acetone)\t = 3.2742 A\n" ] } ], "source": [ "for pure_record in parameters.pure_records:\n", " print(f\"σ ({pure_record.identifier.name})\\t = {pure_record.model_record.sigma} A\")" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Identifier(cas=74-82-8, name=methane, iupac_name=methane, smiles=C, inchi=InChI=1/CH4/h1H4, formula=CH4)" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# get identifier of substance 0\n", "parameters.pure_records[0].identifier" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "16.043" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# get molarweight of substance 0\n", "parameters.pure_records[0].molarweight" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A `PureRecord` object can be used to generate a json string which then can conveniently be stored in a file." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'{\"identifier\":{\"cas\":\"74-82-8\",\"name\":\"methane\",\"iupac_name\":\"methane\",\"smiles\":\"C\",\"inchi\":\"InChI=1/CH4/h1H4\",\"formula\":\"CH4\"},\"molarweight\":16.043,\"model_record\":{\"m\":1.0,\"sigma\":3.7039,\"epsilon_k\":150.03}}'" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# generate a json string from identifier of substance 0\n", "parameters.pure_records[0].to_json_str()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "\n", "In $\\text{FeO}_\\text{s}$, handling of parameters is not predefined within the underlying library. Each implementation of an equation of state has complete autonomy about the way parameters are handled.\n", "Howevery, we offer some convenient ways to automatize parameter handling which result in the methods presented in this example.\n", "\n", "We looked at different ways to get parameters for the `EquationOfState.pcsaft()` equation of state, i.e.\n", "\n", "- how to read parameters for substances from one or more files where we use the json format to store information, and\n", "- how to generate parameters the same parameters in Python.\n", "- In a similar fashion, we showed how parameters can be assembled using a homo-GC method.\n", "\n", "Once parameters are created, we can retrieve information by extracting the intermediate objects such as `PureRecord`, `Identifier` and `PcSaftRecord`.\n", "\n", "## Further reading\n", "\n", "- For more information about group contribution methods, see [this paper by Sauer et al.](https://pubs.acs.org/doi/abs/10.1021/ie502203w)\n", "- Files of published parameters can be found [in the `feos` github repositoy](https://github.com/feos-org/feos/tree/main/parameters/pcsaft).\n", "\n", "## Concluding remkars\n", "\n", "Hopefully you found this example helpful. If you have comments, critique or feedback, please let us know and consider [opening an issue on github](https://github.com/feos-org/feos/issues)." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "from feos.ideal_gas import JobackParameters" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" } }, "nbformat": 4, "nbformat_minor": 4 }