{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 6a. Michaelis-Menten enzyme kinetics\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " Loading BokehJS ...\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function now() {\n", " return new Date();\n", " }\n", "\n", " const force = true;\n", "\n", " if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n", " root._bokeh_onload_callbacks = [];\n", " root._bokeh_is_loading = undefined;\n", " }\n", "\n", "const JS_MIME_TYPE = 'application/javascript';\n", " const HTML_MIME_TYPE = 'text/html';\n", " const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n", " const CLASS_NAME = 'output_bokeh rendered_html';\n", "\n", " /**\n", " * Render data to the DOM node\n", " */\n", " function render(props, node) {\n", " const script = document.createElement(\"script\");\n", " node.appendChild(script);\n", " }\n", "\n", " /**\n", " * Handle when an output is cleared or removed\n", " */\n", " function handleClearOutput(event, handle) {\n", " const cell = handle.cell;\n", "\n", " const id = cell.output_area._bokeh_element_id;\n", " const server_id = cell.output_area._bokeh_server_id;\n", " // Clean up Bokeh references\n", " if (id != null && id in Bokeh.index) {\n", " Bokeh.index[id].model.document.clear();\n", " delete Bokeh.index[id];\n", " }\n", "\n", " if (server_id !== undefined) {\n", " // Clean up Bokeh references\n", " const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n", " cell.notebook.kernel.execute(cmd_clean, {\n", " iopub: {\n", " output: function(msg) {\n", " const id = msg.content.text.trim();\n", " if (id in Bokeh.index) {\n", " Bokeh.index[id].model.document.clear();\n", " delete Bokeh.index[id];\n", " }\n", " }\n", " }\n", " });\n", " // Destroy server and session\n", " const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n", " cell.notebook.kernel.execute(cmd_destroy);\n", " }\n", " }\n", "\n", " /**\n", " * Handle when a new output is added\n", " */\n", " function handleAddOutput(event, handle) {\n", " const output_area = handle.output_area;\n", " const output = handle.output;\n", "\n", " // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n", " if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n", " return\n", " }\n", "\n", " const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", "\n", " if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n", " toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n", " // store reference to embed id on output_area\n", " output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", " }\n", " if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", " const bk_div = document.createElement(\"div\");\n", " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", " const script_attrs = bk_div.children[0].attributes;\n", " for (let i = 0; i < script_attrs.length; i++) {\n", " toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n", " toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n", " }\n", " // store reference to server id on output_area\n", " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", " }\n", " }\n", "\n", " function register_renderer(events, OutputArea) {\n", "\n", " function append_mime(data, metadata, element) {\n", " // create a DOM node to render to\n", " const toinsert = this.create_output_subarea(\n", " metadata,\n", " CLASS_NAME,\n", " EXEC_MIME_TYPE\n", " );\n", " this.keyboard_manager.register_events(toinsert);\n", " // Render to node\n", " const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", " render(props, toinsert[toinsert.length - 1]);\n", " element.append(toinsert);\n", " return toinsert\n", " }\n", "\n", " /* Handle when an output is cleared or removed */\n", " events.on('clear_output.CodeCell', handleClearOutput);\n", " events.on('delete.Cell', handleClearOutput);\n", "\n", " /* Handle when a new output is added */\n", " events.on('output_added.OutputArea', handleAddOutput);\n", "\n", " /**\n", " * Register the mime type and append_mime function with output_area\n", " */\n", " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", " /* Is output safe? */\n", " safe: true,\n", " /* Index of renderer in `output_area.display_order` */\n", " index: 0\n", " });\n", " }\n", "\n", " // register the mime type if in Jupyter Notebook environment and previously unregistered\n", " if (root.Jupyter !== undefined) {\n", " const events = require('base/js/events');\n", " const OutputArea = require('notebook/js/outputarea').OutputArea;\n", "\n", " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", " register_renderer(events, OutputArea);\n", " }\n", " }\n", " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_failed_load = false;\n", " }\n", "\n", " const NB_LOAD_WARNING = {'data': {'text/html':\n", " \"
\\n\"+\n", " \"

\\n\"+\n", " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", " \"

\\n\"+\n", " \"\\n\"+\n", " \"\\n\"+\n", " \"from bokeh.resources import INLINE\\n\"+\n", " \"output_notebook(resources=INLINE)\\n\"+\n", " \"\\n\"+\n", " \"
\"}};\n", "\n", " function display_loaded() {\n", " const el = document.getElementById(\"p1001\");\n", " if (el != null) {\n", " el.textContent = \"BokehJS is loading...\";\n", " }\n", " if (root.Bokeh !== undefined) {\n", " if (el != null) {\n", " el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n", " }\n", " } else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(display_loaded, 100)\n", " }\n", " }\n", "\n", " function run_callbacks() {\n", " try {\n", " root._bokeh_onload_callbacks.forEach(function(callback) {\n", " if (callback != null)\n", " callback();\n", " });\n", " } finally {\n", " delete root._bokeh_onload_callbacks\n", " }\n", " console.debug(\"Bokeh: all callbacks have finished\");\n", " }\n", "\n", " function load_libs(css_urls, js_urls, callback) {\n", " if (css_urls == null) css_urls = [];\n", " if (js_urls == null) js_urls = [];\n", "\n", " root._bokeh_onload_callbacks.push(callback);\n", " if (root._bokeh_is_loading > 0) {\n", " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", " return null;\n", " }\n", " if (js_urls == null || js_urls.length === 0) {\n", " run_callbacks();\n", " return null;\n", " }\n", " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", " root._bokeh_is_loading = css_urls.length + js_urls.length;\n", "\n", " function on_load() {\n", " root._bokeh_is_loading--;\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", " run_callbacks()\n", " }\n", " }\n", "\n", " function on_error(url) {\n", " console.error(\"failed to load \" + url);\n", " }\n", "\n", " for (let i = 0; i < css_urls.length; i++) {\n", " const url = css_urls[i];\n", " const element = document.createElement(\"link\");\n", " element.onload = on_load;\n", " element.onerror = on_error.bind(null, url);\n", " element.rel = \"stylesheet\";\n", " element.type = \"text/css\";\n", " element.href = url;\n", " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", " document.body.appendChild(element);\n", " }\n", "\n", " for (let i = 0; i < js_urls.length; i++) {\n", " const url = js_urls[i];\n", " const element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error.bind(null, url);\n", " element.async = false;\n", " element.src = url;\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " };\n", "\n", " function inject_raw_css(css) {\n", " const element = document.createElement(\"style\");\n", " element.appendChild(document.createTextNode(css));\n", " document.body.appendChild(element);\n", " }\n", "\n", " const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.1.0.min.js\"];\n", " const css_urls = [];\n", "\n", " const inline_js = [ function(Bokeh) {\n", " Bokeh.set_log_level(\"info\");\n", " },\n", "function(Bokeh) {\n", " }\n", " ];\n", "\n", " function run_inline_js() {\n", " if (root.Bokeh !== undefined || force === true) {\n", " for (let i = 0; i < inline_js.length; i++) {\n", " inline_js[i].call(root, root.Bokeh);\n", " }\n", "if (force === true) {\n", " display_loaded();\n", " }} else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(run_inline_js, 100);\n", " } else if (!root._bokeh_failed_load) {\n", " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", " root._bokeh_failed_load = true;\n", " } else if (force !== true) {\n", " const cell = $(document.getElementById(\"p1001\")).parents('.cell').data().cell;\n", " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", " }\n", " }\n", "\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", " run_inline_js();\n", " } else {\n", " load_libs(css_urls, js_urls, function() {\n", " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", " run_inline_js();\n", " });\n", " }\n", "}(window));" ], "application/vnd.bokehjs_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n const NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded() {\n const el = document.getElementById(\"p1001\");\n if (el != null) {\n el.textContent = \"BokehJS is loading...\";\n }\n if (root.Bokeh !== undefined) {\n if (el != null) {\n el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(display_loaded, 100)\n }\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error(url) {\n console.error(\"failed to load \" + url);\n }\n\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.1.0.min.js\"];\n const css_urls = [];\n\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {\n }\n ];\n\n function run_inline_js() {\n if (root.Bokeh !== undefined || force === true) {\n for (let i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\nif (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n const cell = $(document.getElementById(\"p1001\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Colab setup ------------------\n", "import os, sys, subprocess\n", "if \"google.colab\" in sys.modules:\n", " cmd = \"pip install --upgrade colorcet biocircuits watermark\"\n", " process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n", " stdout, stderr = process.communicate()\n", "# ------------------------------\n", "\n", "import biocircuits\n", "\n", "import bokeh.io\n", "import colorcet\n", "\n", "bokeh.io.output_notebook()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "At the heart of a Michaelis-Menten description of enzyme kinetics is the following set of chemical reactions between the enzyme E and its substrate S to give product P.\n", "\n", "\\begin{align}\n", "\\require{mhchem}\n", "\\ce{E + S <=>[k_1][k_{-1}] ES ->[k_2] P + E}.\n", "\\end{align}\n", "\n", "The mechanism assumes that the enzyme reversibly binds the substrate with binding rate constant $k_1$ and unbinding rate constant $k_{-1}$. When bound, the enzyme can convert the substrate to product with rate constant $k_2$. Applying mass action kinetics, we can write the dynamics as a system of ordinary differential equations.\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{e}}{\\mathrm{d}t} &= -\\frac{\\mathrm{d}c_\\mathrm{es}}{\\mathrm{d}t} = -k_1c_\\mathrm{e} c_\\mathrm{s} + (k_{-1} + k_2)c_\\mathrm{es},\\\\[1em]\n", "\\frac{\\mathrm{d}c_\\mathrm{s}}{\\mathrm{d}t} &= -k_1c_\\mathrm{s} c_\\mathrm{e} + k_{-1}c_\\mathrm{es},\\\\[1em]\n", "\\frac{\\mathrm{d}c_p}{\\mathrm{d}t} &= k_2 c_\\mathrm{es},\n", "\\end{align}\n", "\n", "where $c_i$ denotes the concentration of species *i*. Note that\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{e}}{\\mathrm{d}t} + \\frac{\\mathrm{d}c_\\mathrm{es}}{\\mathrm{d}t} = 0,\n", "\\end{align}\n", "\n", "which is a statement of conservation of enzyme. This means that we need to specify a total enzyme amount to fully determine the problem. We define this to be $c_\\mathrm{e}^0$ such that $c_\\mathrm{e}^0 = c_\\mathrm{e} + c_\\mathrm{es}$. With this conservation law, we can write the ODEs as\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{es}}{\\mathrm{d}t} &= k_1(c_\\mathrm{e}^0-c_\\mathrm{es}) c_\\mathrm{s} - (k_{-1} + k_2)c_\\mathrm{es},\\\\[1em]\n", "\\frac{\\mathrm{d}c_\\mathrm{s}}{\\mathrm{d}t} &= -k_1(c_\\mathrm{e}^0-c_\\mathrm{es})c_\\mathrm{s} + k_{-1}c_\\mathrm{es},\\\\[1em]\n", "\\frac{\\mathrm{d}c_p}{\\mathrm{d}t} &= k_2 c_\\mathrm{es}.\n", "\\end{align}\n", "\n", "These equations describe the full dynamics of the enzyme catalyzed system. To simplify the analysis, we often make the **quasi-steady state approximation** that the bound substrate intermediate ES does not appreciably change in its concentration on the time scale of the production of the product P. That is,\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{es}}{\\mathrm{d}t} = k_1(c_\\mathrm{e}^0-c_\\mathrm{es}) c_\\mathrm{s} - (k_{-1} + k_2)c_\\mathrm{es} \\approx 0.\n", "\\end{align}\n", "\n", "This enables us to solve for the quasi-steady state fraction of enzyme that is bound to substrate.\n", "\n", "\\begin{align}\n", "\\frac{c_\\mathrm{es}}{c_\\mathrm{e}^0} \\approx \\frac{c_\\mathrm{s}/K_\\mathrm{M}}{1 + c_\\mathrm{s}/K_\\mathrm{M}},\n", "\\end{align}\n", "\n", "where we have defined the **Michaelis constant**\n", "\n", "\\begin{align}\n", "K_\\mathrm{M} = \\frac{k_{-1} + k_2}{k_1}.\n", "\\end{align}\n", "\n", "The Michaelis constant has dimension of concentration. It is analogous to a dissociation constant, in that it is the ratio of the total rate constants for leaving the bound state to the rate constant for enzyme-substrate binding. \n", "\n", "Substitution of this expression gives\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_p}{\\mathrm{d}t} \\approx k_2\\,c_\\mathrm{e}^0\\, \\frac{c_\\mathrm{s}/K_\\mathrm{M}}{1 + c_\\mathrm{s}/K_\\mathrm{M}}.\n", "\\end{align}\n", "\n", "By conservation of mass, if $\\mathrm{d}c_\\mathrm{es}/\\mathrm{d}t \\approx 0$, then \n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{s}}{\\mathrm{d}t} \\approx -\\frac{\\mathrm{d}c_p}{\\mathrm{d}t} \\approx -k_2 c_\\mathrm{e}^0\\, \\frac{c_\\mathrm{s}/K_\\mathrm{M}}{1 + c_\\mathrm{s}/K_\\mathrm{M}}.\n", "\\end{align}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Testing the accuracy of the quasi-steady state approximation\n", "\n", "To test the accuracy of the quasi-steady state approximation, it helps, as usual, to nondimensionalize the variables, as follows: \n", "\n", "\\begin{align}\n", "t &\\leftarrow \\frac{k_2c_\\mathrm{e}^0}{K_\\mathrm{M}}\\, t,\\\\[1em]\n", "c_\\mathrm{es} &\\leftarrow \\frac{c_\\mathrm{es}}{c_\\mathrm{e}^0},\\\\[1em]\n", "c_\\mathrm{s} &\\leftarrow \\frac{c_\\mathrm{s}}{K_\\mathrm{M}},\\\\[1em]\n", "c_p &\\leftarrow \\frac{c_p}{K_\\mathrm{M}}.\n", "\\end{align}\n", "\n", "The dimensionless dynamical equations are then\n", "\n", "\\begin{align}\n", "\\kappa\\,&\\frac{\\mathrm{d}\\tilde{c}_\\mathrm{s}}{\\mathrm{d}\\tilde{t}} = -(1 - \\tilde{c}_\\mathrm{es})\\tilde{c}_\\mathrm{s} + (1-\\kappa)\\tilde{c}_\\mathrm{es},\\\\[1em]\n", "\\kappa\\zeta\\,&\\frac{\\mathrm{d}\\tilde{c}_\\mathrm{es}}{\\mathrm{d}\\tilde{t}} = (1 - \\tilde{c}_\\mathrm{es})\\tilde{c}_\\mathrm{s} - \\tilde{c}_\\mathrm{es},\\\\[1em]\n", "&\\frac{\\mathrm{d}\\tilde{c}_\\mathrm{P}}{\\mathrm{d}\\tilde{t}} = \\tilde{c}_\\mathrm{es}.\n", "\\end{align}\n", "\n", "We have defined two dimensionless parameters. First, we have\n", "\n", "\\begin{align}\n", "\\kappa = \\frac{k_2}{k_{-1} + k_2}.\n", "\\end{align}\n", "\n", "This is the probability that a given enzyme-substrate complex will result in formation of a product molecule as opposed to dissociating. Note that $0 < \\kappa < 1$. Second, we have \n", "\n", "\\begin{align}\n", "\\zeta = \\frac{k_1 c_\\mathrm{e}^0}{k_{-1} + k_2} = \\frac{c_\\mathrm{e}^0}{K_\\mathrm{M}}. \n", "\\end{align}\n", "\n", "This is the ratio of the rate of transitions into the enzyme-substrate complex to\n", "the rate of transitions out of the complex.\n", "\n", "It is apparent in looking at the dimensionless equations that the quasi-steady state approximation is valid when $\\zeta \\kappa$ is small. Because $0 < \\kappa < 1$, it is sufficient to have $\\zeta \\ll 1$ for the quasi-steady state approximation to hold. Thus, the approximation holds when the amount of enzyme is small compared to the Michaelis constant. \n", "\n", "To investigate this, we can make plots and compare the solution to the full dynamical equations and those using the quasi-steady state approximation. In the plot below, we show the approximate dynamics of the substrate and the product as fainter colored lines and the exact solution as darker, thinner lines. All concentrations and times are dimensionless." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function embed_document(root) {\n", " const docs_json = {\"d52ccfd7-2fe2-497c-a43c-649b364768e3\":{\"version\":\"3.1.0\",\"title\":\"Bokeh Application\",\"defs\":[],\"roots\":[{\"type\":\"object\",\"name\":\"Column\",\"id\":\"p1120\",\"attributes\":{\"children\":[{\"type\":\"object\",\"name\":\"Row\",\"id\":\"p1118\",\"attributes\":{\"children\":[{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1115\",\"attributes\":{\"width\":40}},{\"type\":\"object\",\"name\":\"Slider\",\"id\":\"p1002\",\"attributes\":{\"js_property_callbacks\":{\"type\":\"map\",\"entries\":[[\"change:value\",[{\"type\":\"object\",\"name\":\"CustomJS\",\"id\":\"p1114\",\"attributes\":{\"args\":{\"type\":\"map\",\"entries\":[[\"cds\",{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1007\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1008\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1009\"},\"data\":{\"type\":\"map\",\"entries\":[[\"t\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[400],\"dtype\":\"float64\",\"order\":\"little\"}],[\"cs\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[400],\"dtype\":\"float64\",\"order\":\"little\"}],[\"ces\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[400],\"dtype\":\"float64\",\"order\":\"little\"}],[\"cp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[400],\"dtype\":\"float64\",\"order\":\"little\"}],[\"cs_approx\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[400],\"dtype\":\"float64\",\"order\":\"little\"}],[\"ces_approx\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[400],\"dtype\":\"float64\",\"order\":\"little\"}],[\"cp_approx\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[400],\"dtype\":\"float64\",\"order\":\"little\"}]]}}}],[\"kappaSlider\",{\"id\":\"p1002\"}],[\"zetaSlider\",{\"type\":\"object\",\"name\":\"Slider\",\"id\":\"p1004\",\"attributes\":{\"js_property_callbacks\":{\"type\":\"map\",\"entries\":[[\"change:value\",[{\"id\":\"p1114\"}]]]},\"width\":100,\"title\":\"\\u03b6\",\"format\":{\"type\":\"object\",\"name\":\"CustomJSTickFormatter\",\"id\":\"p1003\",\"attributes\":{\"code\":\"return Math.pow(10, tick).toFixed(2)\"}},\"start\":-2,\"end\":2,\"value\":-2,\"step\":0.05}}],[\"cs0Slider\",{\"type\":\"object\",\"name\":\"Slider\",\"id\":\"p1006\",\"attributes\":{\"js_property_callbacks\":{\"type\":\"map\",\"entries\":[[\"change:value\",[{\"id\":\"p1114\"}]]]},\"width\":100,\"title\":\"init. substr. conc.\",\"format\":{\"type\":\"object\",\"name\":\"CustomJSTickFormatter\",\"id\":\"p1005\",\"attributes\":{\"code\":\"return Math.pow(10, tick).toFixed(2)\"}},\"start\":-1,\"end\":1,\"value\":0.0,\"step\":0.01}}],[\"xRange\",{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1019\",\"attributes\":{\"js_property_callbacks\":{\"type\":\"map\",\"entries\":[[\"change:end\",[{\"id\":\"p1114\"}]]]},\"end\":10}}],[\"yRange\",{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1021\",\"attributes\":{\"start\":-0.02,\"end\":1.02}}]]},\"code\":\"\\nfunction michaelisMentenRHS(c, t, kappa, zeta){\\n let [cs, ces, cp] = c;\\n\\n return [\\n \\t(-(1.0 - ces) * cs + (1.0 - kappa) * ces) / kappa,\\n ((1.0 - ces) * cs - ces) / kappa / zeta,\\n ces\\n ];\\n}\\n\\n\\nfunction approxMichaelisMentenRHS(c, t, kappa, zeta) {\\n let cs = c[0];\\n return [-cs / (1.0 + cs)];\\n}\\n\\n\\nfunction callback() {\\n\\tlet xRangeMax = xRange.end;\\n\\tlet dt = 0.01;\\n\\tlet cs0 = Math.pow(10.0, cs0Slider.value);\\n\\tlet cp0 = 0.0; // No product to start\\n\\tlet ces0 = 0.0;\\n\\tlet c0 = [cs0, 0.0, 0.0];\\n\\tlet c0Approx = [cs0];\\n\\tlet kappa = kappaSlider.value;\\n\\tlet zeta = Math.pow(10.0, zetaSlider.value);\\n\\n\\tlet t = linspace(0.0, xRangeMax, cds.data['t'].length);\\n\\tlet args = [kappa, zeta];\\n\\n\\t// Integrate ODES\\n\\tlet cSolve = rkf45(michaelisMentenRHS, c0, t, args, dt);\\n\\tlet csApprox = rkf45(approxMichaelisMentenRHS, c0Approx, t, args)[0];\\n\\n\\t// Compute product and enzyme conc from substrate in approximate regime\\n let cesApprox = [];\\n let cpApprox = [];\\n for (let i = 0; i < csApprox.length; i++) {\\n \\tcesApprox[i] = csApprox[i] / (1.0 + csApprox[i]);\\n \\tcpApprox[i] = cs0 + cp0 - csApprox[i] + zeta * (ces0 - cesApprox[i]);\\n }\\n\\n\\t// Update data\\n\\tcds.data['t'] = t;\\n\\tcds.data['cs'] = cSolve[0];\\n\\tcds.data['ces'] = cSolve[1];\\n\\tcds.data['cp'] = cSolve[2];\\n\\tcds.data['cs_approx'] = csApprox;\\n\\tcds.data['ces_approx'] = cesApprox;\\n\\tcds.data['cp_approx'] = cpApprox;\\n\\n\\t// Update y-range\\n\\tyRange.start = -0.02 * cs0;\\n\\tyRange.end = 1.02 * cs0;\\n\\n\\tcds.change.emit();\\n\\tyRange.change.emit();\\n}\\n\\n\\nfunction ij(i, j, n) {\\n /*\\n * Lexicographic indexing of 2D array represented as 1D.\\n */\\n\\n return i * n + j;\\n}\\n\\n\\nfunction twoDto1D(A) {\\n /*\\n * Convert a 2D matrix to a 1D representation with row-based (C)\\n * lexicographic ordering.\\n */\\n\\n var m = A.length;\\n var n = A[0].length;\\n\\n var A1d = [];\\n for (var i = 0; i < m; i++) {\\n for (var j = 0; j < n; j++) {\\n A1d.push(A[i][j]);\\n }\\n }\\n\\n return A1d;\\n}\\n\\n\\nfunction linspace(start, stop, n) {\\n var x = [];\\n var currValue = start;\\n var step = (stop - start) / (n - 1);\\n for (var i = 0; i < n; i++) {\\n x.push(currValue);\\n currValue += step;\\n }\\n return x;\\n}\\n\\n\\nfunction zeros(n) {\\n var x = [];\\n for (var i = 0; i < n; i++) x.push(0.0);\\n return x;\\n}\\n\\n\\nfunction shallowCopyMatrix(A) {\\n /*\\n * Make a shallow copy of a matrix.\\n */\\n\\n var Ac = [];\\n var n = A.length;\\n for (i = 0; i < n; i++) {\\n Ac.push([...A[i]]);\\n }\\n\\n return Ac;\\n}\\n\\n\\nfunction nanArray() {\\n /*\\n * Return a NaN array of shape given by arguments.\\n */\\n if (arguments.length == 1) {\\n var x = [];\\n for (var i = 0; i < arguments[0]; i++) x.push(NaN);\\n }\\n else if (arguments.length == 2) {\\n var x = [];\\n for (var i = 0; i < arguments[0]; i++) {\\n var xRow = [];\\n for (var j = 0; j < arguments[1]; j++) xRow.push(NaN);\\n x.push(xRow);\\n }\\n }\\n else {\\n throw 'Must only have one or two arguments to nanArray().'\\n }\\n\\n return x;\\n}\\n\\nfunction transpose(A) {\\n var m = A.length;\\n var n = A[0].length;\\n var AT = [];\\n\\n for (var j = 0; j < n; j++) {\\n var ATj = [];\\n for (var i = 0; i < m; i++) {\\n ATj.push(A[i][j]);\\n }\\n AT.push(ATj);\\n }\\n\\n return AT;\\n}\\n\\n\\nfunction dot(v1, v2) {\\n /*\\n * Compute dot product v1 . v2.\\n */\\n\\n var n = v1.length;\\n var result = 0.0;\\n for (var i = 0; i < n; i++) result += v1[i] * v2[i];\\n\\n return result;\\n}\\n\\n\\nfunction norm(v) {\\n /*\\n * 2-norm of a vector\\n */\\n\\n return Math.sqrt(dot(v, v));\\n}\\n\\n\\nfunction mvMult(A, v, diagonalA) {\\n /*\\n * Compute dot product A . v, where A is a matrix.\\n * If diagonalA is true, then A must be a 1-D array.\\n */\\n\\n if (diagonalA) return elementwiseVectorMult(A, v);\\n else {\\n return A.map(function (Arow) {\\n return dot(Arow, v);\\n });\\n }\\n}\\n\\n\\nfunction svMult(a, v) {\\n /*\\n * Multiply vector v by scalar a.\\n */\\n\\n return v.map(function (x) {\\n return a * x;\\n });\\n}\\n\\n\\nfunction smMult(a, A) {\\n /*\\n * Multiply matrix A by scalar a.\\n */\\n\\n return A.map(function (Arow) {\\n return svMult(a, Arow);\\n });\\n}\\n\\n\\nfunction svAdd(a, v) {\\n /*\\n * Add a scalar a to every element of vector v.\\n */\\n\\n return v.map(function (x) {\\n return a + x;\\n });\\n}\\n\\n\\nfunction vectorAdd() {\\n var m = arguments[0].length;\\n var n = arguments.length;\\n\\n var result = [];\\n for (var i = 0; i < m; i++) {\\n var element = 0.0;\\n for (var j = 0; j < n; j++) {\\n element += arguments[j][i];\\n }\\n result.push(element);\\n }\\n\\n return result;\\n}\\n\\n\\nfunction elementwiseVectorDivide(v1, v2) {\\n /*\\n * Compute v1 / v2 elementwise.\\n */\\n\\n var result = [];\\n n = v1.length;\\n\\n for (var i = 0; i < n; i++) {\\n result.push(v1[i] / v2[i]);\\n }\\n\\n return result;\\n}\\n\\n\\nfunction elementwiseVectorMult(v1, v2) {\\n /*\\n * Compute v1 * v2 elementwise.\\n */\\n\\n var result = [];\\n n = v1.length;\\n\\n for (var i = 0; i < n; i++) {\\n result.push(v1[i] * v2[i]);\\n }\\n\\n return result;\\n}\\n\\n\\nfunction svMultAdd(scalars, vectors) {\\n /*\\n * Add a set of vectors together, each multiplied by a scalar.\\n */\\n\\n var m = vectors[0].length;\\n var n = scalars.length;\\n\\n if (vectors.length != n) {\\n console.warn(\\\"svMultAdd: Difference number of scalars and vectors.\\\");\\n return null;\\n }\\n\\n var result = [];\\n for (var i = 0; i < m; i++) {\\n var element = 0.0;\\n for (var j = 0; j < n; j++) {\\n element += scalars[j] * vectors[j][i];\\n }\\n result.push(element);\\n }\\n\\n return result;\\n}\\n\\n\\nfunction absVector(v) {\\n var result = [];\\n for (var i = 0; i < v.length; i++) {\\n result[i] = Math.abs(v[i]);\\n }\\n\\n return result;\\n}\\n\\n\\nfunction LUPDecompose(A, eps) {\\n /*\\n * LUP decomposition.\\n */\\n\\n var i, j, k, imax;\\n var maxA, absA;\\n var Arow;\\n var p = [];\\n var n = A.length;\\n var LU = shallowCopyMatrix(A);\\n\\n // Permutation matrix\\n for (i = 0; i <= n; i++) p.push(i);\\n\\n for (i = 0; i < n; i++) {\\n maxA = 0.0;\\n imax = i;\\n\\n for (k = i; k < n; k++) {\\n absA = Math.abs(LU[k][i]);\\n if (absA > maxA) {\\n maxA = absA;\\n imax = k;\\n }\\n }\\n\\n // Failure; singular matrix\\n if (maxA < eps) return [null, null];\\n\\n if (imax != i) {\\n // Pivot\\n j = p[i];\\n p[i] = p[imax];\\n p[imax] = j;\\n\\n // Pivot rows of A\\n Arow = LU[i];\\n LU[i] = LU[imax];\\n LU[imax] = Arow;\\n\\n // Count pivots\\n p[n]++;\\n }\\n\\n for (j = i + 1; j < n; j++) {\\n LU[j][i] /= LU[i][i];\\n\\n for (k = i + 1; k < n; k++) LU[j][k] -= LU[j][i] * LU[i][k];\\n }\\n }\\n\\n return [LU, p];\\n}\\n\\nfunction LUPSolve(LU, p, b) {\\n /*\\n * Solve a linear system where LU and p are stored as the\\n * output of LUPDecompose().\\n */\\n\\n var n = b.length;\\n var x = [];\\n\\n for (var i = 0; i < n; i++) {\\n x.push(b[p[i]]);\\n for (var k = 0; k < i; k++) x[i] -= LU[i][k] * x[k];\\n }\\n\\n for (i = n - 1; i >= 0; i--) {\\n for (k = i + 1; k < n; k++) x[i] -= LU[i][k] * x[k];\\n\\n x[i] /= LU[i][i];\\n }\\n\\n return x;\\n}\\n\\nfunction solve(A, b) {\\n /*\\n * Solve a linear system using LUP decomposition.\\n *\\n * Returns null if singular.\\n */\\n\\n var eps = 1.0e-14;\\n var LU, p;\\n\\n [LU, p] = LUPDecompose(A, eps);\\n\\n // Return null if singular\\n if (LU === null) return null;\\n\\n return LUPSolve(LU, p, b);\\n}\\n\\n\\nfunction rkf45(\\n f,\\n initialCondition,\\n timePoints,\\n args,\\n dt,\\n tol,\\n relStepTol,\\n maxDeadSteps,\\n sBounds,\\n hMin,\\n enforceNonnegative,\\n debugMode,\\n) {\\n // Set up return variables\\n let tSol = [timePoints[0]];\\n let t = timePoints[0];\\n let iMax = timePoints.length;\\n let y = [initialCondition];\\n let y0 = initialCondition;\\n let i = 1;\\n let nDeadSteps = 0;\\n let deadStep = false;\\n\\n // DEBUG\\n let nSteps = 0;\\n // END EDEBUG\\n\\n // Default parameters\\n let h;\\n if (dt === undefined) h = timePoints[1] - timePoints[0];\\n else h = dt;\\n\\n if (tol === undefined) tol = 1e-7;\\n if (relStepTol === undefined) relStepTol = 0.0;\\n if (sBounds === undefined) sBounds = [0.1, 10.0];\\n if (hMin === undefined) hMin = 0.0;\\n if (enforceNonnegative === undefined) enforceNonnegative = true;\\n if (maxDeadSteps === undefined) maxDeadSteps = 10;\\n if (debugMode === undefined) debugMode = false;\\n\\n while (i < iMax && nDeadSteps < maxDeadSteps) {\\n nDeadSteps = 0;\\n while (t < timePoints[i] && nDeadSteps < maxDeadSteps) {\\n [y0, t, h, deadStep] = rkf45Step(\\n f,\\n y0,\\n t,\\n args,\\n h,\\n tol,\\n relStepTol,\\n sBounds,\\n hMin\\n );\\n nDeadSteps = deadStep ? nDeadSteps + 1 : 0;\\n if (enforceNonnegative) {\\n y0 = y0.map(function (x) {\\n if (x < 0.0) return 0.0;\\n else return x;\\n });\\n }\\n // DEBUG\\n nSteps += 1;\\n // END DEBUG\\n }\\n if (t > tSol[tSol.length - 1]) {\\n y.push(y0);\\n tSol.push(t);\\n }\\n i += 1;\\n }\\n\\n // DEBUG\\n if (debugMode) console.log(nSteps);\\n // END DEBUG\\n\\n let yInterp;\\n if (nDeadSteps == maxDeadSteps) {\\n \\tyInterp = nanArray(initialCondition.length, iMax);\\n }\\n else yInterp = interpolateSolution(timePoints, tSol, transpose(y));\\n\\n return yInterp;\\n}\\n\\n\\nfunction rkf45Step(f, y, t, args, h, tol, relStepTol, sBounds, hMin) {\\n let k1 = svMult(h, f(y, t, ...args));\\n\\n let y2 = svMultAdd([0.25, 1.0], [k1, y]);\\n let k2 = svMult(h, f(y2, t + 0.25 * h, ...args));\\n\\n let y3 = svMultAdd([0.09375, 0.28125, 1.0], [k1, k2, y]);\\n let k3 = svMult(h, f(y3, t + 0.375 * h, ...args));\\n\\n let y4 = svMultAdd(\\n [1932.0 / 2197.0, -7200.0 / 2197.0, 7296.0 / 2197.0, 1.0],\\n [k1, k2, k3, y]\\n );\\n let k4 = svMult(h, f(y4, t + (12.0 * h) / 13.0, ...args));\\n\\n let y5 = svMultAdd(\\n [\\n 8341.0 / 4104.0,\\n -32832.0 / 4104.0,\\n 29440.0 / 4104.0,\\n -845.0 / 4104.0,\\n 1.0,\\n ],\\n [k1, k2, k3, k4, y]\\n );\\n let k5 = svMult(h, f(y5, t + h, ...args));\\n\\n let y6 = svMultAdd(\\n [\\n -6080.0 / 20520.0,\\n 41040.0 / 20520.0,\\n -28352.0 / 20520.0,\\n 9295.0 / 20520.0,\\n -5643.0 / 20520.0,\\n 1.0,\\n ],\\n [k1, k2, k3, k4, k5, y]\\n );\\n let k6 = svMult(h, f(y6, t + h / 2.0, ...args));\\n\\n // Calculate new step\\n let yNew = svMultAdd(\\n [\\n 2375.0 / 20520.0,\\n 11264.0 / 20520.0,\\n 10985.0 / 20520.0,\\n -4104.0 / 20520.0,\\n 1.0,\\n ],\\n [k1, k3, k4, k5, y]\\n );\\n\\n // Relative difference between steps\\n\\tlet relChangeStep = norm(vectorAdd(yNew, svMult(-1.0, y))) / norm(yNew);\\n\\n // Calculate error (note that k2's contribution to the error is zero)\\n let errorVector = svMultAdd(\\n [\\n 209.0 / 75240.0,\\n -2252.8 / 75240.0,\\n -2197.0 / 75240.0,\\n 1504.8 / 75240.0,\\n 2736.0 / 75240.0,\\n ],\\n [k1, k3, k4, k5, k6]\\n );\\n let error = Math.max(...absVector(errorVector));\\n\\n // Either don't take a step or use the RK4 step\\n let deadStep;\\n if (error < tol || relChangeStep < relStepTol || h <= hMin) {\\n t += h;\\n deadStep = false;\\n } else {\\n yNew = y;\\n deadStep = true;\\n }\\n\\n // Compute scaling for new step size\\n let s;\\n if (error === 0.0) {\\n s = sBounds[1];\\n } else {\\n s = Math.pow((tol * h) / 2.0 / error, 0.25);\\n }\\n if (s < sBounds[0]) {\\n s = sBounds[0];\\n } else if (s > sBounds[1]) {\\n s = sBounds[1];\\n }\\n\\n // Return new y-values, new time, and updated step size h\\n return [yNew, t, Math.max(s * h, hMin), deadStep];\\n}\\n\\n\\nfunction dydtIMEX(y, t, f, cfun, Afun, fArgs, cfunArgs, AfunArgs, diagonalA) {\\n /*\\n * Right hand side of ODEs for initializing IMEX method with RKF.\\n */\\n\\n n = y.length;\\n let rhs = zeros(n);\\n\\n let A = Afun(t, ...AfunArgs);\\n let c = cfun(t, ...cfunArgs);\\n\\n // Linear part\\n let nonConstantLinear = diagonalA\\n ? elementwiseVectorMult(A, y)\\n : mvMult(A, y, diagonalA);\\n let linearPart = vectorAdd(nonConstantLinear, c);\\n\\n // Nonlinear part\\n let nonlinearPart = f(y, t, ...fArgs);\\n\\n return vectorAdd(nonlinearPart, linearPart);\\n}\\n\\n\\nfunction cnab2Step(u, c, A, f1, f0, g1, omega, k, diagonalA) {\\n /*\\n * Take a CNAB2 step.\\n *\\n * - u is the current value of the solution.\\n * - c is the constant term.\\n * - A is the matrix for the linear function.\\n * - f1 is the nonlinear function evaluated at the current value of y.\\n * - f0 is the nonlinear function evaluated at the previous value of y.\\n * - g1 is the linear function evaluated at the current value of y.\\n * - omega is the ratio of the most recent step size to the one before that.\\n * - k is the current step size.\\n * - diagonalA is true if A is diagonal. This leads to a *much* faster time step.\\n * If diagonalA is true, then A is provided only as the diagonal.\\n */\\n\\n let invk = 1.0 / k;\\n let b = vectorAdd(\\n svMult(0.5, c),\\n svMult(invk, u),\\n svMult(1.0 + omega / 2.0, f1),\\n svMult(-omega / 2.0, f0),\\n svMult(0.5, g1)\\n );\\n\\n if (diagonalA) {\\n let Aaug = svAdd(invk, svMult(-0.5, A));\\n let result = elementwiseVectorDivide(b, Aaug);\\n } else {\\n let n = A.length;\\n let Aaug = smMult(-0.5, A);\\n for (i = 0; i < n; i++) {\\n Aaug[i][i] += invk;\\n }\\n let result = solve(Aaug, b);\\n }\\n\\n return result;\\n}\\n\\n\\nfunction vsimexAdjustStepSizePID(\\n k,\\n relChange,\\n relChangeStep,\\n tol,\\n kP,\\n kI,\\n kD,\\n kBounds,\\n sBounds\\n) {\\n /*\\n * Adjust step size using a PID controller.\\n */\\n let mult =\\n Math.pow(relChange[1] / relChangeStep, kP) *\\n Math.pow(tol / relChangeStep, kI) *\\n Math.pow(Math.pow(relChange[0], 2) / relChange[1] / relChangeStep, kD);\\n if (mult > sBounds[1]) mult = sBounds[1];\\n else if (mult < sBounds[0]) mult = sBounds[0];\\n\\n let newk = mult * k;\\n\\n if (newk > kBounds[1]) newk = kBounds[1];\\n else if (newk < kBounds[0]) newk = kBounds[0];\\n\\n return newk;\\n}\\n\\n\\nfunction vsimexAdjustStepSizeRejectedStep(\\n k,\\n relChangeStep,\\n tol,\\n kBounds,\\n sBounds\\n) {\\n /*\\n * Adjust step for rejected step\\n */\\n\\n let mult = tol / relChangeStep;\\n if (mult < sBounds[0]) mult = sBounds[0];\\n\\n let newk = mult * k;\\n if (newk < kBounds[0]) newk = kBounds[0];\\n\\n return newk;\\n}\\n\\n\\nfunction vsimexAdjustStepSizeFailedSolve(k, failedSolveS) {\\n /*\\n * Adjust step for failed solve. Bringing step size down will\\n * eventually make matrix for linear solve positive definite.\\n */\\n\\n return k * failedSolveS;\\n}\\n\\n\\nfunction vsimex(\\n f,\\n cfun,\\n Afun,\\n initialCondition,\\n timePoints,\\n fArgs,\\n cfunArgs,\\n AfunArgs,\\n diagonalA,\\n k0,\\n kBounds,\\n tol,\\n tolBuffer,\\n kP,\\n kI,\\n kD,\\n sBounds,\\n failedSolveS,\\n enforceNonnegative,\\n maxDeadSteps\\n) {\\n /*\\n *\\n */\\n\\n // Defaults\\n if (k0 === undefined) k0 = 1.0e-5;\\n if (kBounds === undefined) kBounds = [1.0e-6, 100.0];\\n if (tol === undefined) tol = 0.001;\\n if (tolBuffer === undefined) tolBuffer = 0.01;\\n if (kP === undefined) kP = 0.075;\\n if (kI === undefined) kI = 0.175;\\n if (kD === undefined) kD = 0.01;\\n if (sBounds === undefined) sBounds = [0.1, 10.0];\\n if (failedSolveS === undefined) failedSolveS = 0.1;\\n if (enforceNonnegative == undefined) enforceNonnegative = true;\\n if (maxDeadSteps === undefined) maxDeadSteps = 10;\\n\\n // Do RKF to get the first few time points\\n let rkf45TimePoints = [\\n timePoints[0],\\n timePoints[0] + k0,\\n timePoints[0] + 2.0 * k0,\\n ];\\n\\n let args = [f, cfun, Afun, fArgs, cfunArgs, AfunArgs, diagonalA];\\n let yRKF = rkf45(\\n dydtIMEX,\\n initialCondition,\\n rkf45TimePoints,\\n args,\\n k0 / 10.0,\\n tol,\\n sBounds,\\n 0.0,\\n enforceNonnegative,\\n maxDeadSteps\\n );\\n\\n yRKF = transpose(yRKF);\\n\\n // Set up variables for running CNAB2 VSIMEX\\n let tSol = [timePoints[0]];\\n let iMax = timePoints.length;\\n let y = [initialCondition];\\n let k = 2.0 * k0;\\n let newk;\\n let t = rkf45TimePoints[2];\\n let y0 = yRKF[2];\\n let i = 1;\\n let nDeadSteps = 0;\\n let deadStep = false;\\n let c = cfun(t, ...cfunArgs);\\n let A = Afun(t, ...AfunArgs);\\n let f0 = f(initialCondition, timePoints[0], ...fArgs);\\n let f1 = f(y0, t, ...fArgs);\\n let g1 = vectorAdd(c, mvMult(A, y0, diagonalA));\\n let omega = 1.0;\\n let yStep;\\n let relChangeStep;\\n let relTol = tol * (1.0 + tolBuffer);\\n let relChange = [\\n norm(vectorAdd(y0, svMult(-1.0, yRKF[1]))) / norm(y0),\\n norm(vectorAdd(yRKF[1], svMult(-1.0, initialCondition))) /\\n norm(yRKF[1]),\\n ];\\n\\n // DEBUG\\n let nSteps = 3;\\n // END EDEBUG\\n\\n while (i < iMax && nDeadSteps < maxDeadSteps) {\\n nDeadSteps = 0;\\n while (t < timePoints[i] && nDeadSteps < maxDeadSteps) {\\n // Take CNAB2 step\\n yStep = cnab2Step(y0, c, A, f1, f0, g1, omega, k, diagonalA);\\n\\n // Reject the step if failed to solve\\n if (yStep === null) {\\n newk = vsimexAdjustStepSizeFailedSolve(k, failedSolveS);\\n omega *= newk / k;\\n k = newk;\\n nDeadSteps += 1;\\n console.log(\\\"null yStep\\\");\\n } else {\\n // Relative change\\n relChangeStep =\\n norm(vectorAdd(yStep, svMult(-1.0, y0))) / norm(yStep);\\n\\n // Take step if below tolerance\\n if (relChangeStep <= relTol) {\\n f0 = f(y0, t, ...fArgs);\\n t += k;\\n y0 = yStep;\\n f1 = f(y0, t, ...fArgs);\\n c = cfun(t, ...cfunArgs);\\n A = Afun(t, ...AfunArgs);\\n g1 = vectorAdd(c, mvMult(A, y0, diagonalA));\\n newk = vsimexAdjustStepSizePID(\\n k,\\n relChange,\\n relChangeStep,\\n tol,\\n kP,\\n kI,\\n kD,\\n kBounds,\\n sBounds\\n );\\n relChange = [relChange[1], relChangeStep];\\n omega = newk / k;\\n k = newk;\\n nDeadSteps = 0;\\n }\\n // Reject the step is not within tolerance\\n else {\\n newk = vsimexAdjustStepSizeRejectedStep(\\n k,\\n relChangeStep,\\n tol,\\n kBounds,\\n sBounds\\n );\\n omega *= newk / k;\\n k = newk;\\n nDeadSteps += 1;\\n }\\n }\\n if (enforceNonnegative) {\\n y0 = y0.map(function (x) {\\n if (x < 0.0) return 0.0;\\n else return x;\\n });\\n }\\n\\n // DEBUG\\n\\t\\t nSteps += 1;\\n\\t\\t // END EDEBUG\\n }\\n if (t > tSol[tSol.length - 1]) {\\n y.push(y0);\\n tSol.push(t);\\n }\\n i += 1;\\n }\\n\\n // DEBUG\\n console.log(nSteps);\\n // END DEBUG\\n\\n if (nDeadSteps == maxDeadSteps) {\\n return nanArray(initialCondition, iMax);\\n }\\n let yInterp = interpolateSolution(timePoints, tSol, transpose(y));\\n\\n return yInterp;\\n}\\n\\n\\nfunction interpolate1d(x, xs, ys) {\\n let y2s = naturalSplineSecondDerivs(xs, ys);\\n\\n let yInterp = x.map(function (xVal) {\\n return splineEvaluate(xVal, xs, ys, y2s);\\n });\\n\\n return yInterp;\\n}\\n\\n\\nfunction interpolateSolution(timePoints, t, y) {\\n // Interpolate each row of y\\n let yInterp = y.map(function (yi) {\\n return interpolate1d(timePoints, t, yi);\\n });\\n\\n return yInterp;\\n}\\n\\n\\nfunction naturalSplineSecondDerivs(xs, ys) {\\n /*\\n * Compute the second derivatives for a cubic spline data\\n * measured at positions xs, ys.\\n *\\n * The second derivatives are then used to evaluate the spline.\\n */\\n\\n let n = xs.length;\\n\\n // Storage used in tridiagonal solve\\n let u = zeros(n);\\n\\n // Return value\\n let y2s = zeros(n);\\n\\n // Solve trigiadonal matrix by decomposition\\n for (let i = 1; i < n - 1; i++) {\\n let fracInterval = (xs[i] - xs[i - 1]) / (xs[i + 1] - xs[i - 1]);\\n let p = fracInterval * y2s[i - 1] + 2.0;\\n y2s[i] = (fracInterval - 1.0) / p;\\n u[i] =\\n (ys[i + 1] - ys[i]) / (xs[i + 1] - xs[i]) -\\n (ys[i] - ys[i - 1]) / (xs[i] - xs[i - 1]);\\n u[i] =\\n ((6.0 * u[i]) / (xs[i + 1] - xs[i - 1]) - fracInterval * u[i - 1]) /\\n p;\\n }\\n\\n // Tridiagonal solve back substitution\\n for (let k = n - 2; k >= 0; k--) {\\n y2s[k] = y2s[k] * y2s[k + 1] + u[k];\\n }\\n\\n return y2s;\\n}\\n\\n\\nfunction splineEvaluate(x, xs, ys, y2s) {\\n /*\\n * Evaluate a spline computed from points xs, ys, with second derivatives\\n * y2s, as compute by naturalSplineSecondDerivs().\\n *\\n * Assumes that x and xs are sorted.\\n */\\n let n = xs.length;\\n\\n // Indices bracketing where x is\\n let lowInd = 0;\\n let highInd = n - 1;\\n\\n // Perform bisection search to find index of x\\n while (highInd - lowInd > 1) {\\n let i = (highInd + lowInd) >> 1;\\n if (xs[i] > x) {\\n highInd = i;\\n } else {\\n lowInd = i;\\n }\\n }\\n let h = xs[highInd] - xs[lowInd];\\n let a = (xs[highInd] - x) / h;\\n let b = (x - xs[lowInd]) / h;\\n\\n let y = a * ys[lowInd] + b * ys[highInd];\\n y +=\\n (((Math.pow(a, 3) - a) * y2s[lowInd] + (Math.pow(b, 3) - b) * y2s[highInd]) * Math.pow(h, 2)) /\\n 6.0;\\n\\n return y;\\n}\\n\\n\\n// module.exports = {\\n// vsimex,\\n// rkf45,\\n// zeros, \\n// linspace\\n// };\\n\\n// vsimex(lotkaVolterra, [1.0, 3.0], linspace(0.0, 20.0, 200), [1.0, 2.0, 3.0, 4.0], 0.01, 1e-7, [0.1, 10.0], 0.0)\\n// let lv = lotkaVolterraIMEX(1.0, 2.0, 3.0, 4.0);\\n// let sol = vsimex(lv.f, lv.cfun, lv.Afun, [1.0, 3.0], linspace(0.0, 20.0, 200), [], [], [], lv.diagonalA)\\n\\ncallback()\"}}]]]},\"width\":100,\"title\":\"\\u03ba\",\"start\":0.01,\"end\":1,\"value\":0.5,\"step\":0.01}},{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1116\",\"attributes\":{\"width\":10}},{\"id\":\"p1004\"},{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1117\",\"attributes\":{\"width\":10}},{\"id\":\"p1006\"}]}},{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1119\",\"attributes\":{\"width\":10}},{\"type\":\"object\",\"name\":\"Figure\",\"id\":\"p1010\",\"attributes\":{\"x_range\":{\"id\":\"p1019\"},\"y_range\":{\"id\":\"p1021\"},\"x_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1023\"},\"y_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1025\"},\"title\":{\"type\":\"object\",\"name\":\"Title\",\"id\":\"p1016\"},\"renderers\":[{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1062\",\"attributes\":{\"data_source\":{\"id\":\"p1007\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1063\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1064\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1059\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"ces\"},\"line_color\":\"#1f77b3\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1060\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"ces\"},\"line_color\":\"#1f77b3\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1061\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"ces\"},\"line_color\":\"#1f77b3\",\"line_alpha\":0.2,\"line_width\":2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1073\",\"attributes\":{\"data_source\":{\"id\":\"p1007\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1074\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1075\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1070\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cs\"},\"line_color\":\"#ff7e0e\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1071\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cs\"},\"line_color\":\"#ff7e0e\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1072\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cs\"},\"line_color\":\"#ff7e0e\",\"line_alpha\":0.2,\"line_width\":2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1083\",\"attributes\":{\"data_source\":{\"id\":\"p1007\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1084\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1085\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1080\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cp\"},\"line_color\":\"#2ba02b\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1081\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cp\"},\"line_color\":\"#2ba02b\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1082\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cp\"},\"line_color\":\"#2ba02b\",\"line_alpha\":0.2,\"line_width\":2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1093\",\"attributes\":{\"data_source\":{\"id\":\"p1007\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1094\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1095\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1090\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"ces_approx\"},\"line_color\":\"#1f77b3\",\"line_alpha\":0.3,\"line_width\":4}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1091\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"ces_approx\"},\"line_color\":\"#1f77b3\",\"line_alpha\":0.1,\"line_width\":4}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1092\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"ces_approx\"},\"line_color\":\"#1f77b3\",\"line_alpha\":0.2,\"line_width\":4}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1102\",\"attributes\":{\"data_source\":{\"id\":\"p1007\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1103\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1104\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1099\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cs_approx\"},\"line_color\":\"#ff7e0e\",\"line_alpha\":0.3,\"line_width\":4}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1100\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cs_approx\"},\"line_color\":\"#ff7e0e\",\"line_alpha\":0.1,\"line_width\":4}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1101\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cs_approx\"},\"line_color\":\"#ff7e0e\",\"line_alpha\":0.2,\"line_width\":4}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1111\",\"attributes\":{\"data_source\":{\"id\":\"p1007\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1112\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1113\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1108\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cp_approx\"},\"line_color\":\"#2ba02b\",\"line_alpha\":0.3,\"line_width\":4}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1109\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cp_approx\"},\"line_color\":\"#2ba02b\",\"line_alpha\":0.1,\"line_width\":4}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1110\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"t\"},\"y\":{\"type\":\"field\",\"field\":\"cp_approx\"},\"line_color\":\"#2ba02b\",\"line_alpha\":0.2,\"line_width\":4}}}}],\"toolbar\":{\"type\":\"object\",\"name\":\"Toolbar\",\"id\":\"p1018\",\"attributes\":{\"tools\":[{\"type\":\"object\",\"name\":\"PanTool\",\"id\":\"p1041\"},{\"type\":\"object\",\"name\":\"WheelZoomTool\",\"id\":\"p1042\"},{\"type\":\"object\",\"name\":\"BoxZoomTool\",\"id\":\"p1043\",\"attributes\":{\"overlay\":{\"type\":\"object\",\"name\":\"BoxAnnotation\",\"id\":\"p1044\",\"attributes\":{\"syncable\":false,\"level\":\"overlay\",\"visible\":false,\"left_units\":\"canvas\",\"right_units\":\"canvas\",\"bottom_units\":\"canvas\",\"top_units\":\"canvas\",\"line_color\":\"black\",\"line_alpha\":1.0,\"line_width\":2,\"line_dash\":[4,4],\"fill_color\":\"lightgrey\",\"fill_alpha\":0.5}}}},{\"type\":\"object\",\"name\":\"SaveTool\",\"id\":\"p1045\"},{\"type\":\"object\",\"name\":\"ResetTool\",\"id\":\"p1046\"},{\"type\":\"object\",\"name\":\"HelpTool\",\"id\":\"p1047\"}]}},\"left\":[{\"type\":\"object\",\"name\":\"LinearAxis\",\"id\":\"p1034\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"BasicTicker\",\"id\":\"p1035\",\"attributes\":{\"mantissas\":[1,2,5]}},\"formatter\":{\"type\":\"object\",\"name\":\"BasicTickFormatter\",\"id\":\"p1036\"},\"axis_label\":\"dimensionless concentration\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1037\"}}}],\"below\":[{\"type\":\"object\",\"name\":\"LinearAxis\",\"id\":\"p1027\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"BasicTicker\",\"id\":\"p1028\",\"attributes\":{\"mantissas\":[1,2,5]}},\"formatter\":{\"type\":\"object\",\"name\":\"BasicTickFormatter\",\"id\":\"p1029\"},\"axis_label\":\"dimensionless time\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1030\"}}}],\"center\":[{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1033\",\"attributes\":{\"axis\":{\"id\":\"p1027\"}}},{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1040\",\"attributes\":{\"dimension\":1,\"axis\":{\"id\":\"p1034\"}}},{\"type\":\"object\",\"name\":\"Legend\",\"id\":\"p1065\",\"attributes\":{\"location\":\"center_right\",\"items\":[{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1066\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"ES\"},\"renderers\":[{\"id\":\"p1062\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1076\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"S\"},\"renderers\":[{\"id\":\"p1073\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1086\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"P\"},\"renderers\":[{\"id\":\"p1083\"}]}}]}}],\"frame_width\":500,\"frame_height\":250}}]}}],\"callbacks\":{\"type\":\"map\"}}};\n", " const render_items = [{\"docid\":\"d52ccfd7-2fe2-497c-a43c-649b364768e3\",\"roots\":{\"p1120\":\"9c8deadf-8ee3-419e-857d-63150021f764\"},\"root_ids\":[\"p1120\"]}];\n", " root.Bokeh.embed.embed_items_notebook(docs_json, render_items);\n", " }\n", " if (root.Bokeh !== undefined) {\n", " embed_document(root);\n", " } else {\n", " let attempts = 0;\n", " const timer = setInterval(function(root) {\n", " if (root.Bokeh !== undefined) {\n", " clearInterval(timer);\n", " embed_document(root);\n", " } else {\n", " attempts++;\n", " if (attempts > 100) {\n", " clearInterval(timer);\n", " console.log(\"Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing\");\n", " }\n", " }\n", " }, 10, root)\n", " }\n", "})(window);" ], "application/vnd.bokehjs_exec.v0+json": "" }, "metadata": { "application/vnd.bokehjs_exec.v0+json": { "id": "p1120" } }, "output_type": "display_data" } ], "source": [ "bokeh.io.show(biocircuits.jsplots.michaelis_menten_approx())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By adjusting the parameters $\\zeta$ and $\\kappa$, we find that provided $\\zeta \\ll 1$, the solution of the Michaelis-Menten equation very closely matches the exact solution When $\\zeta$ is large and the approximation breaks down, we see obvious problems with the approximate solution—the concentration of product goes negative because mass is not conserved. We also find that in the small $\\zeta$ regime, the parameter $\\kappa$ has no bearing on the solution. This is also evident in the dimensionless equations. When $\\zeta$ is small, we have\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}\\tilde{c}_\\mathrm{es}}{\\mathrm{d}\\tilde{t}} \\approx 0\n", "\\end{align}\n", "\n", "such that\n", "\n", "\\begin{align}\n", "(1 - \\tilde{c}_\\mathrm{es})\\tilde{c}_\\mathrm{s} \\approx \\tilde{c}_\\mathrm{es}.\n", "\\end{align}\n", "\n", "The, the ODE describing substrate dynamics is\n", "\n", "\\begin{align}\n", "\\kappa\\,&\\frac{\\mathrm{d}\\tilde{c}_\\mathrm{s}}{\\mathrm{d}\\tilde{t}} = -(1 - \\tilde{c}_\\mathrm{es})\\tilde{c}_\\mathrm{s} + (1-\\kappa)\\tilde{c}_\\mathrm{es}\n", "\\approx -\\tilde{c}_\\mathrm{es} + (1-\\kappa)\\tilde{c}_\\mathrm{es}\n", "= -\\kappa \\tilde{c}_\\mathrm{es}\n", "\\approx -\\kappa \\,\\frac{\\tilde{c}_\\mathrm{s}}{1+\\tilde{c}_\\mathrm{s}},\n", "\\end{align}\n", "\n", "giving\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}\\tilde{c}_\\mathrm{s}}{\\mathrm{d}\\tilde{t}} \\approx \\frac{\\tilde{c}_\\mathrm{s}}{1+\\tilde{c}_\\mathrm{s}},\n", "\\end{align}\n", "\n", "such that the dynamics are independent of $\\kappa$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operating regimes\n", "\n", "Now that we know when the quasi-steady state approximation is valid such that the rate of production of product is\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_p}{\\mathrm{d}t} \\approx k_2 c_\\mathrm{e}^0\\, \\frac{c_\\mathrm{s}/K_\\mathrm{M}}{1 + c_\\mathrm{s}/K_\\mathrm{M}},\n", "\\end{align}\n", "\n", "we can investigate limits of small and large substrate concentrations on the dynamics. First, in the limit of small substrate concentration where $c_\\mathrm{s}/K_\\mathrm{M} \\ll 1$, we have\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{p}}{\\mathrm{d}t} \\approx \\frac{k_2 c_\\mathrm{e}^0}{K_\\mathrm{M}}\\,c_\\mathrm{s}.\n", "\\end{align}\n", "\n", "In this case, we have pseudo-first order kinetics in which the rate of production of product is linear in the substrate concentration with an effective rate constant of $k_2c_\\mathrm{e}^0/K_\\mathrm{M}$.\n", "\n", "Second, in the limit of large substrate concentration where $c_\\mathrm{s}/K_\\mathrm{M} \\gg 1$, we have\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{p}}{\\mathrm{d}t} \\approx k_2 c_\\mathrm{e}^0,\n", "\\end{align}\n", "\n", "which is apparently zero-order in the substrate concentration. An enzyme operating in this high substrate concentration regime is said to be **operating at saturation**. In this sense, the Michaelis constant sets the concentration scale of the substrate for which maximal conversion rate may be achieved." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reaction velocity and $k_\\mathrm{cat}$\n", "\n", "In many schemes for catalyzed conversion of substrate to product, we can write the approximate dynamics for the production rate of product as\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{p}}{\\mathrm{d}t} = k_\\mathrm{cat}\\,c_\\mathrm{e}^0\\,\\frac{c_\\mathrm{s}/K_\\mathrm{M}}{1 + c_\\mathrm{s}/K_\\mathrm{M}}.\n", "\\end{align}\n", "\n", "Some authors refer to $\\mathrm{d}c_\\mathrm{p}/\\mathrm{d}t$ as the reaction velocity, and the product $k_\\mathrm{cat}\\,c_\\mathrm{e}^0$ as the **maximum reaction velocity**, denoted $v_\\mathrm{max}$ or $V_\\mathrm{max}$. \n", "\n", "For the standard Michaelis-Menten chemical reaction scheme we have considered here, $k_\\mathrm{cat} = k_2$ and $K_\\mathrm{M} = (k_{-1} + k_2) / k_{1})$. Other reaction schemes may have different expressions. For example, if an inhibitor is present that can bind teh enzyme, the reaction scheme is\n", "\n", "\\begin{align}\n", "\\require{mhchem}\n", "&\\ce{E + S <=>[k_1][k_{-1}] ES ->[k_2] E + P},\\\\\n", "&\\ce{E + I <=>[k_3][k_{-3}] EI}.\n", "\\end{align}\n", "\n", "It can be derived that\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}c_\\mathrm{p}}{\\mathrm{d}t} = k_\\mathrm{cat}\\,c_\\mathrm{e}^0\\,\\frac{c_\\mathrm{s}/K_\\mathrm{M}}{1 + c_\\mathrm{s}/K_\\mathrm{M}},\n", "\\end{align}\n", "\n", "where, like standard Michaelis-Menten kinetics, $k_\\mathrm{cat} = k_2$, but the Michaelis constant is adjusted to account for inhibition,\n", "\n", "\\begin{align}\n", "K_\\mathrm{M} = \\frac{k_{-1} + k_2}{k_1}\\left(1+\\frac{k_3}{k_{-3}}\\,c_\\mathrm{i}\\right),\n", "\\end{align}\n", "\n", "where $c_\\mathrm{i}$ is the concentration of inhibitor. In the inhibited case, the Michaelis constant is larger, meaning that more substrate is necessary to get a faster production rate, as we would expect." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Computing environment" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "tags": [ "hide_input" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python implementation: CPython\n", "Python version : 3.10.10\n", "IPython version : 8.10.0\n", "\n", "numpy : 1.23.5\n", "scipy : 1.10.0\n", "bokeh : 3.1.0\n", "biocircuits: 0.1.10\n", "jupyterlab : 3.5.3\n", "\n" ] } ], "source": [ "%load_ext watermark\n", "%watermark -v -p numpy,scipy,bokeh,biocircuits,jupyterlab" ] } ], "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.10" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "position": { "height": "730.4000244140625px", "left": "486.6000061035156px", "right": "20px", "top": "120px", "width": "517.4000244140625px" }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }