{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "5b6f419a-7574-447f-91dd-c3c0bdf5944c",
   "metadata": {},
   "source": [
    "# Units\n",
    "\n",
    "MobsPy supports units through the Python module Pint. We provide the user with a variable called u, which allows the user to express units using the dot operator. The user can write the units in this variable and operate with them. For instance, in the code example below, we assign concentrations as initial values for meta-species:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a32b733b-255e-4bde-88dd-051fab555a97",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ball Child Bacteria\n"
     ]
    }
   ],
   "source": [
    "from mobspy import *\n",
    "\n",
    "Ball, Child, Bacteria = BaseSpecies(3)\n",
    "\n",
    "Ball(10/u.meter**2)\n",
    "Child(1/u.meter**2)\n",
    "Bacteria(1*u.mol)\n",
    "print(Ball, Child, Bacteria)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e0177c7-d600-49dc-8a43-963631161537",
   "metadata": {},
   "source": [
    "When concentrations are assigned as initial values, MobsPy will convert concentrations into the total amount by multiplying with the volume for the simulation. \n",
    "\n",
    "Furthermore, one might perceive that the concentrations supplied are per area and not per volume. MobsPy can also model CRNs beyond the classical 3D, using models of chemical reactions based on areas (or others). However, the units must be consistent. If one assigns an area-based concentration to one and a volume-based concentration to another, MobsPy yields a compilation error.\n",
    "The same also holds if one assigns a volume to an area-based model. \n",
    "For instance, the line below yields an error because a volume was assigned to a 2D area based model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "c78aad99-67e0-40d7-9c7b-a17b9c29978a",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Compiling model\n",
      "\u001b[91mERROR: The dimensions are not consistent. There are at least two units given for different dimension models.\u001b[0m\n"
     ]
    },
    {
     "ename": "SystemExit",
     "evalue": "1",
     "output_type": "error",
     "traceback": [
      "An exception has occurred, use %tb to see the full traceback.\n",
      "\u001b[0;31mSystemExit\u001b[0m\u001b[0;31m:\u001b[0m 1\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/fabriciocravo/opt/anaconda3/lib/python3.8/site-packages/IPython/core/interactiveshell.py:3445: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n",
      "  warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n"
     ]
    }
   ],
   "source": [
    "S_error = Simulation(Ball | Child)\n",
    "S_error.volume = 3*u.m**3\n",
    "S_error.compile()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9c7197b-6214-43d6-acdb-bc3b846c03c5",
   "metadata": {},
   "source": [
    "One can also assign units to rates. \n",
    "The units for rates are either 1/([Time]x[Space]^(o-1)) or 1/([Time]), where o is the reaction order (the reaction order is equal to the number of reactants). Space represents units of volume for 3D models (for example, cubic meters m^3), but in the 2D example model here, it represents units of area. \n",
    "An example meta-reaction follows below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "518b829d-2094-43b6-88ae-3fc5d7048181",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<mobspy.modules.meta_class.Reactions at 0x7fb17f9de8b0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Bacteria >> Zero [1/u.second]\n",
    "\n",
    "Ball + Child + Child >> Ball + Child [1e-3*u.meter**4/u.hour]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8fdb3b97-a431-4024-883b-337fba43e9e0",
   "metadata": {},
   "source": [
    "MobsPy allows for both units of 1/([Time]x[Space]^(o-1)) and 1/([Time]) because it simulates using the total amount of each meta-species to give the user flexibility. MobsPy allows for both units of 1/([Time]x[Space]^(o-1)) and 1/([Time]) because it simulates using the total amount of each meta-species to give the user flexibility. If units of 1/([Time]x[Space]^(o-1)) are provided for the reaction rate constant, MobsPy will multiply by the necessary simulation volume. \n",
    "It can be seen in the compiled model below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1184ead7-cbda-46fb-a7f0-c61de07aae3a",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Compiling model\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Species\n",
      "Bacteria,6.02214076e+23\n",
      "Ball,20.0\n",
      "Child,2.0\n",
      "\n",
      "Mappings\n",
      "Bacteria :\n",
      "Bacteria\n",
      "Ball :\n",
      "Ball\n",
      "Child :\n",
      "Child\n",
      "\n",
      "Parameters\n",
      "volume,199.99999999999997\n",
      "\n",
      "Reactions\n",
      "reaction_0,{'re': [(1, 'Bacteria')], 'pr': [], 'kin': 'Bacteria * 1.0'}\n",
      "reaction_1,{'re': [(1, 'Ball'), (2, 'Child')], 'pr': [(1, 'Ball'), (1, 'Child')], 'kin': 'Ball * Child * Child * 0.0027777777777777775 * volume^-2'}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "S = Simulation(Ball | Child | Bacteria)\n",
    "S.volume = 2*u.meter**2\n",
    "print(S.compile())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f593e97-502d-465a-b831-409b1329b831",
   "metadata": {},
   "source": [
    "## MobsPy Standard Units\n",
    "\n",
    "MobsPy standard units are liters for volume, seconds for time, and counts for quantities (as opposed to molar). \n",
    "If a model has units used in it, all numbers without a unit will be assumed to be in MobsPy standard units. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa4d1885-ef5b-40ea-8009-253503fd4a6c",
   "metadata": {},
   "source": [
    "## Output Units\n",
    "\n",
    "With units considered, the MobsPy output is time in seconds, and per meta-species is in counts per liter. \n",
    "There are some exceptions to this, which we discuss in this section. \n",
    "The first exception lies when mols or molar are used as units for the initial amount of any meta-species. If that is the case, the output will be in molar units as well:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "aed05686-00aa-4e05-accb-63455752da3a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[100.0, 90.48374180506713, 81.87307532526243, 74.08182233223961, 67.03200465096499, 60.653065786238066, 54.881163390107275, 49.65853012209919, 44.93289613091965, 40.65696567170237, 36.78794383569595, 33.28710818070353, 30.11942105809889, 27.25317919579898, 24.659696303172485, 22.313015934987394, 20.189651733390615, 18.26835234974359, 16.529888791285984, 14.956861912310245, 13.533528332931242, 12.245642850901097, 11.080315869117978, 10.025884413901444, 9.071795380125312, 8.208499917460475, 7.427357878199143, 6.72055133423511, 6.0810063261727665, 5.502322067882962, 4.978706898441255, 4.504920301992112, 4.076220459402222, 3.688316798974152, 3.337327053468436, 3.0197383990017577, 2.7323722985327197, 2.472352698137563, 2.2370772351004344, 2.0241911921161884, 1.83156393339053, 1.6572675823809528, 1.4995577226483379, 1.356855939320586, 1.2277340258908906, 1.1108996875316481, 1.005183606472399, 0.9095277398881885, 0.8229747326701277, 0.7446583333676843, 0.6737947244815924, 0.6096746793035799, 0.5516564633588952, 0.49915941074216874, 0.45165811280502344, 0.4086771610254685, 0.36978638773066924, 0.3345965607539763, 0.30275548836500393, 0.27394449470700366, 0.2478752296747044, 0.22428678303882177, 0.2029430738479109, 0.18363048719869315, 0.16615573615875506, 0.15034392742260738, 0.13603681125166991, 0.12309119724094605, 0.11137752122617829, 0.100778548819108, 0.09118820202203023, 0.08251049740409132, 0.07465858549816241, 0.06755388180254407, 0.06112528007752468, 0.05530844067718353, 0.050045146699047194, 0.04528272137710319, 0.0409735007584374, 0.03707435667128173, 0.033546265196135426, 0.030353916026151288, 0.027465359045545687, 0.02485168458483361, 0.02248673413760786, 0.02034683848858013, 0.018410580824943307, 0.01665858243233495, 0.015073308735259213, 0.013638893778939988, 0.012340981442732978, 0.011166581795618594, 0.010103941054955832, 0.009142423948555864, 0.00827240728699761, 0.0074851836592279295, 0.0067728742666415195, 0.006128350070237975, 0.005545160459394637, 0.005017468679510152, 0.004539993411843377]\n"
     ]
    }
   ],
   "source": [
    "Bac = BaseSpecies()\n",
    "\n",
    "Bac(100*u.mol)\n",
    "\n",
    "Bac >> Zero [1/u.h]\n",
    "S = Simulation(Bac)\n",
    "S.level = 0\n",
    "S.plot_data = False\n",
    "S.duration = 10*u.h\n",
    "S.run()\n",
    "print(S.fres[Bac])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4416a9a0-d8d9-4103-887a-0f4619e5903a",
   "metadata": {},
   "source": [
    "The second exception lies when the user assigns a unit to the time duration of a simulation. In that case, MobsPy will output the time in the same unit as the one used for the duration. The model above also covers this exception."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "dc1a0c33-0de0-4861-9188-844efa5fb221",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0]\n"
     ]
    }
   ],
   "source": [
    "print(S.fres[\"Time\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7868906-0ec4-47a0-a3b3-5e6efc79aaf4",
   "metadata": {},
   "source": [
    "Finally, the user can also specify the units of the output using the simulation attribute unit_x for time and unit_y for concentration/counts. Furthermore, if the user wishes the output to be in concentration or not, it can use the output_concentration argument. An example on how to set them follows below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "946f8d14-a4a8-4bc0-ad4e-d08906f0a662",
   "metadata": {},
   "outputs": [],
   "source": [
    "S.unit_x = 1*u.year\n",
    "S.unit_y = 1*u.mol\n",
    "S.output_concentration = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e0ed7684-f1b7-4001-9823-c1c4d68d1f1e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
