{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial about fluopy - Cy5 in dSTORM simulation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we outline a simulation procedure for typcial Cy5 fluorophore under dSTORM conditions." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "from pprint import pprint\n", "\n", "%matplotlib inline\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "import fluopy\n", "import fluopy.analysis as an\n", "import fluopy.blinking as bl\n", "import fluopy.emissions as em\n", "import fluopy.fcs as fcs_p\n", "import fluopy.figure as fi\n", "import fluopy.fluorophores as fl\n", "import fluopy.formulas as fo\n", "import fluopy.miscellaneous as mi\n", "import fluopy.prediction as pr\n", "import fluopy.simulation as si\n", "import fluopy.transitions as tr" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "fluopy.__version__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rng = np.random.default_rng(seed=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define the fluorophore system" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fluorophore = fl.Fluorophore(name=\"cy5_dna\", position=[0, 0])\n", "fluorophore_system = fl.FluorophoreSystem(fluorophores=[fluorophore])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pprint(vars(fluorophore_system))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define the transition set" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "transitions = fluorophore_system.load_transitions(\n", " summarize=True,\n", " irradiance=2,\n", " wavelength=640,\n", " bleaching=False,\n", " energy_transfer=False,\n", " dstorm=True,\n", ")\n", "transition_set = tr.TransitionSet(transitions, fluorophore_system)\n", "transition_set = transition_set.remove_energy_transfers()\n", "transition_set.finalize()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "transition_set.plot(graph_type=\"shell\", colors=None, scale=1);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "transition_set.transition_df" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "for key, value in transition_set.transitions.items():\n", " pprint(key)\n", " pprint(value)\n", " print(\"---\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Make a prediction" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "prediction = pr.Prediction(transition_set)\n", "prediction" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prediction.plot_frequency_transitions(scale=0.5)\n", "prediction.plot_frequency_states(scale=0.5)\n", "prediction.plot_mean_lifetimes(scale=0.5)\n", "prediction.plot_mean_transition_times(scale=0.5)\n", "prediction.plot_state_occupations(scale=0.5)\n", "prediction.plot_transition_time_distributions(\n", " fluorophore=\"cy5_dna\", transition_id=0, scale=0.5\n", ");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run a simulation" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "simulation = si.Simulation(transition_set)\n", "simulation" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "%%time\n", "# basic simulation run for a given number of steps (size)\n", "simulation.run(start_at=None, size=1e6, end_time=None, seed=rng, use_memmap=None)\n", "mi.print_class(simulation)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "# simulate until it reaches given end_time\n", "simulation.run(start_at=None, size=1e6, end_time=500, seed=rng, use_memmap=None)\n", "mi.print_class(simulation)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "%%time\n", "# if a lot of steps have to be carried out, the arrays may become too large for RAM\n", "# in that case, use memory maps store on drive\n", "simulation.run(start_at=None, size=1e6, end_time=None, seed=rng,\n", " use_memmap='')\n", "mi.print_class(simulation)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Analyze the simulation" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "analysis = an.Analysis(simulation=simulation)\n", "mi.print_class(analysis)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "analysis.get_fluorescence_lifetimes(fluorophore=\"cy5_dna\")\n", "analysis.get_emitting_transition_lifetimes(fluorophore=\"cy5_dna\")\n", "\n", "analysis.plot_frequency_transitions(scale=0.5, prediction=prediction)\n", "analysis.plot_frequency_states(scale=0.5, prediction=prediction)\n", "analysis.plot_mean_transition_times(scale=0.5, prediction=prediction)\n", "analysis.plot_mean_lifetimes(scale=0.5, prediction=prediction)\n", "analysis.plot_state_occupations(scale=0.5, prediction=prediction)\n", "analysis.plot_lifetime_distributions(\n", " scale=0.5, prediction=prediction, fluorophore=\"cy5_dna\", state_identity=1\n", ")\n", "analysis.plot_transition_time_distributions(\n", " scale=0.5, prediction=prediction, fluorophore=\"cy5_dna\", transition_id=0\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simulation of experimentally observable (photons per frames) only" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Extract photon emission events from simulation" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "emissions = em.Emissions(frame_time=\"5ms\", seed=rng, bandpass=(600, 800))\n", "emissions.extract(simulation=simulation)\n", "emissions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Simulate photon emission events" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "%%time\n", "emissions = em.Emissions(frame_time=\"5ms\", seed=rng, bandpass=(600, 800))\n", "emissions.simulate(transition_set=transition_set, store_time_points=True, frames=2000)\n", "emissions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Correct for detection efficiency and noise contributions:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "emissions.add_photon_collection_objective(p=0.1, seed=rng) # 1.\n", "emissions.add_quantum_efficiency(p=0.9, seed=rng) # 3.1.\n", "emissions.add_poisson_noise(\n", " rate=0.05, seed=rng\n", ") # 3.2. (dark noise), note the frame time\n", "emissions.add_emccd_gain(emccd_gain=10, seed=rng) # 4.\n", "emissions.add_gaussian_noise(mean=10, std=1, seed=rng) # 5. (readout noise)\n", "emissions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "emissions = em.Emissions(frame_time=\"5ms\", seed=rng, bandpass=(660, 700))\n", "emissions.extract(simulation=approximation) " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 2.\n", "# at this point, the bandpass filter was applied\n", "# yet, the effect of photon collection by the objective is missing\n", "# the order is not relevant for two consecutive binomial distributions\n", "# it is more convenient to apply the bandpass first because it needs the\n", "# information about the emitting fluorophore whereas all the other effects are\n", "# roughly wavelength independent\n", "p_photon_collection = fo.calculate_photon_collection_rate(NA=1.45, n1=1.51)\n", "emissions.add_photon_collection_objective(p=p_photon_collection) # 1.\n", "emissions.add_quantum_efficiency(p=0.9) # 4.1.\n", "emissions.add_transmittance(p=0.99) # 3 (depending on number of components of optical\n", "# path, may be applied multiple times)\n", "emissions.add_poisson_noise(rate=0.05) # 4.2. (dark noise), note the frame time\n", "emissions.add_emccd_gain(emccd_gain=10) # 5. (+ multiplicative noise)\n", "emissions.add_gaussian_noise(mean=10, std=1, seed=rng) # 6. (readout noise)\n", "# CIC (spurious noise) neglected since low probability to happen in the pixels of\n", "# interest\n", "emissions.apply_threshold(threshold=100) # 7 (thresholding)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "mi.print_class(emissions, \"Emissions\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "emissions.plot_cumulative_events(scale=1)\n", "emissions.plot_histogram(scale=1)\n", "emissions.plot_time_series(scale=1)\n", "\n", "# to save the time_series and time_points\n", "# emissions.save(path='', name_extension='test')\n", "\n", "# to load time_series and time_points\n", "# emissions.load(path='', name_extension='test')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simulation of pulsed excitation" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "emissions_tcspc = em.Emissions(frame_time=\"1ms\", seed=rng, bandpass=None)\n", "lifetimes_DA, lifetimes_D, lifetimes_all, simulation_object = emissions_tcspc.tcspc(\n", " transition_set=transition_set,\n", " number_pulses=5e5,\n", " pulse_duration=1e-11,\n", " time_between_pulses=1e-7,\n", " excitation_rates={\"cy5_dna\": 1e11},\n", " size=1e5,\n", " store_time_points=True,\n", " # details = True\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "emissions_tcspc.plot_time_series()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fi.universal_figure(\n", " type_=\"hist\", data=lifetimes_all, ylabel=\"PD\", density=True, xlabel=\"Lifetime (s)\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fluorescence correlation spectroscopy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Observed fluorescence emission events can be analyzed by a correlation analysis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fcs = fcs_p.FCS(emissions)\n", "list(vars(fcs).keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Autocorrelation of time points" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "fcs.autocorrelate_time_points(\n", " exp_min=-20, exp_max=-6, points_per_base=4, base=4, normalize=True\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mi.print_class(fcs)\n", "fcs.plot(normalize_to=None, unit=\"s\", scale=1);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Autocorrelation of time series" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fcs.autocorrelate_time_series(log=True, m=4, normalize=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fcs.plot(normalize_to=None, unit=\"s\", scale=1);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# some fcs fits are available:\n", "# fcs_predict = fcs_p.fit_dark(tau, dark_lifetime, dark_occupation)\n", "# fcs_predict = fcs_p.fit_antibunching(tau, excitation_rate, s1_lifetime)\n", "# fcs_predict = fcs_p.fit_triplet_cis(tau, k_isc, k_T, k_01, k_10, k_iso, k_biso_eff)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Antibunching" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, you can focus on fast time scales in a linear scale and observe antibunching." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# sensible to tau_max and bin_width, see coincidence notebook\n", "hist, bins = fcs_p.coincidence(\n", " emissions.event_time_points[: int(2e5)], tau_max=1e-8, bin_width=1e-10, seed=rng\n", ")\n", "fi.universal_figure(\n", " type_=\"line\",\n", " data=[bins, hist],\n", " xlabel=r\"$\\tau$ (s)\",\n", " ylabel=r\"$g^{(2)}(\\tau)$\",\n", " scale=1,\n", ");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Blinking" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Emissions from a short simulation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We limit the dataset to 2000 frames for illustration purposes." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "emissions = em.Emissions(frame_time=\"10ms\", seed=rng, bandpass=None)\n", "emissions.simulate(\n", " transition_set=transition_set, store_time_points=False, frames=10_000\n", ")\n", "emissions" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "threshold: int = 1000" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "emissions.plot_time_series(scale=1)\n", "plt.hlines(threshold, xmin=0, xmax=100)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "blinks = bl.Blinking(emissions, threshold=threshold)\n", "blinks" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mi.print_class(blinks)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# plot a histogram of OFF times\n", "blinks.plot(\n", " mode=\"off_histogram\", density=True, display_mean=True, as_time=\"s\", scale=0.5\n", ")\n", "\n", "# plot a histogram of ON times\n", "blinks.plot(\n", " mode=\"on_histogram\", density=True, display_mean=True, as_time=\"ms\", scale=0.5\n", ")\n", "\n", "# plot a time series of OFF times\n", "blinks.plot(mode=\"off_frame_series\", scale=0.5)\n", "\n", "# plot a time series of ON times\n", "blinks.plot(mode=\"on_frame_series\", scale=0.5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# to get information of the photophysical (not analytical) OFF of each fluorophore, use\n", "on_off_times_photophys, on_off_values_photophys = bl.get_off_statistics(\n", " simulation=simulation, index=0\n", ")\n", "\n", "# to get the analytical OFF statistics as the same view, use\n", "on_off_times_analytic, on_off_values_analytic = bl.get_analytical_off_statistics(\n", " off_frames=blinks.off_periods_frames,\n", " off_periods=blinks.off_periods,\n", " on_frames=blinks.on_periods_frames,\n", " frame_time=blinks.emissions.parameters[\"frame_time\"],\n", ")\n", "\n", "# plot the photophysical OFF statistics\n", "bl.plot_off_statistics(\n", " on_off_times_photophys,\n", " on_off_values_photophys,\n", " scale=1,\n", " title=\"photophysical OFF\",\n", ")\n", "# plot the analytical OFF statistics (no differentiation between fluorophores)\n", "bl.plot_off_statistics(\n", " on_off_times_analytic, on_off_values_analytic, scale=1, title=\"analytical OFF\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Emissions from the long simulation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Get more detailed information from a complete simulation:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "emissions = em.Emissions(frame_time=\"10ms\", seed=rng, bandpass=None)\n", "emissions.extract(simulation=simulation)\n", "emissions" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "blinks = bl.Blinking(emissions, threshold=threshold)\n", "blinks" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mi.print_class(blinks)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# plot a histogram of OFF times\n", "blinks.plot(\n", " mode=\"off_histogram\", density=True, display_mean=True, as_time=\"s\", scale=0.5\n", ")\n", "\n", "# plot a histogram of ON times\n", "blinks.plot(\n", " mode=\"on_histogram\", density=True, display_mean=True, as_time=\"ms\", scale=0.5\n", ")\n", "\n", "# plot a time series of OFF times\n", "blinks.plot(mode=\"off_frame_series\", scale=0.5)\n", "\n", "# plot a time series of ON times\n", "blinks.plot(mode=\"on_frame_series\", scale=0.5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# to get information of the photophysical (not analytical) OFF of each fluorophore, use\n", "on_off_times_photophys, on_off_values_photophys = bl.get_off_statistics(\n", " simulation=simulation, index=0\n", ")\n", "\n", "# to get the analytical OFF statistics as the same view, use\n", "on_off_times_analytic, on_off_values_analytic = bl.get_analytical_off_statistics(\n", " off_frames=blinks.off_periods_frames,\n", " off_periods=blinks.off_periods,\n", " on_frames=blinks.on_periods_frames,\n", " frame_time=blinks.emissions.parameters[\"frame_time\"],\n", ")\n", "\n", "# plot the photophysical OFF statistics\n", "bl.plot_off_statistics(\n", " on_off_times_photophys,\n", " on_off_values_photophys,\n", " scale=1,\n", " title=\"photophysical OFF\",\n", ")\n", "# plot the analytical OFF statistics (no differentiation between fluorophores)\n", "bl.plot_off_statistics(\n", " on_off_times_analytic, on_off_values_analytic, scale=0.5, title=\"analytical OFF\"\n", ")" ] } ], "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.14.4" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }