From eb4d354061217b9a716094abb75e18c14059be5b Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 3 Jul 2021 18:02:35 +0100 Subject: [PATCH] Tutorial for identifying flip-flop events --- notebooks/3-FlipFlop.ipynb | 599 +++++++++++++++++++++++++++++++++++++ 1 file changed, 599 insertions(+) create mode 100644 notebooks/3-FlipFlop.ipynb diff --git a/notebooks/3-FlipFlop.ipynb b/notebooks/3-FlipFlop.ipynb new file mode 100644 index 0000000..a43ea6c --- /dev/null +++ b/notebooks/3-FlipFlop.ipynb @@ -0,0 +1,599 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Identify cholesterol flip-flop events\n", + "\n", + "A flip-flop event occurs when a molecule - typically a sterol - moves from one leaflet of a bilayer into the opposing leaflet.\n", + "\n", + "We will identify flip-flop events in a ternary mixture of DPPC, DOPC, and Cholesterol simulated by [Smith et al.](https://www.biorxiv.org/content/10.1101/2021.05.24.445501v3).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pickle\n", + "\n", + "import numpy as np\n", + "import MDAnalysis as mda\n", + "\n", + "from lipyphilic.lib.flip_flop import FlipFlop\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load the topology and trajectory using MDAnalysis" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "u = mda.Universe(\"../datafiles/dppc-dopc-chol.tpr\", \"../datafiles/dppc-dopc-chol.xtc\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load the leaflet information\n", + "\n", + "To identify flip-flop events, we first need to know which leaflet each lipid is in at each frame. We will use the results from the notebook on [assigning lipids to leaflets](2-AssignLeaflets.ipynb)." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"../results/leaflets.pkl\", 'rb') as f:\n", + " leaflets = pickle.load(f)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Find flip-flop events\n", + "\n", + "The class `lipyphilic.lib.flip_flop.FlipFlop` finds the frames at which a flip-flop event begins and ends, as well as the direction of travel (upper-to-lower or lower-to-upper).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "flip_flop = FlipFlop(\n", + " universe=u,\n", + " lipid_sel=\"resname CHOL and name ROH\", # only find flip-flop events for cholesterol\n", + " leaflets=leaflets.filter_leaflets(\"resname CHOL and name ROH\") # pass only leaflet information on cholesterol\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Select the frames to use in the analysis (`None` will use every frame):" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "76074d71f06a4349b7c6d55780a8842a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/4000 [00:00" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flip_flop.run(\n", + " start=None,\n", + " stop=None,\n", + " step=None\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The results are then available in the `flipflop.flip_flops` attribute as a NumPy array.\n", + "\n", + "Each row corresponds to an individual flip-flop event. In each row, the four columns correspond to the:\n", + "- molecule resindex\n", + "- flip-flop start frame\n", + "- flip-flop end frame\n", + "- the leaflet in which the molecule resides after the flip-flop. 1 and -1 correspond to the upper and lower leaflets respectively.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(7743, 4)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# We see there were 7743 flip-flop events in total\n", + "flip_flop.flip_flops.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's look at the first flip-flop event:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "first_event = flip_flop.flip_flops[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 1, 39, 40, 1])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "first_event" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above case, cholesterol with residue index 1 left it's original leaflet at frame 39, and entered its new leaflet at frame 40. This new leaflet is the upper leaflet (as the fourth column is equal to 1)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this information, it is possible to, for example, determine the local lipid environemnt immediately before and after the flip-flop event occured. This is useful to know as [Gu et al.](https://pubs.acs.org/doi/10.1021/acs.jctc.8b00933) showed that translocation is highly influenced by the local lipid environment of cholesterol." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Specify minimum residence time for successful flip-flops\n", + "\n", + "Due to thermal fluctuations, cholesterol may briefly go to the midplane before returning to its original lealfet. It may also briefly leave the midplane before returning to the hydrophobic core. As such, it is useful to be able to ignore these small fluctuations.\n", + "\n", + "With `FlipFlop`, we can specify the minumum number of frames a molecule must reside in its new leaflet for the flip-flop to be considered successful. We do this using the `frame_cutoff` keyword:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "flip_flop = FlipFlop(\n", + " universe=u,\n", + " lipid_sel=\"name ROH\",\n", + " leaflets=leaflets.filter_leaflets(\"name ROH\"),\n", + " frame_cutoff=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With *frame_cutoff=2*, a molecule must remain in its new leaflet for at least 2 consecutive frames for the flip-flop to be considered successful. If this condition is not met, the flip-flop event is recorded as failing." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ac3c40ea8e774cc78a6fecba1a3d2316", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/4000 [00:00" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flip_flop.run(\n", + " start=None,\n", + " stop=None,\n", + " step=None\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Calculate the flip-flop rate\n", + "\n", + "`FlipFlop` returns information on whether each event was successful (the molecule resides in the opposing leaflet for at least a given length of time), or not (the molecule went to the midplane but returned to its original leaflet).\n", + "\n", + "This can be used to calculate the rate of flip-flop. The flip-flop rate, $k$, is given by the number of successful flip-flop events, $N_{\\rm Success}$, divided by the product of the number of cholesterol molecles, ($N_{\\rm Chol}$), and the total simulation time, $t_{\\rm Seconds}$, used in the analysis:\n", + "\n", + "$$\n", + "k = \\frac{N_{\\rm Success}}{N_{\\rm Chol} t_{\\rm Seconds}}\n", + "$$\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "cholesterol = u.select_atoms(\"resname CHOL\")\n", + "n_cholesterol = cholesterol.n_residues" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "ps_to_seconds = 1e-12 # convert ps to seconds\n", + "total_time = u.trajectory.dt * flip_flop.n_frames * ps_to_seconds" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "number_successful = np.sum(flip_flop.flip_flop_success == \"Success\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "flip_flop_rate = number_successful / (n_cholesterol * total_time) # per second" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4252941.176470588" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flip_flop_rate" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note\n", + "----\n", + "\n", + "See [Baral et al.](https://www.sciencedirect.com/science/article/pii/S0009308420300980) for further discussion on flip-flop in lipid bilayers, including the affect on the flip-flop rate of the buffer size used to assign molecules to the midplane of the bilayer.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:lpp]", + "language": "python", + "name": "conda-env-lpp-py" + }, + "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.6" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "0bbc4c1e22d54ccba1a7a890bfb310a5": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": {} + }, + "1ea4670b4e1e4a8484beb1a5507c055e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "description_width": "" + } + }, + "5ff8a8b3042549a698ffd9a22d9d7bcf": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "description_width": "" + } + }, + "66cedb98dc6e4f33b2121f63d7236b56": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "FloatProgressModel", + "state": { + "bar_style": "success", + "layout": "IPY_MODEL_0bbc4c1e22d54ccba1a7a890bfb310a5", + "max": 4000, + "style": "IPY_MODEL_e61acd172d434fbba65e5ef85a9a9600", + "value": 4000 + } + }, + "6fa4bcc784db4fb7b481f490bff57bfd": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "layout": "IPY_MODEL_b83f125755ba40ddbc0cc262d5141dc7", + "style": "IPY_MODEL_5ff8a8b3042549a698ffd9a22d9d7bcf", + "value": " 4000/4000 [00:00<00:00, 10280.69it/s]" + } + }, + "76074d71f06a4349b7c6d55780a8842a": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "children": [ + "IPY_MODEL_87fe035a5bc0414992845b0879abae82", + "IPY_MODEL_66cedb98dc6e4f33b2121f63d7236b56", + "IPY_MODEL_6fa4bcc784db4fb7b481f490bff57bfd" + ], + "layout": "IPY_MODEL_a4452effe28a4c089639bacb487b867d" + } + }, + "873079633f824397bd5922904c72483e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "layout": "IPY_MODEL_aed3e085bddb4b41a22d2b190066605a", + "style": "IPY_MODEL_e9eecf57ef3e4cfc8772ca2fcce19ef5", + "value": "100%" + } + }, + "87fe035a5bc0414992845b0879abae82": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "layout": "IPY_MODEL_f26af783cae1497d8bbc81d2bae45b63", + "style": "IPY_MODEL_e0995304394b4d2799efc2848ad895e4", + "value": "100%" + } + }, + "9fc87c45000948dda157719845d2d2e9": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": {} + }, + "a4452effe28a4c089639bacb487b867d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": {} + }, + "ac3c40ea8e774cc78a6fecba1a3d2316": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "children": [ + "IPY_MODEL_873079633f824397bd5922904c72483e", + "IPY_MODEL_d92084c58eef4ab790c6ec76eaf4c73f", + "IPY_MODEL_b497903963e141e7989292c75bd89ccd" + ], + "layout": "IPY_MODEL_9fc87c45000948dda157719845d2d2e9" + } + }, + "aed3e085bddb4b41a22d2b190066605a": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": {} + }, + "b497903963e141e7989292c75bd89ccd": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "layout": "IPY_MODEL_fdba74bf44d248fdb8eed31a67a599b0", + "style": "IPY_MODEL_e7d0fd730006475abc44fcfd37751df0", + "value": " 4000/4000 [00:00<00:00, 9983.59it/s]" + } + }, + "b83f125755ba40ddbc0cc262d5141dc7": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": {} + }, + "d92084c58eef4ab790c6ec76eaf4c73f": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "FloatProgressModel", + "state": { + "bar_style": "success", + "layout": "IPY_MODEL_e082fa6cd13e4473b5aceacb4bf1714d", + "max": 4000, + "style": "IPY_MODEL_1ea4670b4e1e4a8484beb1a5507c055e", + "value": 4000 + } + }, + "e082fa6cd13e4473b5aceacb4bf1714d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": {} + }, + "e0995304394b4d2799efc2848ad895e4": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "description_width": "" + } + }, + "e61acd172d434fbba65e5ef85a9a9600": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "description_width": "" + } + }, + "e7d0fd730006475abc44fcfd37751df0": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "description_width": "" + } + }, + "e9eecf57ef3e4cfc8772ca2fcce19ef5": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "description_width": "" + } + }, + "f26af783cae1497d8bbc81d2bae45b63": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": {} + }, + "fdba74bf44d248fdb8eed31a67a599b0": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": {} + } + }, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}