{
 "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
}