{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Multi-fluid EOS\n", "\n", "Peering into the innards of teqp" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:06.606089Z", "iopub.status.busy": "2022-07-06T18:40:06.605465Z", "iopub.status.idle": "2022-07-06T18:40:07.147629Z", "shell.execute_reply": "2022-07-06T18:40:07.146669Z" } }, "outputs": [], "source": [ "import timeit, json\n", "import pandas\n", "import numpy as np\n", "import teqp\n", "teqp.__version__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ancillary Equations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ancillary equations are provided along with multiparameter equations of state. The give a good *approximation* to the phase equilibrium densities. There are routines in teqp to use the ancillary equations provided with the EOS. First a class containing the ancillary equations is obtained, then methods on that class are called" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model = teqp.build_multifluid_model([\"Methane\"], teqp.get_datapath())\n", "anc = model.build_ancillaries()\n", "T = 100.0 # [K]\n", "rhoL, rhoV = anc.rhoL(T), anc.rhoV(T)\n", "print('Densities are:', rhoL, rhoV, 'mol/m^3')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But those densities do not correspond to the *true* phase equilibrium solution, so we need to polish the solution:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Niter = 10\n", "rhoLtrue, rhoVtrue = model.pure_VLE_T(T, rhoL, rhoV, Niter)\n", "print('VLE densities are:', rhoLtrue, rhoVtrue, 'mol/m^3')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And looking the densities, they are slightly different after the phase equilibrium calculation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pure fluid loading" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:07.163785Z", "iopub.status.busy": "2022-07-06T18:40:07.163785Z", "iopub.status.idle": "2022-07-06T18:40:17.280030Z", "shell.execute_reply": "2022-07-06T18:40:17.278333Z" } }, "outputs": [], "source": [ "# By default teqp looks for fluids relative to the set of fluids in ROOT/dev/fluids\n", "# The name (case-sensitive) should match the .json file, without the json extension.\n", "%timeit model = teqp.build_multifluid_model([\"Methane\"], teqp.get_datapath())" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:17.286031Z", "iopub.status.busy": "2022-07-06T18:40:17.285350Z", "iopub.status.idle": "2022-07-06T18:40:27.300085Z", "shell.execute_reply": "2022-07-06T18:40:27.299050Z" } }, "outputs": [], "source": [ "# And if you provide valid aliases, alias lookup will be used to resolve the name\n", "# But beware, this is rather a lot slower than the above because all fluid files need to be read\n", "# in to build the alias map\n", "%timeit model = teqp.build_multifluid_model([\"n-C1H4\"], teqp.get_datapath())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, how to make it faster? Only do it once and cache" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:27.307115Z", "iopub.status.busy": "2022-07-06T18:40:27.307115Z", "iopub.status.idle": "2022-07-06T18:40:34.876155Z", "shell.execute_reply": "2022-07-06T18:40:34.875146Z" } }, "outputs": [], "source": [ "# Here is the set of possible aliases to absolute paths of files\n", "# Building this map takes a little while (somewhat faster in C++) due to all the file reads\n", "# If you know your files will not change, good idea to build this alias map yourself.\n", "%timeit aliasmap = teqp.build_alias_map(teqp.get_datapath())\n", "aliasmap = teqp.build_alias_map(teqp.get_datapath())\n", "list(aliasmap.keys())[0:10] # the first 10 aliases in the dict" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:34.879157Z", "iopub.status.busy": "2022-07-06T18:40:34.879157Z", "iopub.status.idle": "2022-07-06T18:40:42.930387Z", "shell.execute_reply": "2022-07-06T18:40:42.930079Z" } }, "outputs": [], "source": [ "# Then load the absolute paths from the alias map, \n", "# which will guarantee that you hit exactly what you were looking for,\n", "# resolving aliases as needed\n", "identifiers = [aliasmap[n] for n in [\"n-C1H4\"]]\n", "%timeit model = teqp.build_multifluid_model(identifiers, teqp.get_datapath())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At some point soon teqp will support in-memory loading of JSON data for the pure components, without requiring reads from the operating system" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:42.932720Z", "iopub.status.busy": "2022-07-06T18:40:42.932720Z", "iopub.status.idle": "2022-07-06T18:40:42.946939Z", "shell.execute_reply": "2022-07-06T18:40:42.945927Z" } }, "outputs": [], "source": [ "# And you can also load the JSON that teqp is loading for the pure fluids\n", "pureJSON = teqp.collect_component_json(['Neon','Hydrogen'], teqp.get_datapath())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mixture model loading" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:42.949975Z", "iopub.status.busy": "2022-07-06T18:40:42.948972Z", "iopub.status.idle": "2022-07-06T18:40:42.962308Z", "shell.execute_reply": "2022-07-06T18:40:42.961547Z" } }, "outputs": [], "source": [ "# Load the default JSON for the binary interaction parameters\n", "BIP = json.load(open(teqp.get_datapath()+'/dev/mixtures/mixture_binary_pairs.json'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:42.965595Z", "iopub.status.busy": "2022-07-06T18:40:42.964944Z", "iopub.status.idle": "2022-07-06T18:40:42.978409Z", "shell.execute_reply": "2022-07-06T18:40:42.977232Z" } }, "outputs": [], "source": [ "# You can obtain interaction parameters either by pairs of names, where name is the name that teqp uses, the [\"INFO\"][\"NAME\"] field\n", "params, swap_needed = teqp.get_BIPdep(BIP, ['Methane','Ethane'])\n", "params" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:42.981288Z", "iopub.status.busy": "2022-07-06T18:40:42.981288Z", "iopub.status.idle": "2022-07-06T18:40:42.993879Z", "shell.execute_reply": "2022-07-06T18:40:42.993281Z" } }, "outputs": [], "source": [ "# Or also by CAS#\n", "params, swap_needed = teqp.get_BIPdep(BIP, ['74-82-8','74-84-0'])\n", "params" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2022-07-06T18:40:42.996338Z", "iopub.status.busy": "2022-07-06T18:40:42.996338Z", "iopub.status.idle": "2022-07-06T18:40:43.423368Z", "shell.execute_reply": "2022-07-06T18:40:43.422895Z" }, "tags": [ "raises-exception" ] }, "outputs": [], "source": [ "# But mixing is not allowed\n", "params, swap_needed = teqp.get_BIPdep(BIP, ['74-82-8','Ethane'])\n", "params" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Estimation of interaction parameters\n", "\n", "Estimation of interaction parameters can be used when no mixture model is present. The ``flags`` keyword argument allows the user to control how estimation is applied. The ``flags`` keyword argument should be a dictionary, with keys of ``\"estimate\"`` to provide the desired estimation scheme as-needed. For now, the only allowed estimation scheme is ``Lorentz-Berthelot``. \n", "\n", "If it is desired to force the estimation, the ``\"force-estimate\"`` to force the use of the provided esimation scheme for all binaries, even when one is available. The value associated with ``\"force-estimate\"`` is ignored." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "params, swap_needed = teqp.get_BIPdep(BIP, ['74-82-8','74-84-0'], flags={'force-estimate':'yes', 'estimate': 'Lorentz-Berthelot'})\n", "params" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# And without the force, the forcing is ignored\n", "params, swap_needed = teqp.get_BIPdep(BIP, ['74-82-8','74-84-0'], flags={'estimate': 'Lorentz-Berthelot'})\n", "params" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# And the same flags can be passed to the multifluid model constructor\n", "model = teqp.build_multifluid_model(\n", " ['74-82-8','74-84-0'], \n", " teqp.get_datapath(), \n", " flags={'force-estimate':'yes', 'estimate': 'Lorentz-Berthelot'})" ] } ], "metadata": { "celltoolbar": "Edit 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.10.6" } }, "nbformat": 4, "nbformat_minor": 4 }