{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "[PyBroMo](http://tritemio.github.io/PyBroMo/) - 2. Generate timestamps - Parallel" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> *This notebook is part of [PyBroMo](http://tritemio.github.io/PyBroMo/) a \n", "> python-based single-molecule Brownian motion diffusion simulator \n", "> that simulates confocal [smFRET](http://en.wikipedia.org/wiki/Single-molecule_FRET)\n", "> experiments. You can find the full list of notebooks in \n", "> [Usage Examples](http://tritemio.github.io/PyBroMo/#usage-examples).*" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Start the cluster" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ">*In this notebooks we load simulations saved in a cluster and generate timestamps \n", ">for different emissions and background rates.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Follow the steps in [HOWTO CLUSTER SETUP.txt](files/HOWTO%20CLUSTER%20SETUP.txt) \n", "to configure and start an IPython cluster. There is another \n", "[txt file](files/HOWTO%20WIN7%20REMOTE.txt) explaining\n", "how to manage remotely windows machines (so you can start the enigines\n", "without walking in front of the remote PC).\n", "\n", "After the cluster is started we can test it:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from IPython.parallel import Client\n", "from IPython.utils.path import get_ipython_dir\n", "ipython_dir = get_ipython_dir() " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "PROFILE = 'parallel'\n", "rc = Client(ipython_dir+'/profile_%s/security/ipcontroller-client.json' % PROFILE)\n", "dview = rc[:]\n", "dview.block = True" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "rc.ids" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 6, "text": [ "[0, 1, 2, 3, 4, 5, 6, 7]" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The previous command returns a list of integers\n", "that are the ID of all the connected engines (remote or local)." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Prepare the cluster" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Run the inizialization script for the simulation. This will \n", "just set the correct folder and load brownian motion functions\n", "on the local computer:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%run -i load_bromo.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "/home/anto/Documents/ucla/src/brownian\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Prepare the engines (change folder, define a unique eid, load PyBroMo software):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%px %reset # Not needed on the first excution" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 54 }, { "cell_type": "code", "collapsed": false, "input": [ "# Send a variable containing the engine ID to each engine\n", "dview.scatter('eid', rc.ids, flatten=True)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 55 }, { "cell_type": "code", "collapsed": false, "input": [ "%px eid" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "display_data", "text": [ "\u001b[0;31mOut[0:1277]: \u001b[0m0" ] }, { "metadata": {}, "output_type": "display_data", "text": [ "\u001b[0;31mOut[1:1277]: \u001b[0m1" ] }, { "metadata": {}, "output_type": "display_data", "text": [ "\u001b[0;31mOut[2:1277]: \u001b[0m2" ] }, { "metadata": {}, "output_type": "display_data", "text": [ "\u001b[0;31mOut[3:1277]: \u001b[0m3" ] }, { "metadata": {}, "output_type": "display_data", "text": [ "\u001b[0;31mOut[4:1277]: \u001b[0m4" ] }, { "metadata": {}, "output_type": "display_data", "text": [ "\u001b[0;31mOut[5:1277]: \u001b[0m5" ] }, { "metadata": {}, "output_type": "display_data", "text": [ "\u001b[0;31mOut[6:1277]: \u001b[0m6" ] }, { "metadata": {}, "output_type": "display_data", "text": [ "\u001b[0;31mOut[7:1277]: \u001b[0m7" ] } ], "prompt_number": 56 }, { "cell_type": "code", "collapsed": false, "input": [ "%%px\n", "import os\n", "if os.name == 'posix':\n", " BROWN_DIR = \"/home/anto/Documents/ucla/src/brownian/\"\n", "elif os.name == 'nt':\n", " BROWN_DIR = r\"C:/Data/Antonio/software/Dropbox/brownian/\"" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 57 }, { "cell_type": "code", "collapsed": false, "input": [ "%%px \n", "%cd $BROWN_DIR" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[stdout:0] C:\\Data\\Antonio\\software\\Dropbox\\brownian\n", "[stdout:1] C:\\Data\\Antonio\\software\\Dropbox\\brownian\n", "[stdout:2] C:\\Data\\Antonio\\software\\Dropbox\\brownian\n", "[stdout:3] C:\\Data\\Antonio\\software\\Dropbox\\brownian\n", "[stdout:4] C:\\Data\\Antonio\\software\\Dropbox\\brownian\n", "[stdout:5] C:\\Data\\Antonio\\software\\Dropbox\\brownian\n", "[stdout:6] C:\\Data\\Antonio\\software\\Dropbox\\brownian\n", "[stdout:7] C:\\Data\\Antonio\\software\\Dropbox\\brownian\n" ] } ], "prompt_number": 58 }, { "cell_type": "code", "collapsed": false, "input": [ "%px run -i brownian.py" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 59 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Generate timestamps from a simulation (single FRET value, single ID)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we load in the remote engine the simulation containing the emission array. We let the remote engines to simulate the timestamps. Then we transfer the timestamps locally and merge them in a single\n", "timestamp array.\n", "\n", "We start loading on each engine a simulation with `ID=1` and containing the string `t_max10.0s`\n", "(so we select only 10s simualtions):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%px\n", "S = load_sim_id(ID=1, glob_str=\"*t_max10.0s*\", dir_=SIM_DATA_DIR)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[stdout:0] \n", "Loaded:\n", "C:/Data/Antonio/data/sim/brownian/objects\\bromo_sim_D1.2e-11_30P_64pM_step0.5us_t_max10.0s_ID0-1.pickle\n", "[stdout:1] \n", "Loaded:\n", "C:/Data/Antonio/data/sim/brownian/objects\\bromo_sim_D1.2e-11_30P_64pM_step0.5us_t_max10.0s_ID1-1.pickle\n", "[stdout:2] \n", "Loaded:\n", "C:/Data/Antonio/data/sim/brownian/objects\\bromo_sim_D1.2e-11_30P_64pM_step0.5us_t_max10.0s_ID2-1.pickle\n", "[stdout:3] \n", "Loaded:\n", "C:/Data/Antonio/data/sim/brownian/objects\\bromo_sim_D1.2e-11_30P_64pM_step0.5us_t_max10.0s_ID3-1.pickle\n", "[stdout:4] \n", "Loaded:\n", "C:/Data/Antonio/data/sim/brownian/objects\\bromo_sim_D1.2e-11_30P_64pM_step0.5us_t_max10.0s_ID4-1.pickle\n", "[stdout:5] \n", "Loaded:\n", "C:/Data/Antonio/data/sim/brownian/objects\\bromo_sim_D1.2e-11_30P_64pM_step0.5us_t_max10.0s_ID5-1.pickle\n", "[stdout:6] \n", "Loaded:\n", "C:/Data/Antonio/data/sim/brownian/objects\\bromo_sim_D1.2e-11_30P_64pM_step0.5us_t_max10.0s_ID6-1.pickle\n", "[stdout:7] \n", "Loaded:\n", "C:/Data/Antonio/data/sim/brownian/objects\\bromo_sim_D1.2e-11_30P_64pM_step0.5us_t_max10.0s_ID7-1.pickle\n" ] } ], "prompt_number": 60 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we generate the timestamps remotely and merge them in local arrays \n", "(`ph_times_d` and `ph_times_a`):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "run -i brownian.py" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 65 }, { "cell_type": "code", "collapsed": false, "input": [ "ph_times_d, t_tot, sim_name = parallel_gen_timetag(dview, max_em_rate=1e6, bg_rate=2e3)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 62 }, { "cell_type": "code", "collapsed": false, "input": [ "ph_times_a, t_tot, sim_name = parallel_gen_timetag(dview, max_em_rate=5e5, bg_rate=4e3)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a last optional step we change data format. \n", "We merge the two arrays `ph_times_d` and `ph_times_a` in a single array `ph_times`\n", "and use a boolean mask (array of booleans) `a_em` to signal if each timestamp\n", "is from the **A**cceptor (`True`) or from the **D**onor (`False`)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "ph_times, a_em = merge_DA_ph_times(ph_times_d, ph_times_a)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and test that the two representation are equivalent:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "(ph_times_d == ph_times[-a_em]).all()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "(ph_times_a == ph_times[a_em]).all()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "ph_times.size == ph_times_d.size+ph_times_a.size == a_em.size" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this examples we have generate a FRET efficiency of:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "k = 5e5/1e6\n", "E = k/(k+1)\n", "print \"%.1f%%\" % (E*100)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "33.3%\n" ] } ], "prompt_number": 2 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Generate sets of timestamps (multiple FRET values, multiple IDs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to simulate different FRET values we need different levels of emission rates.\n", "Furthermore it is important to check different background rates in order to understand \n", "how background influence the burst analisys. \n", "Therefore we need to simulated different backgorund rate for each emission rate.\n", "\n", "The process can easily diverge if we choose too many cases. Practically around 100 cases \n", "(for example 10 emission leveles and 10 background rates) can be simulated in around \n", "20 minutes on a quad-core desktop running 4 engines.\n", "\n", "Here we choose the values to simulate for the max emission rate and background rate:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np\n", "EM = np.r_[10,20:201:20, 190]*1e3\n", "#EM = np.r_[90,99,101,110]*1e3\n", "print EM" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 90000. 99000. 101000. 110000.]\n" ] } ], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "BG = np.r_[1:7,8]*1e3\n", "print BG" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 1000. 2000. 3000. 4000. 5000. 6000. 8000.]\n" ] } ], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Graphical check of the values:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print EM[None,:].shape, BG.shape" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(1, 4) (7,)\n" ] } ], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "# Compute any possible k and E\n", "M = np.dot(EM[:,None],1/EM[None,:])\n", "k = np.sort(M.ravel())\n", "E = k/(k+1)\n", "M.shape" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 18, "text": [ "(12, 12)" ] } ], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": [ "%pylab inline" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Populating the interactive namespace from numpy and matplotlib\n" ] }, { "output_type": "stream", "stream": "stderr", "text": [ "WARNING: pylab import has clobbered these variables: ['box', 'rc']\n", "`%pylab --no-import-all` prevents importing * from pylab and numpy\n" ] } ], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(E, '.')\n", "title(\"Check how many E values are possible\");" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAEKCAYAAAAYd05sAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XtYVHX+B/A3KhleEBVvMFwUvEAoWGTaRanWS2waqRji\nqrimrqvPLrbrz7YnV3MLMdceM3/b6rMprSlZrf4gA7wgZJpGpWCBvwR+YAjeUC6aKYjf3x/TOc4M\nM8NlzjDnDO/X8/Acz8xh5j0H+czhM9/zPS5CCAEiInI6HRwdgIiI7IMFnojISbHAExE5KRZ4IiIn\nxQJPROSkWOCJiJwUC7wdrF69GrNnz1b8cTt06ID/+7//a3K70tJSdOjQAXfv3lU8A5kXFxeHlStX\nOjqGZoWEhODIkSMAmv798ff3R2ZmZltF0zQW+FbatWsXwsPD0b17d3h5eSEyMhLHjh0DALi4uDg4\nHUni4uLQuXNndO/eXf4aOXKk4s/j4uLCn7sNvv/+e4wdOxZA078/3NfNxwLfCm+99RaWLVuGV199\nFZcvX0ZZWRmWLFmCTz/9FADAc8fUw8XFBStWrMD169flr1OnTtnludT8c29oaHB0hGZT837UGhb4\nFqqpqcGqVavwj3/8A1FRUXBzc0PHjh3x61//GomJiQD0RaWurg5z586Fu7s7QkJC8O2338qPUVFR\ngWnTpqFv374YNGgQ3nnnHfm+u3fvIiEhAYGBgXB3d0d4eDjKy8sb5Th69Ch8fX3lP2vN+eCDD+Dn\n54c+ffogISFBvv327duIj4+Ht7c3vL29sWzZMtTV1QEAxo0bhz179gAAjh07hg4dOiAtLQ0AkJmZ\nafHod/Xq1YiOjsbs2bPh7u6OESNGoLCwEGvXrkW/fv3g5+eHgwcPyttv374dwcHBcHd3R0BAALZu\n3Srfl52dDZ1Oh7feegv9+vWDl5cXkpKSAABff/01+vfvb1QE9uzZg7CwMIv7obmCgoLw2Wefyet3\n7txBnz59kJubCwCIjo7GgAED4OHhgXHjxqGgoMDo+6WjyqSkJDzxxBNG9xm2127fvo0///nP8PPz\nQ//+/bF48WLcunULAFBZWYlnn30WPXv2RO/evTF27FiLBe+Pf/wjfH190aNHD4SHh+Po0aPyfatX\nr8b06dMxe/Zs9OjRA++//z5qamowf/58eHl5QafTYeXKlRbbeNL3x8TEwN3dHQ899BBOnz4t33/m\nzBlERESgZ8+eCAkJkQ9uACAtLQ0PPPAA3N3dodPpsGHDBouvTeLv74/Dhw/L+/HWrVsWn9uQEAKJ\niYkIDAyEp6cnXnjhBVRVVZndtj1igW+h48eP49atW3j++ectbiOEQGpqKmbOnImamhpMmTIFS5cu\nBaAv4JMnT8bIkSNRUVGBzMxMbNy4EQcOHAAAbNiwAR9++CHS09NRW1uLbdu2wc3NzejxMzIyEBsb\niz179hj9kpg6duwYzp49i8zMTKxZswY//PADAOCNN95ATk4O8vLykJeXh5ycHLz++usAgIiICGRn\nZwMAPv/8cwwaNEh+E/n8888RERFh8fn27duHOXPmoKqqCiNHjsT48eMB6N/QVq5ciUWLFsnb9uvX\nD5999hlqa2uxfft2LFu2zOjI+tKlS6itrUVFRQXee+89LFmyBDU1NXj44YfRu3dv7N+/X952x44d\nmDt3rtWfR3PExsYiOTlZXt+/fz/69u0rv3n8+te/RlFREa5cuYIHH3wQs2bNatbjmnr55ZdRVFSE\nvLw8FBUVoby8HGvWrAGg//n7+PigsrISly9fxtq1ay22I0aNGoW8vDxUVVUhNjYW0dHR8hs1AKSm\npiI6Oho1NTWIjY1FXFwc7rvvPhQXF+PUqVM4cOAA/vWvf1nMmZqaihkzZsiPHxUVhYaGBtTX12Py\n5MmYNGkSrly5gnfeeQezZs1CYWEhAGD+/PnYunUramtrkZ+fj6eeesria5MYvkYhBFJSUsw+t6lN\nmzYhNTUVR44cwYULF9CzZ08sWbKkBT8NJyeoRT744APRv39/q9usWrVKjB8/Xl7Pz88Xbm5uQggh\nTpw4IXx9fY22T0hIEPPmzRNCCDFkyBCRmppq9nFdXFxEQkKC8PPzE/n5+Rafv6SkRLi4uIjy8nL5\ntlGjRondu3cLIYQICAgQ6enp8n379+8X/v7+QgghDh06JEaMGCGEEGLSpEniX//6lxg9erQQQoix\nY8eKvXv3WnzNEyZMkNdTU1NFt27dxN27d4UQQtTW1goXFxdRU1Nj9vujoqLE22+/LYQQIisrS7i5\nuYmGhgb5/r59+4qvvvpKCCFEYmKimDVrlhBCiKtXr4ouXbqIixcvmn3cuXPnivvvv194eHjIX3Fx\ncWa3LSoqEt27dxc///yzEEKI2NhY8be//c3stlVVVcLFxUXU1tYKIYSIi4sTK1euFEIIsX37dvH4\n448bbe/i4iKKi4vF3bt3RdeuXUVxcbF835dffikGDhwohBDir3/9q3juuedEUVGR2ee1pmfPnuL0\n6dNCCP3PY9y4cfJ9Fy9eFJ07d5ZfmxBC7Nq1Szz55JNmH2vVqlVizJgx8vrdu3fFgAEDxBdffCGO\nHDnS6Hdg5syZYvXq1UIIIXx9fcWWLVsa/aytvTZ/f3+RmZlp9bmPHj3aaNugoCD530IIUVFRIVxd\nXY3+77RnPIJvod69e6OysrLJESr9+vWT/92lSxfcunULd+/exblz51BRUYGePXvKX2vXrsXly5cB\nAOfPn0dAQIDFx920aRNeeOEFBAcHN5m1f//+Rhlu3LgBQH9E7efnJ9/n6+uLiooKAMCYMWNw9uxZ\nXL58Gbm5uZgzZw7Kyspw9epVfP3111b/Yujbt6/8bzc3N3h6espHZtJfIVKG9PR0jB49Gr1790bP\nnj2RlpaGq1evyt/fu3dvdOhw77+nYf5Zs2bh008/xc2bN/HRRx9h7NixRvvbkIuLC5YvX46qqir5\na/v27Wa3DQgIQFBQEFJTU3Hz5k18+umniI2NBaDvYb/88ssIDAxEjx49MHDgQAD6tkNLXLlyBTdv\n3sRDDz0k//yfeeYZ+XGWL1+OwMBATJgwAQEBAVi3bp3Fx/r73/+O4OBgeHh4oGfPnqipqTHKo9Pp\n5H+fO3cO9fX1GDBggPy8v/vd73DlyhWLj2/4/S4uLtDpdKioqMCFCxfg4+NjtK2fn5/cSvzPf/6D\ntLQ0+Pv7IyIiAidOnGjxa7P03KZKS0vx/PPPy68pODgYnTp1wqVLlyw+dnvCAt9CY8aMQefOnbF3\n716L21j7hN/HxwcDBw40Kji1tbXYt2+ffH9RUZHF7//444+xd+9ebNq0qdWvwcvLC6WlpfL6jz/+\nCC8vLwD6QvrQQw9h48aNGD58OFxdXfHoo49iw4YNCAwMRK9evcw+ZktGNdy+fRvTpk3Df/3Xf+Hy\n5cuoqqpCZGRks1spOp0Oo0ePxp49e/DBBx8oOiR15syZSE5ORkpKCoKDgzFo0CAA+lFTqampyMzM\nRE1NDUpKSgCYb/907doVN2/elNcvXrwo/9vT0xNubm4oKCiQf/7V1dWora0FAHTr1g1///vfUVxc\njNTUVLz11ltyb9rQF198gfXr1+Pjjz9GdXU1qqqq0KNHD6M8hj8THx8fdO7cGVevXpWft6amBt99\n953FfVFWVib/++7duzh//jy8vb3h5eWFsrIyo+c6d+6cXJTDw8PxP//zP7hy5QqioqIwY8YMi68t\nKyur2c8t/R815Ovri4yMDKPfp5s3b2LAgAEWX1d7wgLfQj169MCaNWuwZMkSpKSk4ObNm6ivr0d6\nejpWrFgBwHrPd9SoUejevTvefPNN/Pzzz2hoaMD333+Pb775BgDw4osvYuXKlSgqKoIQAqdPn8a1\na9fk7/fy8kJmZibefvtt/POf/2zVa5g5cyZef/11VFZWorKyEmvWrDEqkuPGjcN///d/Y9y4cQD0\nffnNmzfL6+Y0tzgDQF1dHerq6uDp6YkOHTogPT1d/gyiuebMmYN169bh+++/x9SpU63makm2mJgY\n7N+/H//85z+Neuw3btxA586d0atXL/z000945ZVXLD5PaGgo8vPzkZeXh1u3bmH16tXydh06dMCC\nBQsQHx8vHz2Xl5fLr/+zzz6Tf/bu7u7o2LEjOnbs2Cjn9evX0alTJ3h6eqKurg5r1qyR3yTMGTBg\nACZMmICXXnoJ169fx927d1FcXGz1Q/pvv/0We/fuxZ07d7Bx40bcf//9GD16NEaNGoUuXbrgzTff\nRH19PbKzs7Fv3z7ExMSgvr4eO3fuRE1NDTp27Iju3bvL+fft29fotRn+ldac5zb1u9/9Dq+88gp+\n/PFHAPq/kFJTUy2+pvaGBb4VXnrpJbz11lt4/fXX0bdvX/j6+uIf//iH/MGruXG60nrHjh2xb98+\n5ObmYtCgQejTpw8WLlwo/3K+9NJLmDFjBiZMmIAePXpgwYIF8ggL6TF8fHyQmZmJxMREbNu2zWxG\na0fUr776KsLDwzFixAiMGDEC4eHhePXVV+X7x40bhxs3bsjtmLFjx+Knn36y2p6x9ppN17t3745N\nmzZhxowZ6NWrF5KTk/Hcc881Oz8ATJ06FT/++COef/553H///VZzvfnmm0bj4A1bSab69++PRx99\nFMePH8cLL7wg3z5nzhz4+fnB29sbISEhGDNmjFFGw9c/ZMgQ/PWvf8WvfvUrDB06FE888YTRtuvW\nrUNgYCBGjx6NHj16YPz48Th79iwAoLCwEOPHj0f37t3x6KOPYsmSJWbfWCdNmoRJkyZhyJAh8Pf3\nh5ubG3x9fc3mkfz73/9GXV0dgoOD0atXL0RHRxv9dWG635577jns3r0bvXr1ws6dO7Fnzx507NgR\n9913Hz799FOkp6ejT58+WLp0KXbs2IEhQ4YA0I/eGjhwIHr06IGtW7di586dAICioqJmvTYXFxdE\nRUWZfW5Tf/zjHzFlyhRMmDAB7u7uGDNmDHJycsy+pvbIRTRxePPb3/4Wn332Gfr27Wvxz7k//OEP\nSE9PR5cuXZCUlGSXE0mITA0ePBhbtmyRR2mQcl577TUUFRVhx44djo5CNmjyCH7evHnIyMiweH9a\nWhqKiopQWFiIrVu3YvHixYoGJDJnz549cHFxYXG3k5a0tUi9OjW1wRNPPGH0gZyp1NRUeQzyI488\ngurqaly6dMniqAYiW0VEROB///d/eXRpR5wOwDk0WeCbUl5ebjRkSqfT4fz58yzwZDfSiVhkP6tW\nrXJ0BFKAIh+ymv45x3d+IiLHs/kI3tvb22jMqjRW1tx25k5UICIiywICAqyeG2ONzUfwU6ZMwb//\n/W8AwIkTJ+Dh4WG2PVNRUSGPFVbz16pVqxyegTmZkTmZU/oqLi5udX1u8gh+5syZ+Pzzz1FZWQkf\nHx+89tprqK+vBwAsWrQIkZGRSEtLQ2BgILp27WrxNHCtsPaBspowp3K0kBFgTqVpJactmizwhrPr\nWbJ582ZFwhARkXJ4JquJuLg4R0doFuZUjhYyAsypNK3ktEWTZ7Iq9kQuLmijpyIichq21E4ewZvQ\nyhhr5lSOFjICzKk0reS0BQs8EZGTYouGiEjF2KIhIlLAwoVARAQQGQlUVzs6je1Y4E1opS/HnMrR\nQkaAOZWWnZ0tF3QfH+Dxx4FPPgE+/xxIT9cXe62zeaoCIiKtOntWX9AB4Pz5e7eHhwNbtzomk5LY\ngyeidmfhQn1xz88HKisBd3egthYICwP8/YHt2wEPD0en1LOldvIInojaDamwnz4NVFXpb9PpgKNH\ngeXL9UftainsSmAP3oSW+odaoIWcWsgIMKcSpJaMvrhnIzwc+O47wM8P+Ogj5yruAI/giagd6dJF\nvwwLA7p2Bfbtc76ibog9eCJyelJrxtUV6NZNXT32pnAcPBGRFVJr5tAhfZHXSnG3FQu8CTX3Dw0x\np3K0kBFgTltIrRnD4Y9qzKk09uCJyOlILZniYv0HqG5uQFSUtlozSmAPnoicglTUu3TRj2k/dsz4\n/uho/UgZreE4eCJqt8yNbe/fX7+UTmByljNTW4o9eBNa6csxp3K0kBFgTkuMx7bri/mJE/oj9tOn\n9cuDBxu3ZrSyP23BI3gi0hTT/voPP+hvN51mQGrHaLEtoxT24IlIUyIi7k0QJtHp9GekOuMHqBwH\nT0TthjTk0d1dv5SmG3DG4m4rFngTWunLMadytJARYE7Jrl1N99ebQyv70xbswRORJhgOg9y1y7jP\nTuaxB09EmmDYe9fqmPbWYA+eiJyeuekGyDoWeBNa6csxp3K0kBFofzlNr5daX6+fbqC1PXdTWtmf\ntmAPnohUydz1UqOjOVqmJdiDJyJViowE0tONpxtQ6uhdS9iDJyKno9RwyPaMBd6EVvpyzKkcLWQE\n2l9OaRikva6XqpX9aQsWeCIiJ8UePBGpgukkYu7u905oas9sqZ0s8ETkUObmc5e0pxOaLOGHrArS\nSl+OOZWjhYyA8+Y0nc/dcBIxe57QpJX9aQsWeCJyCOlEpvx8/XpYmP5EJo6aUU6TLZqMjAzEx8ej\noaEBL774IlasWGF0f2VlJX7zm9/g4sWLuHPnDv785z8jLi6u8ROxRUNEBgznlnHm+dxtZbcWTUND\nA5YuXYqMjAwUFBQgOTkZZ86cMdpm8+bNGDlyJHJzc5GdnY0//elPuHPnTqvCEFH7YTi3DIu7fVgt\n8Dk5OQgMDIS/vz9cXV0RExODlJQUo20GDBiA2tpaAEBtbS169+6NTp20OwOCVvpyzKkcLWQEnC+n\ndCKTo1oxWtmftrBaicvLy+Hj4yOv63Q6fPXVV0bbLFiwAE899RS8vLxw/fp1fNTeP/ImIpnp0Mdz\n54yHQLJc2JfVAu/i4tLkAyQkJCAsLAzZ2dkoLi7G+PHjkZeXh+7duzfaNi4uDv7+/gAADw8PhIWF\nISIiAsC9d1OuN29duk0tebS8HhERoao81tYlasnT1P48ezbilz579i8ThkX8ssxGVBSQne3YvBI1\n7b/s7GwkJSUBgFwvW01Ycfz4cTFx4kR5PSEhQSQmJhpt88wzz4ijR4/K60899ZT4+uuvGz1WE09F\nRE7omWeEAIRwdzdehocLUVXl6HTaYEvttNqDDw8PR2FhIUpLS1FXV4fdu3djypQpRtsMGzYMhw4d\nAgBcunQJP/zwAwYNGmTbu44Dmb6zqxVzKkcLGQFt5jSdMExNQyC1sj9tYbVF06lTJ2zevBkTJ05E\nQ0MD5s+fj6CgIGzZsgUAsGjRIrzyyiuYN28eQkNDcffuXbz55pvo1atXm4QnInUzvG6q6ZLsj1MV\nEJHizF0gm1qHUxUQkapI0w+kp+uLPTkGC7wJrfTlmFM5WsgIaCPnwoVAWFi2PP2Ami+QrYX9aSvt\nnpFERKpz9iyQl6f/t06njg9T2zP24InIZlLPPT8fqKxsv9dPtQdbaieP4InIZlLPHeCRu5qwB29C\nK3055lSOFjIC6sgpTfHr4wM8/vi9pWHP/d13szVR3NWwP+2NR/BE1GyGR+r6KQfuLaUj99xcx2Sj\nxtiDJ6Jmi4zUD310dwdqa+8t2XO3H46DJ6I2oeapB6gxFngTWunLMadytJARUEdOaeoBPz/jpWFx\nV0PO5tBKTluwwBNRk6QPVyMjgepqR6eh5mIPnoiaZHj91OhoThjWltiDJyK7Mrx+qlqnHqDGWOBN\naKUvx5zK0UJGoO1ymo51j4wE3n23+R+mcn+qB8fBE5ERc2Pdly9nW0aL2IMnIiOmY905xt2x2IMn\nIptJrZn6eiAqimPcnQELvAmt9OWYUzlayAjYL6dU2D/5RN+aOXQIcHU1P8a9Odr7/lQT9uCJ2ilp\nit/Tp4Gqqnu3c6SM82APnqidMhzbDgBhYYC/P7B9O1syasL54ImoxaSx7Szszos9eBNa6csxp3K0\nkBFQPqc0cVhWFrB3r3LFvb3uTzXiETxROyVNHEbOiz14IiIVYw+eiORRMcXF+iGO585ZX7q769s0\n7Ls7L/bgTWilL8ecytFCRqDpnNIUA+fPA8eONb1MT9e/KbR1TrXQSk5bsMATOQlpVIy7e/OWHO/u\n/NiDJ9IwqS3TpYt+xsfly4H165u33LqV7RktsKV2ssATaRgvxOH8ONmYgrTSl2NO5WghI2CcU5o/\nJj9fv66mdosW96ez4igaIg0ynLNdp+OMj2QeWzREGiL13PPzgcpKztXeHnAcPFE7wSN3agn24E1o\npS/HnMpRc0bD66MOH55t1HP/7jt1Fnc1709DWslpCx7BE6mYueuj8sidmqvJHnxGRgbi4+PR0NCA\nF198EStWrGi0TXZ2NpYtW4b6+np4enqafWdkD56o+Ux77bw+avtlt3HwDQ0NGDp0KA4dOgRvb288\n/PDDSE5ORlBQkLxNdXU1HnvsMezfvx86nQ6VlZXw9PRUNCRRe2HuKks6HXD0KE9Oaq/sNg4+JycH\ngYGB8Pf3h6urK2JiYpCSkmK0za5duzBt2jTodDoAMFvctUQrfTnmVI6aMkotGam4S712Pz/g97/P\n1kRxV9P+tEYrOW1htcCXl5fDx8dHXtfpdCgvLzfaprCwENeuXcOTTz6J8PBw7Nixwz5JidoBw6ss\nRUWxHUO2sfohq4uLS5MPUF9fj5MnTyIzMxM3b97EmDFjMHr0aAwePFixkG0pIiLC0RGahTmV44iM\nlqb2dXPTF3Zzl8/Twr4EmFNNrBZ4b29vlJWVyetlZWVyK0bi4+MDT09PuLm5wc3NDWPHjkVeXp7Z\nAh8XFwd/f38AgIeHB8LCwuSdLP25xHWut4f1nJxs5OUBQMQvo2Oyf1lGIDoayM1VV16ut916dnY2\nkpKSAECul60mrKivrxeDBg0SJSUl4vbt2yI0NFQUFBQYbXPmzBnx9NNPizt37oiffvpJhISEiPz8\n/EaP1cRTqUZWVpajIzQLcyrHERmfeUYIQAh3d+NleLgQVVXmv0cL+1II5lSaLbXTag++U6dO2Lx5\nMyZOnIjg4GC88MILCAoKwpYtW7BlyxYAwLBhwzBp0iSMGDECjzzyCBYsWIDg4GDb3nWInJR04lJ9\nvb4Vc/q0fhZIacmeOymJc9EQ2ZnhnO21tfqrKQGc3peah3PREKmQuTHt/fvrl2qa3pecF+eiMSF9\n2KF2zKkcpTIazhvz+OPAJ580HtN+4kTrWzFa2JcAc6oJj+CJFGJu3hhAP6bd3//e0Ee2ZaitsAdP\nZCNL88aYFnai1mAPnsiBTOdo57wxpBbswZvQSl+OOZXT0oymvXbTOdr9/PRtGKWLuxb2JcCcasIj\neKIW4hztpBXswRM1E+doJ0dgD57IjjhHO2kVe/AmtNKXY07lWMoo9drNjWe3Z6+9pTnVhjnVg0fw\nRCbMHbEDHPZI2sMePLVrpvOyS311ab4YgIWdHIs9eKJWMjciRpovhoWdtI49eBNa6csxpzL0l8jL\nhru7ft1wvpisLGDvXvUUd7XvSwlzqgcLPLUrpicp1dcDjz1mPB97W394SmQv7MFTuxIRca8lI+G8\n7KRmttROHsFTu6JvycCoJcN52clZscCb0EpfzhlzmrZPLC0jI4G5c5u3renS9FJ5Bw/eu8C12jnj\nz9yRtJLTFhxFQ6phbkSLpaWnp366gOZsa7qMjr7XZydyZuzBk2pERgLp6ffGoltahofrPwA9dKjp\nbc19L+eNIS1hD540ydyIFsP2iaXlwYPAxx9b38ba97K4U7sh2kgbPpVNsrKyHB2hWZwh57hxQgDG\nX9HRbRZN5gz7Uk2YU1m21E4ewZPDcEQLkX2xB09tTpr/xdUV6NYN2LiR0+4SWWJL7WSBpzZjbpZG\nnmREZB0/ZFWQVsbGaimntXnV1dCS0dK+1ALmVA+Ogye7WbgQyMkBfvyR86oTOQJbNKQIzqtOZB+c\nD54cjvOqE6kPe/AmtNKXU1tOc0MeT5wAxo3LVt286qbUti8tYU5laSWnLVjgqVWaOgtVmld99Wr1\nFnYiZ8cePLWIpQtSAxzySGQP7MFTmzHstQPGk3ipYcgjEd3DFo0JrfTl2iqnaSsmP19/e1hY45aM\nuVaMFvanFjICzKk0reS0BY/gySxzrRhpdIxOp78gtVTQ2ZYhUif24Mks02uXcj51Isew61QFGRkZ\nGDZsGAYPHox169ZZ3O7rr79Gp06dsGfPnlYFIXWQWjItbcUQkfpYLfANDQ1YunQpMjIyUFBQgOTk\nZJw5c8bsditWrMCkSZM0f5Sulb6c0jlN54uprLzXitm7994l7lpa3LWwP7WQEWBOpWklpy2sFvic\nnBwEBgbC398frq6uiImJQUpKSqPt3nnnHUyfPh19+vSxW1CyL2l0jOFEYN99x6N1Ii2zWuDLy8vh\n4+Mjr+t0OpSXlzfaJiUlBYsXLwag7xdpWUREhKMjNIvSOaUzUaWWjFKtGC3sTy1kBJhTaVrJaQur\no2iaU6zj4+ORmJgofxCg9RaNMzOdEOzcuXsTg737Li+6QeRsrBZ4b29vlJWVyetlZWXQ6XRG23z7\n7beIiYkBAFRWViI9PR2urq6YMmVKo8eLi4uDv78/AMDDwwNhYWHyu6jUD3P0unSbWvJYWt+4cWOL\n919ODpCXp18/fz77l6V+fe7c7F+mFVA2r3Sbo/eXtXXTrI7OY2k9NzcX8fHxqsljaZ370/b9l5SU\nBAByvWw1axdsra+vF4MGDRIlJSXi9u3bIjQ0VBQUFFjcPi4uTvznP/8xe18TT6UaWrkQb0tyLlig\nv8C1p6f+wtbu7sbL8HAhqqocn9NRtJBRCOZUmlZy2lI7mxwHn56ejvj4eDQ0NGD+/Pn4y1/+gi1b\ntgAAFi1aZLTtvHnzMHnyZEydOrXR43AcfNszd7KSTgccPapvx6xfz7YMkdrxmqxklunJSjxJiUh7\neE1WBRn2D9XMXM6m5o1xRHHXwv7UQkaAOZWmlZy24Fw0TsTcVZVM540hovaDLRonEhkJpKdz3hgi\nZ8IWTTsntWbMXVWJxZ2o/WKBN6GVvlx2dnaj+WMOHQJcXVs/b4w9aGF/aiEjwJxK00pOW7AHr2Gm\nV1fiVZWBFVOvAAAPHklEQVSIyBB78Bom9dzDwgB/f2D7dnUctRORcjgOvp2RTmBydQW6dWNhJ3Jm\n/JBVQVroy+lbM9lyz13NxV0L+1MLGQHmVJpWctqCPXgHszTDo+nS3R3o00e/Lp3AxJ47EVnDFo2D\nmU4nYI2np/5KS4D+BCZekIPI+bFFo2HShTbc3a0vw8P1H6ZK/2ZxJ6KmsMCbaOu+3K5d+pOSpJOT\nLC0PHgQ+/vjev3Nz2zZna2mhz6mFjABzKk0rOW3BHryDeXjoT0oCml6a/puIyBr24ImIVIw9eA2S\nphmIjASqqx2dhoicEQu8ibbqy0nTDKSn64t9S2mlf6iFnFrICDCn0rSS0xbswbcxadw7x7ITkb2x\nB99GLF0flcMdicga9uA1QGrJSMWdY9mJyN5Y4E0o1Zez9/VRtdI/1EJOLWQEmFNpWslpC/bg7YTX\nRyUiR2MP3k54fVQiUgJ78CrC66MSkVqwwJuwtS8ntWbsfX1UrfQPtZBTCxkB5lSaVnLaggVeYdLs\nkBzfTkSOxh68wqqr9W2arVvZkiEi2/GarEREToofsiqoOX050zHu0rItJw7TSv9QCzm1kBFgTqVp\nJactOA6+FcyNcZeWCxdyznYiUge2aFrAcKKwysp7Y9w51p2I7IUtmjYiHblXVurPSjV3WT0WdyJS\nCxZ4E+b6clLP3XCK3+++uzfG3V5j3VuaU420kFMLGQHmVJpWctqCPfhmMOy563Q8UicibWAP3grT\nnjt77ETU1mypnTyCt4JH7kSkZc3qwWdkZGDYsGEYPHgw1q1b1+j+nTt3IjQ0FCNGjMBjjz2G06dP\nKx60rRj25QynHVDbxTm00j/UQk4tZASYU2layWmLJgt8Q0MDli5dioyMDBQUFCA5ORlnzpwx2mbQ\noEE4cuQITp8+jZUrV2Jha64irUK7dnF0DBFpV5M9+OPHj+O1115DRkYGACAxMREA8PLLL5vdvqqq\nCsOHD8d56cwf6Yk02IMnInI0u/bgy8vL4ePjI6/rdDp89dVXFrd/7733EBkZ2aowjiJ9mFpcrB/y\neO6cfunurj+K59E7EWlRkwXexcWl2Q+WlZWFbdu24dixY2bvj4uLg7+/PwDAw8MDYWFhiIiIAHCv\nH+aIdf2Hqfp1/R8eETh/Xr++cGEEPvrIsfnMrW/cuFE1+8/aunSbWvKYWzfN6ug8ltZzc3MRHx+v\nmjyW1rk/bd9/SUlJACDXy1YTTTh+/LiYOHGivJ6QkCASExMbbZeXlycCAgJEYWGh2cdpxlM5zDPP\nCAEI4e4uBJD1y1KI8HAhqqocnc68rKwsR0doFi3k1EJGIZhTaVrJaUvtbPI76+vrxaBBg0RJSYm4\nffu2CA0NFQUFBUbbnDt3TgQEBIjjx4/bJaS9VVUJER0tRGmp8VKtxZ2I2g9bamezTnRKT09HfHw8\nGhoaMH/+fPzlL3/Bli1bAACLFi3Ciy++iL1798LX1xcA4OrqipycHKPHUOOHrFLvvUsX9tqJSJ1s\nqp0Kvck0qQ2fqtnGjdO3YgD9EbsQ2vmzjTmVo4WMQjCn0rSS05ba2S7PZDWcggDg9VOJyDm1y7lo\nIiKMpyBQ21mqREQSzkVjhekYd3d3wNVVfx8nDyMiZ+b088FLE4adPw8cOwakpwNdu1qegsBwDK+a\nMadytJARYE6laSWnLZz+CF6aMMzwsnpJSTxqJyLn5/Q9+OpqfZtm/Xpg+XL9h6ks7kSkFbbUTqcv\n8EREWsaLbhuQrp/q4wM8/jgQGak/im8urfTlmFM5WsgIMKfStJLTFk7Xgze8CpM0Y/HChfqLYhMR\ntSdO16KJjNSPlDH8UJVDIYlIq9iiMSBdhen0aV6NiYjaN6cp8FLvPTZWP1LGz0/flmlpcddKX445\nlaOFjABzKk0rOW3hNAVe6r2np+uLPRFRe+c0PXip986eOxE5k3Y5Dt50jhk3N6BbN2D7dhZ3InIe\n7fJDVtM5Zg4d0k8iZmtx10pfjjmVo4WMAHMqTSs5baG5cfCmc7kbDofknO5ERPdorkVjOpf70aOc\nY4aInFe76MEbHrlXVvLDVCJqH5yyB286p8wnn+iP3Csr9Ufu9iruWunLMadytJARYE6laSWnLVTb\ngzc3pwzAI3ciouZSbYvGdE6ZsDDA35/DIImofXGaFo3UlomMBN5913hOmawsYO9eFnciouZSVYE3\nnG5g+XL9XDKtnVOmtbTSl2NO5WghI8CcStNKTluoogdvOradY9qJiGynih686dj2775jK4aICLCt\nB+/QI3hzR+4cIUNEpAyH9OClD1Pbamx7S2ilL8ecytFCRoA5laaVnLZo0yN4Hx/9h6YFBUBV1b3b\neeRORKS8Nu3BA8ZPxbHtRETWaaYHz5OWiIjaTpv24LVw0pJW+nLMqRwtZASYU2layWmLNj2Cl05a\nIiIi+1PFOHgiIjLPaeaiISIi5TRZ4DMyMjBs2DAMHjwY69atM7vNH/7wBwwePBihoaE4deqU4iHb\nklb6csypHC1kBJhTaVrJaQurBb6hoQFLly5FRkYGCgoKkJycjDNnzhhtk5aWhqKiIhQWFmLr1q1Y\nvHixXQPbW25urqMjNAtzKkcLGQHmVJpWctrCaoHPyclBYGAg/P394erqipiYGKSkpBhtk5qairlz\n5wIAHnnkEVRXV+PSpUv2S2xn1dXVjo7QLMypHC1kBJhTaVrJaQurBb68vBw+Pj7yuk6nQ3l5eZPb\nnDe8BBMRETmE1QKvP/u0aaaf8Db3+9SotLTU0RGahTmVo4WMAHMqTSs5bSKsOH78uJg4caK8npCQ\nIBITE422WbRokUhOTpbXhw4dKi5evNjosQICAgT0cxXwi1/84he/mvkVEBBgrUxbZfVEp/DwcBQW\nFqK0tBReXl7YvXs3kpOTjbaZMmUKNm/ejJiYGJw4cQIeHh7o169fo8cqKiqy9lRERKQwqwW+U6dO\n2Lx5MyZOnIiGhgbMnz8fQUFB2LJlCwBg0aJFiIyMRFpaGgIDA9G1a1ds3769TYITEZF1bXYmKxER\ntS27n8nanBOlHKGsrAxPPvkkHnjgAYSEhGDTpk0AgGvXrmH8+PEYMmQIJkyYoJqhVA0NDRg5ciQm\nT54MQJ05q6urMX36dAQFBSE4OBhfffWVKnOuXbsWDzzwAIYPH47Y2Fjcvn1bFTl/+9vfol+/fhg+\nfLh8m7Vca9euxeDBgzFs2DAcOHDAYRmXL1+OoKAghIaGYurUqaipqXFoRks5JRs2bECHDh1w7do1\n1eZ85513EBQUhJCQEKxYsaL1OVvdvW+GO3fuiICAAFFSUiLq6upEaGioKCgosOdTNtuFCxfEqVOn\nhBBCXL9+XQwZMkQUFBSI5cuXi3Xr1gkhhEhMTBQrVqxwZEzZhg0bRGxsrJg8ebIQQqgy55w5c8R7\n770nhBCivr5eVFdXqy5nSUmJGDhwoLh165YQQogZM2aIpKQkVeQ8cuSIOHnypAgJCZFvs5QrPz9f\nhIaGirq6OlFSUiICAgJEQ0ODQzIeOHBAfu4VK1Y4PKOlnEII8eOPP4qJEycKf39/cfXqVVXmPHz4\nsPjVr34l6urqhBBCXL58udU57Vrgv/zyS6NROGvXrhVr166151O22nPPPScOHjxoNArowoULYujQ\noQ5OJkRZWZl4+umnxeHDh8Wzzz4rhBCqy1ldXS0GDhzY6Ha15bx69aoYMmSIuHbtmqivrxfPPvus\nOHDggGpylpSUGP2yW8plOqJt4sSJ4vjx4w7JaGjPnj1i1qxZDs8ohPmc06dPF3l5eUYFXm05o6Oj\nRWZmZqPtWpPTri2a5pwopQalpaU4deoUHnnkEVy6dEkeBdSvXz9VnJW7bNkyrF+/Hh063PtxqS1n\nSUkJ+vTpg3nz5uHBBx/EggUL8NNPP6kuZ69evfCnP/0Jvr6+8PLygoeHB8aPH6+6nBJLuSoqKqDT\n6eTt1PK7tW3bNkRGRgJQX8aUlBTodDqMGDHC6Ha15SwsLMSRI0cwevRoRERE4JtvvgHQupx2LfBa\nOOHpxo0bmDZtGt5++210797d6D4XFxeHv4Z9+/ahb9++GDlypMUpQ9WQ886dOzh58iR+//vf4+TJ\nk+jatSsSExONtlFDzuLiYmzcuBGlpaWoqKjAjRs38MEHHxhto4ac5jSVy9GZ33jjDdx3332IjY21\nuI2jMt68eRMJCQl47bXX5Nss/T4Bjt2Xd+7cQVVVFU6cOIH169djxowZFrdtKqddC7y3tzfKysrk\n9bKyMqN3IEerr6/HtGnTMHv2bERFRQHQHyVdvHgRAHDhwgX07dvXkRHx5ZdfIjU1FQMHDsTMmTNx\n+PBhzJ49W3U5dToddDodHn74YQDA9OnTcfLkSfTv319VOb/55hs8+uij6N27Nzp16oSpU6fi+PHj\nqsspsfRzNv3dOn/+PLy9vR2SEQCSkpKQlpaGnTt3yrepKWNxcTFKS0sRGhqKgQMH4vz583jooYdw\n6dIlVeUE9L9LU6dOBQA8/PDD6NChAyorK1uV064F3vBEqbq6OuzevRtTpkyx51M2mxAC8+fPR3Bw\nMOLj4+Xbp0yZgvfffx8A8P7778uF31ESEhJQVlaGkpISfPjhh3jqqaewY8cO1eXs378/fHx8cPbs\nWQDAoUOH8MADD2Dy5Mmqyjls2DCcOHECP//8M4QQOHToEIKDg1WXU2Lp5zxlyhR8+OGHqKurQ0lJ\nCQoLCzFq1CiHZMzIyMD69euRkpKC+++/3yi7WjIOHz4cly5dQklJCUpKSqDT6XDy5En069dPVTkB\nICoqCocPHwYAnD17FnV1dfD09GxdTmU+JrAsLS1NDBkyRAQEBIiEhAR7P12zffHFF8LFxUWEhoaK\nsLAwERYWJtLT08XVq1fF008/LQYPHizGjx8vqqqqHB1Vlp2dLY+iUWPO3NxcER4eLkaMGCGef/55\nUV1drcqc69atE8HBwSIkJETMmTNH1NXVqSJnTEyMGDBggHB1dRU6nU5s27bNaq433nhDBAQEiKFD\nh4qMjAyHZHzvvfdEYGCg8PX1lX+PFi9e7NCMhjnvu+8+eV8aGjhwoPwhq9py1tXVid/85jciJCRE\nPPjggyIrK6vVOXmiExGRk+Il+4iInBQLPBGRk2KBJyJyUizwREROigWeiMhJscATETkpFngiIifF\nAk9E5KT+H7VvcK1x7/gAAAAAAElFTkSuQmCC\n", "text": [ "" ] } ], "prompt_number": 19 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some helper functions to generate file names:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def gen_tot_sim_name(Sim_names):\n", " \"\"\"Conatenates with '+' the ID of strings in `Sim_names`.\n", " Assumes all the string be the same except for\n", " a one-digit ID.\n", " Example: gen_tot_sim_name(['_ID0','_ID1']) returns '_ID0+1'\n", " \"\"\"\n", " IDs = []\n", " for s in Sim_names:\n", " n = s.find('_ID') + 3\n", " IDs.append(s[n])\n", " name = Sim_names[0][:n] + '+'.join(IDs) + Sim_names[0][n+1:]\n", " return name" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": [ "gen_tot_sim_name(['pippo_ID0_pluto','pippo_ID1_pluto', 'pippo_ID2_pluto'])" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 19, "text": [ "'pippo_ID0+1+2_pluto'" ] } ], "prompt_number": 19 }, { "cell_type": "code", "collapsed": false, "input": [ "def gen_ph_times_name(em, bg, sim_name, t_tot):\n", " \"\"\"Generate a name for a timestamp array\n", " \"\"\"\n", " EM_str = \"%04d\" % (em/1e3)\n", " BG_str = \"%04.1f\" % (bg/1e3)\n", " fname = \"ph_times_{t}s_{sim}_EM{em}kHz_BG{bg}kHz.npy\".format(\n", " em=EM_str, bg=BG_str, t=t_tot, sim=sim_name)\n", " return fname" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "gen_ph_times_name(5e5, 3e3, 'pippo', 10.)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 21, "text": [ "'ph_times_10.0s_pippo_EM0500kHz_BG03.0kHz.npy'" ] } ], "prompt_number": 21 }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now the **\"big loop\"** to generate timestamps for multiple:\n", "\n", "- background rates\n", "- max emission rates\n", "\n", "This will also merge different simulation IDs:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#%qtconsole" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 22 }, { "cell_type": "code", "collapsed": false, "input": [ "%%timeit -n1 -r1\n", "IDs = [1, 2, 3, 4, 5, 6]\n", "for bg in BG:\n", " for em in EM:\n", " ph_list = []\n", " t_tot_tot = 0\n", " Sim_name = []\n", " for ID in IDs:\n", " dview['ID'] = ID\n", " %px S = load_sim_id(ID=ID, glob_str=\"*t_max10.0s*\", dir_=SIM_DATA_DIR)\n", "\n", " ph, t_tot, sim_name = parallel_gen_timetag(dview, \n", " max_em_rate=em, bg_rate=bg)\n", " \n", " ph_list.append(ph)\n", " t_tot_tot += t_tot\n", " Sim_name.append(sim_name)\n", " \n", " # Use last sim `t_tot` to set time_block\n", " ph_times = merge_ph_times(ph_list, time_block=t_tot)\n", " \n", " tot_sim_name = gen_tot_sim_name(Sim_name)\n", " fname = gen_ph_times_name(em, bg, tot_sim_name, t_tot_tot)\n", " \n", " ph_times.dump(SIM_PH_DIR+fname)\n", " del ph_times" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "plt.hist(ph_times, bins=arange(0,0.5,1e-3), histtype='step');" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Loading the timestamps" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> This is a quick example. For a better description see the next notebook: \n", "> **3. Generate and export smFRET data**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Specify here the parameters of the simulation to load:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "d_EM_kHz = 400.\n", "d_BG_kHz = 4\n", "a_EM_kHz = 200\n", "a_BG_kHz = 2\n", "FRET_val = 1.*a_EM_kHz/(a_EM_kHz+d_EM_kHz)\n", "print \"Simulated FRET value: %.2f\" % FRET_val" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# These are used for the file name\n", "ID = '0+1+2'\n", "t_tot = '0.6'\n", "\n", "# These are metadata associated to the timestamps\n", "t_step = 0.5e-6\n", "clk_p = t_step/32. # with t_step=0.5us -> 156.25 ns" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we compute the file name from the parameter:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "d_EM_kHz_str = \"%04d\" % d_EM_kHz\n", "a_EM_kHz_str = \"%04d\" % a_EM_kHz\n", "d_BG_kHz_str = \"%04.1f\" % d_BG_kHz\n", "a_BG_kHz_str = \"%04.1f\" % d_BG_kHz\n", "\n", "print \"D: EM %s BG %s \"%(d_EM_kHz_str,d_BG_kHz_str)\n", "print \"A: EM %s BG %s \"%(a_EM_kHz_str,a_BG_kHz_str)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "fname_d = \"ph_times_{t_tot}s_D1.2e-11_10P_21pM_step0.5us_ID{ID}_EM{em}kHz_BG{bg}kHz.npy\".format(em=d_EM_kHz_str, bg=d_BG_kHz_str, t_tot=t_tot, ID=ID)\n", "fname_a = \"ph_times_{t_tot}s_D1.2e-11_10P_21pM_step0.5us_ID{ID}_EM{em}kHz_BG{bg}kHz.npy\".format(em=a_EM_kHz_str, bg=a_BG_kHz_str, t_tot=t_tot, ID=ID)\n", "print fname_d\n", "print fname_a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "SIM_PH_DIR" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Load the timestamps arrays:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ph_times_d = numpy.load(SIM_PH_DIR+fname_d)\n", "ph_times_a = numpy.load(SIM_PH_DIR+fname_a)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "ph_times, a_em = merge_DA_ph_times(ph_times_d, ph_times_a)\n", "ph_times_int = (ph_times/clk_p).astype('int64')" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now the timestamp arrays can be analized. For example you can perform a bust search \n", "and build a FRET histogram." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "from IPython.core.display import HTML\n", "def css_styling():\n", " styles = open(\"./styles/custom2.css\", \"r\").read()\n", " return HTML(styles)\n", "css_styling()" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n" ], "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "" ] } ], "prompt_number": 3 } ], "metadata": {} } ] }