├── .gitattributes ├── .github └── workflows │ └── build_test_notebooks.yml ├── .gitignore ├── Bexvar └── Bexvar tutorial.ipynb ├── Bispectrum └── bispectrum_tutorial.ipynb ├── CrossCorrelation └── cross_correlation_notebook.ipynb ├── Crossspectrum └── Crossspectrum_tutorial.ipynb ├── DataQuickLook └── Quicklook NuSTAR data with Stingray.ipynb ├── Deadtime ├── Dead time model in Stingray.ipynb └── FAD correction in Stingray.ipynb ├── Debug └── New normalization formulas are consistent.ipynb ├── DynamicalPowerspectrum ├── DynamicalPowerspectrum_tutorial_[fake_data].ipynb └── DynamicalPowerspectrum_tutorial_[real_data].ipynb ├── EventList ├── EventList Tutorial.ipynb └── events.fits ├── LICENSE ├── Lightcurve ├── Analyze light curves chunk by chunk - an example.ipynb ├── Lightcurve tutorial.ipynb ├── lightcurve.png └── photon_arrivals.txt ├── LombScargle ├── LombScargleCrossspectrum_tutorial.ipynb ├── LombScarglePowerspectrum_tutorial.ipynb └── Very slow variability with Lomb-Scargle methods.ipynb ├── Modeling ├── GP_Modeling │ └── GP_modeling_tutorial.ipynb └── ModelingExamples.ipynb ├── Multitaper ├── koi2133.csv └── multitaper_example.ipynb ├── Performance └── Dealing with large data files.ipynb ├── Powerspectrum └── Powerspectrum_tutorial.ipynb ├── Pulsar ├── Phase Dispersion Minimization.ipynb └── Pulsar search with epoch folding and Z squared.ipynb ├── README.rst ├── Simulator ├── Concepts │ ├── Inverse Transform Sampling.ipynb │ ├── PowerLaw Spectrum.ipynb │ ├── Simulate Event Lists With Inverse CDF.ipynb │ └── Simulator.ipynb ├── Lag Analysis.ipynb ├── Power Spectral Models.ipynb └── Simulator Tutorial.ipynb ├── Spectral Timing ├── Spectral Timing Exploration.ipynb ├── epoch_0_data.csv └── wang_data.csv ├── StingrayTimeseries ├── StingrayTimeseries Tutorial.ipynb └── Working with weights and polarization.ipynb ├── Transfer Functions ├── 2d.png ├── Data Preparation.ipynb ├── TransferFunction Tutorial.ipynb └── intensity.txt ├── Window Functions └── window_functions.ipynb └── requirements.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # To ignore prompt numbers and cell output when adding any notebook. 2 | # See https://github.com/adrn/DropOutput for configuration. 3 | *.ipynb filter=clean_ipynb 4 | -------------------------------------------------------------------------------- /.github/workflows/build_test_notebooks.yml: -------------------------------------------------------------------------------- 1 | name: Build & Test Notebooks 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build-notebooks: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout stingray repo 18 | uses: actions/checkout@v4 19 | with: 20 | repository: StingraySoftware/stingray 21 | path: ./stingray 22 | submodules: recursive 23 | 24 | # This step gets the latest commit of the PR or the pushed commit and checks out the PR version of the notebooks 25 | - name: Get latest commit of the PR or pushed commit and Checkout PR version of Notebooks 26 | run: | 27 | 28 | # If the event is a pull request, fetch the PR SHA 29 | 30 | if [ "${{ github.event_name }}" == "pull_request" ]; then 31 | echo "PR event detected. Fetching PR SHA..." 32 | PR_SHA=$(curl -s 'https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}' | jq -r .head.sha) 33 | if [ "$PR_SHA" == "null" ]; then 34 | echo "::error::Failed to get PR SHA" 35 | exit 1 36 | fi 37 | echo "commit=$PR_SHA" >> $GITHUB_ENV 38 | cd ./stingray/docs/notebooks # Change to the submodule directory 39 | git fetch origin $PR_SHA:pr_temp 40 | git checkout pr_temp 41 | 42 | # If the event is a push, use the pushed commit SHA 43 | 44 | else 45 | echo "Push event detected. Using pushed commit SHA..." 46 | echo "commit=${{ github.sha }}" >> $GITHUB_ENV 47 | cd ./stingray/docs/notebooks # Change to the submodule directory 48 | pwd 49 | git fetch origin ${{ github.sha }}:pr_temp 50 | git checkout pr_temp 51 | fi 52 | 53 | # This step verifies that the submodule has been updated 54 | - name: Verify submodule update 55 | run: | 56 | cd ./stingray/docs/notebooks 57 | git log -1 58 | 59 | - name: Setup Python 60 | uses: actions/setup-python@v5 61 | with: 62 | python-version: '3.10' 63 | 64 | - name: Install pandoc and additional dependencies 65 | run: | 66 | sudo apt-get update 67 | sudo apt-get install -y pandoc fonts-freefont-ttf 68 | pip install sphinx sphinx-astropy tox 69 | 70 | - name: Install Stingray 71 | run: | 72 | pip install -e ./stingray 73 | 74 | - name: Run Build Docs 75 | run: | 76 | cd ./stingray 77 | tox -e build_docs -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | .DS_Store 3 | .vscode 4 | *.png 5 | *.jpg 6 | *.jpeg -------------------------------------------------------------------------------- /Bexvar/Bexvar tutorial.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Baysian Excess Variance (Bexvar)" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "The Bayesian Excess Variance (bexvar) is a statistical measurement of variability in Poisson-distributed light curves. Bexvar is a Bayesian formulation of excess variance. A brief summary of theoretical understanding of bexvar is given at the end of this tutorial. " 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "The `bexvar()` method implemented in Stingray, provides posterior samples of bexvar given a light curve data as input parameters. \n", 22 | "This tutorial is intended to give a demonstration of How to use `bexvar()` method implemented in Stingray.\n", 23 | "The method takes following input parameters. (Given here for completeness)" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "\n", 31 | "  ```time``` : iterable, `:class:numpy.array` or `:class:List` of floats, optional, default ``None`` \n", 32 | "     A list or array of time stamps for a light curve. \n", 33 | "  `time_del` : iterable, `:class:numpy.array` or `:class:List` of floats \n", 34 | "    A list or array of time intervals for each bin of light curve. \n", 35 | "  `src_counts` : iterable, `:class:numpy.array` or `:class:List` of floats \n", 36 | "    A list or array of counts observed from source region in each bin. \n", 37 | "  `bg_counts` : iterable, `:class:numpy.array` or `:class:List` of floats, optional, default ``None`` \n", 38 | "    A list or array of counts observed from background region in each bin. If ``None`` \n", 39 | "    we assume it as a numpy array of zeros, of length equal to length of ``src_counts``. \n", 40 | "  `bg_ratio` : iterable, `:class:numpy.array` or `:class:List` of floats, optional, default ``None`` \n", 41 | "    A list or array of source region area to background region area ratio in each bin. \n", 42 | "    If ``None`` we assume it as a numpy array of ones, of length equal to the length of \n", 43 | "    ``src_counts``. \n", 44 | "  `frac_exp` : iterable, `:class:numpy.array` or `:class:List` of floats, optional, default ``None`` \n", 45 | "    A list or array of fractional exposers in each bin. If ``None`` we assume it as \n", 46 | "    a numpy array of ones, of length equal to length of ``src_counts``. \n" 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "Let us start by importing the bexvar module" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 13, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "from stingray import bexvar" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "Now consider an example dataset." 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 14, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "import numpy as np\n", 79 | "\n", 80 | "time = np.arange(0,8)*100\n", 81 | "counts= np.array([106, 87, 115, 148, 43, 129, 204, 87])\n", 82 | "time_del = np.ones(np.size(time))*100\n", 83 | "bg_counts = np.array([722, 696, 701, 721, 722, 703, 722, 695])\n", 84 | "bg_ratio = np.array([0.01474, 0.01158, 0.01214, 0.01308, 0.010877, 0.01177, 0.01058, 0.01138])\n", 85 | "frac_exp = np.array([0.37416, 0.21713, 0.37937, 0.50140, 0.11617, 0.39221, 0.64275, 0.31160])" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "Call bexvar function to get posterior distribution of bexvar." 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "The `bexvar()` method uses [UltraNest](https://johannesbuchner.github.io/UltraNest/) python package to obtain the posteriors of bexvar. Ultranest gives a brief summary of log evidence (log(z)) and its uncertainties, and the parameter constraints. \n" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 16, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "name": "stdout", 109 | "output_type": "stream", 110 | "text": [ 111 | "preparing time bin posteriors...\n", 112 | "running bexvar...\n", 113 | "[ultranest] Sampling 400 live points from prior ...\n", 114 | "[ultranest] Explored until L=-2e+01 [-20.4040..-20.4040]*| it/evals=3622/5046 eff=77.9595% N=400 \n", 115 | "[ultranest] Likelihood function evaluations: 5051\n", 116 | "[ultranest] logZ = -24.86 +- 0.0784\n", 117 | "[ultranest] Effective samples strategy satisfied (ESS = 1590.2, need >400)\n", 118 | "[ultranest] Posterior uncertainty strategy is satisfied (KL: 0.47+-0.06 nat, need <0.50 nat)\n", 119 | "[ultranest] Evidency uncertainty strategy is satisfied (dlogz=0.08, need <0.5)\n", 120 | "[ultranest] logZ error budget: single: 0.09 bs:0.08 tail:0.01 total:0.08 required:<0.50\n", 121 | "[ultranest] done iterating.\n", 122 | "\n", 123 | "logZ = -24.856 +- 0.156\n", 124 | " single instance: logZ = -24.856 +- 0.093\n", 125 | " bootstrapped : logZ = -24.856 +- 0.156\n", 126 | " tail : logZ = +- 0.010\n", 127 | "insert order U test : converged: True correlation: inf iterations\n", 128 | "\n", 129 | " logmean : 0.350 │ ▁ ▁ ▁▁▁▁▁▁▁▁▂▃▄▅▆▇▇▇▆▅▄▃▂▁▁▁▁▁▁▁ ▁ ▁▁ │0.575 0.461 +- 0.020\n", 130 | " logsigma : 0.010 │▇▅▄▃▂▂▂▁▁▁▁▁▁▁▁▁▁▁ ▁▁▁▁ ▁ ▁ │0.227 0.028 +- 0.018\n", 131 | "\n", 132 | "running bexvar... done\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "\n", 138 | " bexvar_distribution = bexvar.bexvar(time=time, src_counts=counts, time_del=time_del, frac_exp=frac_exp,\n", 139 | " bg_counts=bg_counts, bg_ratio=bg_ratio)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": {}, 145 | "source": [ 146 | "We can then plot the samples to visualize the posterior distribution of bexvar." 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 5, 152 | "metadata": {}, 153 | "outputs": [ 154 | { 155 | "data": { 156 | "image/png": "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", 157 | "text/plain": [ 158 | "
" 159 | ] 160 | }, 161 | "metadata": { 162 | "needs_background": "light" 163 | }, 164 | "output_type": "display_data" 165 | } 166 | ], 167 | "source": [ 168 | "import matplotlib.pyplot as plt\n", 169 | "%matplotlib inline\n", 170 | "plt.hist(bexvar_distribution, bins=20)\n", 171 | "plt.ylabel(\"# of samples\")\n", 172 | "plt.xlabel(r\"$\\sigma_{bexvar}$\")\n", 173 | "plt.show()" 174 | ] 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": {}, 179 | "source": [ 180 | "If the light curve is intrinsically variable, then the posterior distribution of bexvar should exclude low values. Users can compute \n", 181 | "the lower 10% quantile of the posterior, and use it as a variability indicator (see [Buchner et al. (2021)](https://arxiv.org/abs/2106.14529))." 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "metadata": {}, 187 | "source": [ 188 | "The method uses fractional exposers (`frac_exp`) in each bin to compute the count rates (i.e.$~\\scriptstyle{R_i = C_i/(\\Delta{t_i}\\times f_i)}$). In its current form it only considers time bins with `frac_exp` < 1. The `bg_ratio` parameter is used to scale the `bg_counts` to estimate counts in source region. The `bg_count`, `bg_ratio` and `frac_exp` are optional parameters, if they are not provided, the method defines default values for them as described in documentation. " 189 | ] 190 | }, 191 | { 192 | "cell_type": "markdown", 193 | "metadata": {}, 194 | "source": [ 195 | "Let us see an example to get bexvar distribution without these optional parameters." 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 3, 201 | "metadata": {}, 202 | "outputs": [ 203 | { 204 | "name": "stdout", 205 | "output_type": "stream", 206 | "text": [ 207 | "preparing time bin posteriors...\n", 208 | "running bexvar...\n", 209 | "[ultranest] Sampling 400 live points from prior ...\n", 210 | "[ultranest] Explored until L=-4e+01 [-36.8486..-36.8486]*| it/evals=3615/5101 eff=76.8985% N=400 \n", 211 | "[ultranest] Likelihood function evaluations: 5125\n", 212 | "[ultranest] logZ = -41.34 +- 0.09729\n", 213 | "[ultranest] Effective samples strategy satisfied (ESS = 1692.4, need >400)\n", 214 | "[ultranest] Posterior uncertainty strategy is satisfied (KL: 0.46+-0.06 nat, need <0.50 nat)\n", 215 | "[ultranest] Evidency uncertainty strategy is satisfied (dlogz=0.10, need <0.5)\n", 216 | "[ultranest] logZ error budget: single: 0.09 bs:0.10 tail:0.01 total:0.10 required:<0.50\n", 217 | "[ultranest] done iterating.\n", 218 | "\n", 219 | "logZ = -41.331 +- 0.174\n", 220 | " single instance: logZ = -41.331 +- 0.092\n", 221 | " bootstrapped : logZ = -41.335 +- 0.174\n", 222 | " tail : logZ = +- 0.010\n", 223 | "insert order U test : converged: True correlation: inf iterations\n", 224 | "\n", 225 | " logmean : -0.517│ ▁ ▁ ▁▁▁▁▁▁▁▁▁▁▂▂▃▄▆▇▇▆▅▄▃▂▁▁▁▁▁▁▁▁▁ │0.383 0.020 +- 0.081\n", 226 | " logsigma : 0.029 │ ▁▂▆▇▇▅▃▂▂▁▁▁▁▁▁▁▁ ▁▁▁▁▁ ▁ ▁ │1.236 0.213 +- 0.074\n", 227 | "\n", 228 | "running bexvar... done\n" 229 | ] 230 | } 231 | ], 232 | "source": [ 233 | "import numpy as np\n", 234 | "\n", 235 | "time = np.arange(0,8)*100\n", 236 | "counts= np.array([106, 87, 115, 148, 43, 129, 204, 87])\n", 237 | "time_del = np.ones(np.size(time))*100\n", 238 | "\n", 239 | "bexvar_distribution = bexvar.bexvar(time=time, src_counts=counts, time_del=time_del)" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": {}, 245 | "source": [ 246 | "### Bexvar: Theoretical background" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "\n", 254 | "This section provides a theoretical understanding of Bayesian excess variance (bexvar). This is an optional read.\n", 255 | "\n", 256 | "Given a lightcurve data ${\\scriptstyle 𝐷 = (𝑆_1,𝐵_1,~…~,𝑆_𝑁,𝐵_𝑁)}$\n", 257 | " where ($\\scriptstyle{S_i}$) denotes counts obtained from source region and ($\\scriptstyle{B_i}$) denotes counts obtained from background extraction region in $\\scriptstyle{i^{th}}$ time bin.\n", 258 | "If it is assumed that the counts $\\scriptstyle{𝑆_𝑖}$ and $\\scriptstyle{𝐵_𝑖}$ can be expressed as\n", 259 | "Poisson processes. \n", 260 | "$$ \\scriptstyle {𝑆_𝑖 ~ \\sim ~ 𝑃𝑜𝑖𝑠𝑠𝑜𝑛((( 𝑅_𝑆(𝑡_𝑖) ~+~ 𝑅_𝐵(𝑡_𝑖) \\times 𝑟)~×~𝑓_𝑖~\\times~Δ𝑡)}$$\n", 261 | "$$ \\scriptstyle {𝐵_𝑖 ~ \\sim ~ 𝑃𝑜𝑖𝑠𝑠𝑜𝑛(𝑅_𝐵(𝑡_𝑖) × 𝑓_𝑖 × Δ𝑡)}$$\n", 262 | "\n", 263 | "Here, $\\scriptstyle{𝑅_𝑆(𝑡_𝑖)}$ is source count rate and $\\scriptstyle{𝑅_B(𝑡_𝑖)}$ is background count rate in $\\scriptstyle{i^{th}}$ time bin. \n", 264 | "It is further assumed that $\\scriptstyle{𝑅_𝑆(𝑡_𝑖)}$ is distributed according to a log normal distribution, with some unknown parameters (i.e., $\\scriptstyle{log(\\bar{𝑅_{S}})}$, and $\\scriptstyle{\\sigma_{bexvar}}$).\n", 265 | "$$\\scriptstyle{log(𝑅_𝑆(𝑡_𝑖))~\\sim~𝑁𝑜𝑟𝑚𝑎𝑙(log(\\bar{𝑅_𝑆}),~ \\sigma_{𝑏𝑒𝑥𝑣𝑎𝑟})} $$\n", 266 | "\n", 267 | "This $\\sigma_{𝑏𝑒𝑥𝑣𝑎𝑟}$ provides intrinsic variability on log-count rate and it is defined as Bayesian excess variance (bexvar). The posterior distribution of $\\sigma_{𝑏𝑒𝑥𝑣𝑎𝑟}$ can be used to identify intrinsically variable object.\n", 268 | "\n", 269 | "The bexvar() method in Stingray returns posterior samples of $\\scriptstyle{\\sigma_{𝑏𝑒𝑥𝑣𝑎𝑟}}$ given a light curve data.\n", 270 | "The samples are generated following the same prescription given in [Buchner et al. (2021)](https://arxiv.org/abs/2106.14529). The method uses flat, uninformative priors on $\\scriptstyle{log(\\bar{𝑅_𝑆})}$ and $\\scriptstyle{log(\\sigma_{𝑏𝑒𝑥𝑣𝑎𝑟})}$ and obtains the posterior samples using nested sampling Monte Carlo algorithm MLFriends (Buchner [2016](https://link.springer.com/article/10.1007/s11222-014-9512-y),\n", 271 | "[2019](https://arxiv.org/abs/1707.04476)) implemented in the [UltraNest](https://johannesbuchner.github.io/UltraNest/) Python package (Buchner [2021](https://arxiv.org/abs/2101.09604)).\n", 272 | "\n" 273 | ] 274 | } 275 | ], 276 | "metadata": { 277 | "kernelspec": { 278 | "display_name": "Python 3 (ipykernel)", 279 | "language": "python", 280 | "name": "python3" 281 | }, 282 | "language_info": { 283 | "codemirror_mode": { 284 | "name": "ipython", 285 | "version": 3 286 | }, 287 | "file_extension": ".py", 288 | "mimetype": "text/x-python", 289 | "name": "python", 290 | "nbconvert_exporter": "python", 291 | "pygments_lexer": "ipython3", 292 | "version": "3.9.12" 293 | }, 294 | "vscode": { 295 | "interpreter": { 296 | "hash": "f6246b25e200e4c5124e3e61789ac81350562f0761bbcf92ad9e48654207659c" 297 | } 298 | } 299 | }, 300 | "nbformat": 4, 301 | "nbformat_minor": 4 302 | } 303 | -------------------------------------------------------------------------------- /Debug/New normalization formulas are consistent.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "13333de3", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "%load_ext autoreload\n", 11 | "%autoreload 2\n", 12 | "from astropy.table import Table\n", 13 | "import numpy as np\n", 14 | "import tqdm" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "id": "ca505aeb", 20 | "metadata": {}, 21 | "source": [ 22 | "# Verify that old and new normalizations are equivalent\n" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "id": "616b93aa", 28 | "metadata": {}, 29 | "source": [ 30 | "Old ones:" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 2, 36 | "id": "675f3e59", 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "def normalize_crossspectrum_oldstingray(unnorm_power, tseg, nbins, nphots1, nphots2, norm=\"none\", power_type=\"real\"):\n", 41 | " \"\"\"\n", 42 | " Normalize the real part of the cross spectrum to Leahy, absolute rms^2,\n", 43 | " fractional rms^2 normalization, or not at all.\n", 44 | "\n", 45 | " Parameters\n", 46 | " ----------\n", 47 | " unnorm_power: numpy.ndarray\n", 48 | " The unnormalized cross spectrum.\n", 49 | "\n", 50 | " tseg: int\n", 51 | " The length of the Fourier segment, in seconds.\n", 52 | "\n", 53 | " nbins : int\n", 54 | " Number of bins in the light curve\n", 55 | "\n", 56 | " nphots1 : int\n", 57 | " Number of photons in the light curve no. 1\n", 58 | "\n", 59 | " nphots2 : int\n", 60 | " Number of photons in the light curve no. 2\n", 61 | "\n", 62 | " Other parameters\n", 63 | " ----------------\n", 64 | " norm : str\n", 65 | " One of `'leahy'` (Leahy+83), `'frac'` (fractional rms), `'abs'`\n", 66 | " (absolute rms)\n", 67 | "\n", 68 | " power_type : str\n", 69 | " One of `'real'` (real part), `'all'` (all complex powers), `'abs'`\n", 70 | " (absolute value)\n", 71 | "\n", 72 | " Returns\n", 73 | " -------\n", 74 | " power: numpy.nd.array\n", 75 | " The normalized co-spectrum (real part of the cross spectrum). For\n", 76 | " 'none' normalization, imaginary part is returned as well.\n", 77 | " \"\"\"\n", 78 | "\n", 79 | " # The \"effective\" counts/bin is the geometrical mean of the counts/bin\n", 80 | " # of the two light curves. Same goes for counts/second in meanrate.\n", 81 | "\n", 82 | " log_nphots1 = np.log(nphots1)\n", 83 | " log_nphots2 = np.log(nphots2)\n", 84 | "\n", 85 | " actual_nphots = np.float64(np.sqrt(np.exp(log_nphots1 + log_nphots2)))\n", 86 | "\n", 87 | " if power_type == \"all\":\n", 88 | " c_num = unnorm_power\n", 89 | " elif power_type == \"real\":\n", 90 | " c_num = unnorm_power.real\n", 91 | " elif power_type == \"absolute\":\n", 92 | " c_num = np.absolute(unnorm_power)\n", 93 | " else:\n", 94 | " raise ValueError(\"`power_type` not recognized!\")\n", 95 | "\n", 96 | " if norm.lower() == 'leahy':\n", 97 | " power = c_num * 2. / actual_nphots\n", 98 | "\n", 99 | " elif norm.lower() == 'frac':\n", 100 | " meancounts1 = nphots1 / nbins\n", 101 | " meancounts2 = nphots2 / nbins\n", 102 | "\n", 103 | " actual_mean = np.sqrt(meancounts1 * meancounts2)\n", 104 | "\n", 105 | " assert actual_mean > 0.0, \\\n", 106 | " \"Mean count rate is <= 0. Something went wrong.\"\n", 107 | "\n", 108 | " c = c_num / float(nbins ** 2.)\n", 109 | " power = c * 2. * tseg / (actual_mean ** 2.0)\n", 110 | "\n", 111 | " elif norm.lower() == 'abs':\n", 112 | " meanrate = np.sqrt(nphots1 * nphots2) / tseg\n", 113 | "\n", 114 | " power = c_num * 2. * meanrate / actual_nphots\n", 115 | "\n", 116 | " elif norm.lower() == 'none':\n", 117 | " power = unnorm_power\n", 118 | "\n", 119 | " else:\n", 120 | " raise ValueError(\"Value for `norm` not recognized.\")\n", 121 | "\n", 122 | " return power\n", 123 | "\n", 124 | "\n", 125 | "def normalize_crossspectrum_gauss(\n", 126 | " unnorm_power, mean_flux, var, dt, N, norm=\"none\", power_type=\"real\"):\n", 127 | " \"\"\"\n", 128 | " Normalize the real part of the cross spectrum to Leahy, absolute rms^2,\n", 129 | " fractional rms^2 normalization, or not at all.\n", 130 | "\n", 131 | " Parameters\n", 132 | " ----------\n", 133 | " unnorm_power: numpy.ndarray\n", 134 | " The unnormalized cross spectrum.\n", 135 | "\n", 136 | " mean_flux: float\n", 137 | " The mean flux of the light curve (if a cross spectrum, the geometrical\n", 138 | " mean of the flux in the two channels)\n", 139 | "\n", 140 | " var: float\n", 141 | " The variance of the light curve (if a cross spectrum, the geometrical\n", 142 | " mean of the variance in the two channels)\n", 143 | "\n", 144 | " dt: float\n", 145 | " The sampling time of the light curve\n", 146 | "\n", 147 | " N: int\n", 148 | " The number of bins in the light curve\n", 149 | "\n", 150 | " Other parameters\n", 151 | " ----------------\n", 152 | " norm : str\n", 153 | " One of `'leahy'` (Leahy+83), `'frac'` (fractional rms), `'abs'`\n", 154 | " (absolute rms)\n", 155 | "\n", 156 | " power_type : str\n", 157 | " One of `'real'` (real part), `'all'` (all complex powers), `'abs'`\n", 158 | " (absolute value)\n", 159 | "\n", 160 | " Returns\n", 161 | " -------\n", 162 | " power: numpy.nd.array\n", 163 | " The normalized co-spectrum (real part of the cross spectrum). For\n", 164 | " 'none' normalization, imaginary part is returned as well.\n", 165 | "\n", 166 | " Examples\n", 167 | " --------\n", 168 | " >>> lc_c = np.random.poisson(10000, 10000)\n", 169 | " >>> lc_c_var = 10000\n", 170 | " >>> lc = lc_c / 17.3453\n", 171 | " >>> lc_var = (100 / 17.3453)**2\n", 172 | " >>> pds_c = np.absolute(np.fft.fft(lc_c))**2\n", 173 | " >>> pds = np.absolute(np.fft.fft(lc))**2\n", 174 | " >>> norm_c = normalize_crossspectrum_gauss(pds_c, np.mean(lc_c), lc_c_var, 0.1, len(lc_c), norm='leahy')\n", 175 | " >>> norm = normalize_crossspectrum_gauss(pds, np.mean(lc), lc_var, 0.1, len(lc), norm='leahy')\n", 176 | " >>> np.allclose(norm, norm_c)\n", 177 | " True\n", 178 | " >>> np.isclose(np.mean(norm[1:]), 2, atol=0.1)\n", 179 | " True\n", 180 | " >>> norm_c = normalize_crossspectrum_gauss(pds_c, np.mean(lc_c), np.mean(lc_c), 0.1, len(lc_c), norm='frac')\n", 181 | " >>> norm = normalize_crossspectrum_gauss(pds, np.mean(lc), lc_var, 0.1, len(lc), norm='frac')\n", 182 | " >>> np.allclose(norm, norm_c)\n", 183 | " True\n", 184 | " >>> norm_c = normalize_crossspectrum_gauss(pds_c, np.mean(lc_c), np.mean(lc_c), 0.1, len(lc_c), norm='abs')\n", 185 | " >>> norm = normalize_crossspectrum_gauss(pds, np.mean(lc), lc_var, 0.1, len(lc), norm='abs')\n", 186 | " >>> np.allclose(norm / np.mean(lc)**2, norm_c / np.mean(lc_c)**2)\n", 187 | " True\n", 188 | " >>> np.isclose(np.mean(norm_c[2:]), 2 * np.mean(lc_c * 0.1), rtol=0.1)\n", 189 | " True\n", 190 | " \"\"\"\n", 191 | "\n", 192 | " # The \"effective\" counts/bin is the geometrical mean of the counts/bin\n", 193 | " # of the two light curves. Same goes for counts/second in meanrate.\n", 194 | " if power_type == \"all\":\n", 195 | " c_num = unnorm_power\n", 196 | " elif power_type == \"real\":\n", 197 | " c_num = unnorm_power.real\n", 198 | " elif power_type == \"absolute\":\n", 199 | " c_num = np.absolute(unnorm_power)\n", 200 | " else:\n", 201 | " raise ValueError(\"`power_type` not recognized!\")\n", 202 | "\n", 203 | " common_factor = 2 * dt / N\n", 204 | " rate_mean = mean_flux * dt\n", 205 | " if norm.lower() == 'leahy':\n", 206 | " norm = 2 / var / N\n", 207 | "\n", 208 | " elif norm.lower() == 'frac':\n", 209 | " norm = common_factor / rate_mean**2\n", 210 | "\n", 211 | " elif norm.lower() == 'abs':\n", 212 | " norm = common_factor\n", 213 | "\n", 214 | " elif norm.lower() == 'none':\n", 215 | " norm = 1\n", 216 | "\n", 217 | " else:\n", 218 | " raise ValueError(\"Value for `norm` not recognized.\")\n", 219 | "\n", 220 | " return norm * c_num\n", 221 | "\n", 222 | "\n" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "id": "2c19d226", 228 | "metadata": {}, 229 | "source": [ 230 | "New ones:" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 3, 236 | "id": "3e8ff0ed", 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "def normalize_frac(power, dt, N, mean):\n", 241 | " \"\"\"Fractional rms normalization, from the variance of the lc.\n", 242 | "\n", 243 | " Examples\n", 244 | " --------\n", 245 | " >>> mean = var = 1000000\n", 246 | " >>> N = 1000000\n", 247 | " >>> dt = 0.2\n", 248 | " >>> meanrate = mean / dt\n", 249 | " >>> lc = np.random.poisson(mean, N)\n", 250 | " >>> pds = np.abs(fft(lc))**2\n", 251 | " >>> pdsnorm = normalize_frac(pds, dt, lc.size, mean)\n", 252 | " >>> np.isclose(pdsnorm[1:N//2].mean(), poisson_level(norm=\"frac\", meanrate=meanrate), rtol=0.01)\n", 253 | " True\n", 254 | " \"\"\"\n", 255 | " # (mean * N) / (mean /dt) = N * dt\n", 256 | " # It's Leahy / meanrate;\n", 257 | " # Nph = mean * N\n", 258 | " # meanrate = mean / dt\n", 259 | " # norm = 2 / (Nph * meanrate) = 2 * dt / (mean**2 * N)\n", 260 | "\n", 261 | " return power * 2. * dt / (mean ** 2 * N)\n", 262 | "\n", 263 | "\n", 264 | "def normalize_abs(power, dt, N):\n", 265 | " \"\"\"Absolute rms normalization, from the variance of the lc.\n", 266 | "\n", 267 | " Examples\n", 268 | " --------\n", 269 | " >>> mean = var = 100000\n", 270 | " >>> N = 1000000\n", 271 | " >>> dt = 0.2\n", 272 | " >>> meanrate = mean / dt\n", 273 | " >>> lc = np.random.poisson(mean, N)\n", 274 | " >>> pds = np.abs(fft(lc))**2\n", 275 | " >>> pdsnorm = normalize_abs(pds, dt, lc.size)\n", 276 | " >>> np.isclose(pdsnorm[1:N//2].mean(), poisson_level(norm=\"abs\", meanrate=meanrate), rtol=0.01)\n", 277 | " True\n", 278 | " \"\"\"\n", 279 | " # It's frac * meanrate**2; Leahy / meanrate * meanrate**2\n", 280 | " # Nph = mean * N\n", 281 | " # meanrate = mean / dt\n", 282 | " # norm = 2 / (Nph * meanrate) * meanrate**2 = 2 * dt / (mean**2 * N) * mean**2 / dt**2\n", 283 | "\n", 284 | " return power * 2. / N / dt\n", 285 | "\n", 286 | "\n", 287 | "def normalize_leahy_from_variance(power, variance, N):\n", 288 | " \"\"\"Leahy+83 normalization, from the variance of the lc.\n", 289 | "\n", 290 | " Examples\n", 291 | " --------\n", 292 | " >>> mean = var = 100000.\n", 293 | " >>> N = 1000000\n", 294 | " >>> lc = np.random.poisson(mean, N).astype(float)\n", 295 | " >>> pds = np.abs(fft(lc))**2\n", 296 | " >>> pdsnorm = normalize_leahy_from_variance(pds, var, lc.size)\n", 297 | " >>> np.isclose(pdsnorm[0], 2 * np.sum(lc), rtol=0.01)\n", 298 | " True\n", 299 | " >>> np.isclose(pdsnorm[1:N//2].mean(), poisson_level(norm=\"leahy\"), rtol=0.01)\n", 300 | " True\n", 301 | " \"\"\"\n", 302 | " return power * 2. / (variance * N)\n", 303 | "\n", 304 | "\n", 305 | "def normalize_leahy_poisson(power, Nph):\n", 306 | " \"\"\"Leahy+83 normalization, from the variance of the lc.\n", 307 | "\n", 308 | " Examples\n", 309 | " --------\n", 310 | " >>> mean = var = 100000.\n", 311 | " >>> N = 1000000\n", 312 | " >>> lc = np.random.poisson(mean, N).astype(float)\n", 313 | " >>> pds = np.abs(fft(lc))**2\n", 314 | " >>> pdsnorm = normalize_leahy_poisson(pds, np.sum(lc))\n", 315 | " >>> np.isclose(pdsnorm[0], 2 * np.sum(lc), rtol=0.01)\n", 316 | " True\n", 317 | " >>> np.isclose(pdsnorm[1:N//2].mean(), poisson_level(norm=\"leahy\"), rtol=0.01)\n", 318 | " True\n", 319 | " \"\"\"\n", 320 | " return power * 2. / Nph\n", 321 | "\n", 322 | "\n", 323 | "def normalize_crossspectrum(unnorm_power, dt, N, mean, variance=None, norm=\"abs\", power_type=\"all\"):\n", 324 | " \"\"\"Wrapper around all the normalize_NORM methods.\"\"\"\n", 325 | "\n", 326 | " if norm == \"leahy\" and variance is not None:\n", 327 | " pds = normalize_leahy_from_variance(unnorm_power, variance, N)\n", 328 | " elif norm == \"leahy\":\n", 329 | " pds = normalize_leahy_poisson(unnorm_power, N * mean)\n", 330 | " elif norm == \"frac\":\n", 331 | " pds = normalize_frac(unnorm_power, dt, N, mean)\n", 332 | " elif norm == \"abs\":\n", 333 | " pds = normalize_abs(unnorm_power, dt, N)\n", 334 | " elif norm == \"none\":\n", 335 | " pds = unnorm_power\n", 336 | " else:\n", 337 | " raise ValueError(\"Unknown value for the norm\")\n", 338 | "\n", 339 | " if power_type == \"real\":\n", 340 | " pds = pds.real\n", 341 | " elif power_type in [\"abs\", \"absolute\"]:\n", 342 | " pds = np.abs(pds)\n", 343 | "\n", 344 | " return pds\n" 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": 4, 350 | "id": "e2a43bb3", 351 | "metadata": {}, 352 | "outputs": [ 353 | { 354 | "name": "stderr", 355 | "output_type": "stream", 356 | "text": [ 357 | "100%|██████████| 100/100 [00:00<00:00, 4963.97it/s]" 358 | ] 359 | }, 360 | { 361 | "name": "stdout", 362 | "output_type": "stream", 363 | "text": [ 364 | "BAD: power=1, dt=0.898527, M=561, N=1320, mean1=38383.5, mean2=38383.5, variance=976.9199352745533, norm=abs, power_type=absolute\n", 365 | "old_power=0.0013614051652651507, new_power=0.0016862607638327997\n", 366 | "BAD: power=1, dt=0.66665, M=627, N=7181, mean1=8692.88, mean2=8692.88, variance=781.5211894773033, norm=abs, power_type=all\n", 367 | "old_power=0.00018567044354993417, new_power=0.0004177797281562002\n", 368 | "BAD: power=1, dt=0.615666, M=65, N=1647, mean1=31771.1, mean2=31771.1, variance=174.09922389759558, norm=abs, power_type=real\n", 369 | "old_power=0.0007476213964438318, new_power=0.0019723821833813847\n", 370 | "BAD: power=1, dt=0.0727525, M=748, N=199, mean1=242526, mean2=242526, variance=990.0484899918553, norm=abs, power_type=real\n", 371 | "old_power=0.0007311813190525624, new_power=0.1381429580904335\n", 372 | "BAD: power=1, dt=0.444013, M=703, N=1191, mean1=22037.5, mean2=22037.5, variance=61.77808527096529, norm=abs, power_type=all\n", 373 | "old_power=0.0007456144979623862, new_power=0.003782005223872418\n", 374 | "BAD: power=1, dt=0.507541, M=65, N=4706, mean1=11359.3, mean2=11359.3, variance=595.1883648463114, norm=abs, power_type=absolute\n", 375 | "old_power=0.00021569962615485447, new_power=0.0008373494767162612\n", 376 | "BAD: power=1, dt=0.459405, M=914, N=4050, mean1=12130.3, mean2=12130.3, variance=394.9085770957451, norm=abs, power_type=real\n", 377 | "old_power=0.00022686676348644433, new_power=0.0010749272422884786\n", 378 | "BAD: power=1, dt=0.623446, M=664, N=575, mean1=44104.4, mean2=44104.4, variance=497.5281648889309, norm=abs, power_type=absolute\n", 379 | "old_power=0.002168508033911969, new_power=0.0055790887041001\n", 380 | "BAD: power=1, dt=0.965974, M=330, N=6576, mean1=5020.67, mean2=5020.67, variance=268.4617736720939, norm=abs, power_type=all\n", 381 | "old_power=0.00029378768322722225, new_power=0.0003148493476579783\n", 382 | "BAD: power=1, dt=0.550627, M=523, N=563, mean1=153668, mean2=153668, variance=485.0786564351558, norm=abs, power_type=real\n", 383 | "old_power=0.001956045111107487, new_power=0.006451553977409911\n" 384 | ] 385 | }, 386 | { 387 | "name": "stderr", 388 | "output_type": "stream", 389 | "text": [ 390 | "\n" 391 | ] 392 | } 393 | ], 394 | "source": [ 395 | "import tqdm\n", 396 | "ntrial = 100\n", 397 | "\n", 398 | "rows = []\n", 399 | "for i in tqdm.tqdm(range(ntrial)):\n", 400 | " M = np.random.randint(1, 1000)\n", 401 | " N = np.random.randint(1, 10000)\n", 402 | " \n", 403 | " dt = np.random.uniform(0.0001, 1)\n", 404 | " nphots1 = np.random.randint(0, 100_000_000)\n", 405 | " nphots2 = nphots1 # np.random.randint(0, 100_000_000)\n", 406 | " nphots = np.sqrt(nphots1 * nphots2)\n", 407 | "\n", 408 | " mean1 = nphots1 / N\n", 409 | " mean2 = nphots2 / N\n", 410 | " mean = np.sqrt(mean1 * mean2)\n", 411 | " \n", 412 | " unnorm_power = 1\n", 413 | "\n", 414 | " variance = np.random.choice([None, np.random.uniform(0, 1000)])\n", 415 | " norm = np.random.choice([\"abs\", \"frac\", \"leahy\", \"none\"])\n", 416 | " power_type = np.random.choice([\"all\", \"real\", \"absolute\"])\n", 417 | " \n", 418 | " tseg = dt * N\n", 419 | " \n", 420 | " if variance is not None:\n", 421 | " old_power = normalize_crossspectrum_gauss(\n", 422 | " unnorm_power, mean / dt, variance, dt, N, norm=norm, power_type=power_type)\n", 423 | " else:\n", 424 | " old_power = normalize_crossspectrum_oldstingray(\n", 425 | " unnorm_power, tseg, N, nphots1, nphots2, norm=norm, power_type=power_type)\n", 426 | "\n", 427 | " new_power = normalize_crossspectrum(unnorm_power, dt, N, mean, variance=variance, norm=norm, power_type=power_type)\n", 428 | " \n", 429 | " msg =(f\"power={unnorm_power:g}, dt={dt:g}, M={M}, N={N}, mean1={mean1:g}, mean2={mean2:g}, \" \n", 430 | " f\"variance={variance}, norm={norm}, power_type={power_type}\\n\"\n", 431 | " f\"old_power={old_power}, new_power={new_power}\")\n", 432 | " is_close = np.isclose(new_power, old_power, rtol=0.00001)\n", 433 | " if is_close:\n", 434 | " msg = f\"GOOD: {msg}\"\n", 435 | " else:\n", 436 | " msg = f\"BAD: {msg}\"\n", 437 | " print(msg)\n", 438 | " variance = 0 if variance is None else variance\n", 439 | " rows.append([old_power, new_power, dt, M, N, mean1, mean2, mean, variance, norm, power_type, is_close])\n", 440 | "table = Table(rows=rows, names=[\"old\", \"new\", \"dt\", \"M\", \"N\", \"mean1\", \"mean2\", \"mean\", \"variance\", \"norm\", \"power_type\", \"good?\"])" 441 | ] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "execution_count": 5, 446 | "id": "ada9178a", 447 | "metadata": {}, 448 | "outputs": [ 449 | { 450 | "data": { 451 | "text/html": [ 452 | "
Table length=100\n", 453 | "\n", 454 | "\n", 455 | "\n", 456 | "\n", 457 | "\n", 458 | "\n", 459 | "\n", 460 | "\n", 461 | "\n", 462 | "\n", 463 | "\n", 464 | "\n", 465 | "\n", 466 | "\n", 467 | "\n", 468 | "\n", 469 | "\n", 470 | "\n", 471 | "\n", 472 | "\n", 473 | "\n", 474 | "\n", 475 | "\n", 476 | "\n", 477 | "
oldnewdtMNmean1mean2meanvariancenormpower_typegood?
float64float64float64int64int64float64float64float64float64str5str8bool
2.9806062812510466e-072.980606281251046e-070.77699573546328865796651817.7675116399381817.7675116399381817.767511639938694.2622076469609leahyallTrue
0.00136140516526515070.00168626076383279970.8985274090749995561132038383.48257575757538383.48257575757538383.482575757575976.9199352745533absabsoluteFalse
0.0015689068622217120.00156890686222171280.4386692813134602193290612043.21369580178912043.21369580178912043.2136958017890.0absallTrue
5.411572785735735e-135.411572785735735e-130.823649888800288324318430919.89698492462430919.89698492462430919.8969849246240.0fracallTrue
5.879977513836387e-135.879977513836387e-130.5344521891262215975473619591.86359797297319591.86359797297319591.86359797297312.24575026381891fracabsoluteTrue
1.196458833686626e-061.1964588336866258e-060.41014302527390867815357811280.51900503074311280.51900503074311280.519005030743467.18823641557026leahyabsoluteTrue
4.427743193905621e-084.427743193905619e-080.197780729783228585793054854.3512090274044854.3512090274044854.3512090274040.0leahyallTrue
1.01.00.8029256477987071470348827168.9337729357827168.9337729357827168.933772935780.0noneallTrue
1.01.00.862486535911196628720812015.56895723212015.56895723212015.56895723210.0noneabsoluteTrue
0.000185670443549934170.00041777972815620020.666649727566038762771818692.8823283665228692.8823283665228692.882328366522781.5211894773033absallFalse
....................................
1.01.00.1925497654361147440893105971.16461366181105971.16461366181105971.16461366181617.0921539102311noneallTrue
4.161518828198522e-124.161518828198522e-120.705402904283136734165247208.5964132434097208.5964132434097208.596413243409682.4867194375161fracallTrue
2.6551856086922027e-082.6551856086922067e-080.891894454839117792389448421.7688953488388421.7688953488388421.7688953488380.0leahyabsoluteTrue
1.01.00.3495870412439917654667579842.0745893147859842.0745893147859842.074589314785780.5071544320691noneallTrue
5.294729099916432e-135.294729099916433e-130.44921103375229543631533317837.44065254078317837.44065254078317837.4406525407830.0fracabsoluteTrue
0.0019560451111074870.0064515539774099110.5506266987767575523563153667.86856127885153667.86856127885153667.86856127885485.0786564351558absrealFalse
1.01.00.383338571715390892962622393.3372724369212393.3372724369212393.337272436921427.3679401880777noneallTrue
1.01.00.11439024311365674134237323037.78297513695723037.78297513695723037.782975136957297.39144169664445noneallTrue
0.000444272625144913540.000444272625144913760.706709630017737858063707162.09811616954457162.09811616954457162.09811616954450.0absallTrue
2.090149790793769e-082.0901497907937722e-080.596249918361558199738412958.68391115926412958.68391115926412958.6839111592640.0leahyabsoluteTrue
" 478 | ], 479 | "text/plain": [ 480 | "\n", 481 | " old new ... power_type good?\n", 482 | " float64 float64 ... str8 bool\n", 483 | "---------------------- ---------------------- ... ---------- -----\n", 484 | "2.9806062812510466e-07 2.980606281251046e-07 ... all True\n", 485 | " 0.0013614051652651507 0.0016862607638327997 ... absolute False\n", 486 | " 0.001568906862221712 0.0015689068622217128 ... all True\n", 487 | " 5.411572785735735e-13 5.411572785735735e-13 ... all True\n", 488 | " 5.879977513836387e-13 5.879977513836387e-13 ... absolute True\n", 489 | " 1.196458833686626e-06 1.1964588336866258e-06 ... absolute True\n", 490 | " 4.427743193905621e-08 4.427743193905619e-08 ... all True\n", 491 | " 1.0 1.0 ... all True\n", 492 | " 1.0 1.0 ... absolute True\n", 493 | "0.00018567044354993417 0.0004177797281562002 ... all False\n", 494 | " ... ... ... ... ...\n", 495 | " 1.0 1.0 ... all True\n", 496 | " 4.161518828198522e-12 4.161518828198522e-12 ... all True\n", 497 | "2.6551856086922027e-08 2.6551856086922067e-08 ... absolute True\n", 498 | " 1.0 1.0 ... all True\n", 499 | " 5.294729099916432e-13 5.294729099916433e-13 ... absolute True\n", 500 | " 0.001956045111107487 0.006451553977409911 ... real False\n", 501 | " 1.0 1.0 ... all True\n", 502 | " 1.0 1.0 ... all True\n", 503 | "0.00044427262514491354 0.00044427262514491376 ... all True\n", 504 | " 2.090149790793769e-08 2.0901497907937722e-08 ... absolute True" 505 | ] 506 | }, 507 | "execution_count": 5, 508 | "metadata": {}, 509 | "output_type": "execute_result" 510 | } 511 | ], 512 | "source": [ 513 | "table" 514 | ] 515 | }, 516 | { 517 | "cell_type": "code", 518 | "execution_count": 6, 519 | "id": "c69c2f58", 520 | "metadata": {}, 521 | "outputs": [ 522 | { 523 | "data": { 524 | "text/html": [ 525 | "
Table length=10\n", 526 | "
\n", 527 | "\n", 528 | "\n", 529 | "\n", 530 | "\n", 531 | "\n", 532 | "\n", 533 | "\n", 534 | "\n", 535 | "\n", 536 | "\n", 537 | "\n", 538 | "\n", 539 | "
oldnewdtMNmean1mean2meanvariancenormpower_typegood?
float64float64float64int64int64float64float64float64float64str5str8bool
0.00136140516526515070.00168626076383279970.8985274090749995561132038383.48257575757538383.48257575757538383.482575757575976.9199352745533absabsoluteFalse
0.000185670443549934170.00041777972815620020.666649727566038762771818692.8823283665228692.8823283665228692.882328366522781.5211894773033absallFalse
0.00074762139644383180.00197238218338138470.615666219971495565164731771.09289617486531771.09289617486531771.092896174865174.09922389759558absrealFalse
0.00073118131905256240.13814295809043350.07275254124572995748199242525.6783919598242525.6783919598242525.6783919598990.0484899918553absrealFalse
0.00074561449796238620.0037820052238724180.444013433536601703119122037.4601175482822037.4601175482822037.4601175482861.77808527096529absallFalse
0.000215699626154854470.00083734947671626120.507541220342372665470611359.338504037411359.338504037411359.3385040374595.1883648463114absabsoluteFalse
0.000226866763486444330.00107492724228847860.45940519606004976914405012130.26172839506212130.26172839506212130.261728395062394.9085770957451absrealFalse
0.0021685080339119690.00557908870410010.623446059749691166457544104.4469565217444104.4469565217444104.44695652174497.5281648889309absabsoluteFalse
0.000293787683227222250.00031484934765797830.965973902451106733065765020.6651459854015020.6651459854015020.665145985401268.4617736720939absallFalse
0.0019560451111074870.0064515539774099110.5506266987767575523563153667.86856127885153667.86856127885153667.86856127885485.0786564351558absrealFalse
" 540 | ], 541 | "text/plain": [ 542 | "\n", 543 | " old new ... power_type good?\n", 544 | " float64 float64 ... str8 bool\n", 545 | "---------------------- --------------------- ... ---------- -----\n", 546 | " 0.0013614051652651507 0.0016862607638327997 ... absolute False\n", 547 | "0.00018567044354993417 0.0004177797281562002 ... all False\n", 548 | " 0.0007476213964438318 0.0019723821833813847 ... real False\n", 549 | " 0.0007311813190525624 0.1381429580904335 ... real False\n", 550 | " 0.0007456144979623862 0.003782005223872418 ... all False\n", 551 | "0.00021569962615485447 0.0008373494767162612 ... absolute False\n", 552 | "0.00022686676348644433 0.0010749272422884786 ... real False\n", 553 | " 0.002168508033911969 0.0055790887041001 ... absolute False\n", 554 | "0.00029378768322722225 0.0003148493476579783 ... all False\n", 555 | " 0.001956045111107487 0.006451553977409911 ... real False" 556 | ] 557 | }, 558 | "execution_count": 6, 559 | "metadata": {}, 560 | "output_type": "execute_result" 561 | } 562 | ], 563 | "source": [ 564 | "table_bad = table[~table[\"good?\"]]\n", 565 | "table_bad" 566 | ] 567 | }, 568 | { 569 | "cell_type": "markdown", 570 | "id": "824fbac2", 571 | "metadata": {}, 572 | "source": [ 573 | "Looking at the actual normalizations, I realized that the _old_ stingray formula was wrong, in the Gaussian case. \n", 574 | "The normalization factor should have been\n", 575 | "\n", 576 | "$$\\frac{2}{dt\\,N}$$\n", 577 | "\n", 578 | "instead of \n", 579 | "\n", 580 | "$$\\frac{2 dt}{N}$$\n" 581 | ] 582 | }, 583 | { 584 | "cell_type": "code", 585 | "execution_count": null, 586 | "id": "876d2705", 587 | "metadata": {}, 588 | "outputs": [], 589 | "source": [] 590 | } 591 | ], 592 | "metadata": { 593 | "kernelspec": { 594 | "display_name": "Python 3", 595 | "language": "python", 596 | "name": "python3" 597 | }, 598 | "language_info": { 599 | "codemirror_mode": { 600 | "name": "ipython", 601 | "version": 3 602 | }, 603 | "file_extension": ".py", 604 | "mimetype": "text/x-python", 605 | "name": "python", 606 | "nbconvert_exporter": "python", 607 | "pygments_lexer": "ipython3", 608 | "version": "3.8.8" 609 | } 610 | }, 611 | "nbformat": 4, 612 | "nbformat_minor": 5 613 | } 614 | -------------------------------------------------------------------------------- /EventList/events.fits: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StingraySoftware/notebooks/43ba0594276c66e27a877488ec333b5c3e0b56b3/EventList/events.fits -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Stingray 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lightcurve/lightcurve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StingraySoftware/notebooks/43ba0594276c66e27a877488ec333b5c3e0b56b3/Lightcurve/lightcurve.png -------------------------------------------------------------------------------- /Lightcurve/photon_arrivals.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 1 3 | 2 4 | 2 5 | 2 6 | 3 7 | 3 8 | 3 9 | 3 10 | 3 11 | 4 12 | 5 13 | 5 14 | 5 15 | 5 16 | 6 17 | 7 18 | 7 19 | 7 20 | 8 21 | 9 22 | 10 23 | 10 24 | 10 25 | -------------------------------------------------------------------------------- /Performance/Dealing with large data files.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "24df35e1-e5c9-40a8-89ab-73c782e070b3", 6 | "metadata": {}, 7 | "source": [ 8 | "In this tutorial, we approach the case of a very large event file, larger than the memory of our computer. Will we be able to analyze it?" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "8957430d-d905-40a2-87cc-dcbdbaec91d7", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "%load_ext autoreload\n", 19 | "%autoreload 2\n", 20 | "%load_ext memory_profiler\n", 21 | "import psutil\n", 22 | "import os\n", 23 | "import numpy as np\n", 24 | "import gc\n", 25 | "\n", 26 | "from stingray import EventList, AveragedPowerspectrum" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "id": "73c7f674-c04e-44c9-bf02-54713675352b", 33 | "metadata": {}, 34 | "outputs": [ 35 | { 36 | "name": "stdout", 37 | "output_type": "stream", 38 | "text": [ 39 | "Current memory use (29237): 91.16 MB\n" 40 | ] 41 | } 42 | ], 43 | "source": [ 44 | "pid = os.getpid()\n", 45 | "python_process = psutil.Process(pid)\n", 46 | "memory_use = python_process.memory_info()[0]/2.**20\n", 47 | "print(f\"Current memory use ({pid}): {memory_use:.2f} MB\")\n" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "id": "ac2a89f2-c520-4c32-9f28-9da5a0029b46", 53 | "metadata": {}, 54 | "source": [ 55 | "## Data preparation\n", 56 | "\n", 57 | "Now we simulate and load a full dataset. Let's simulate a large observation, about 2GB. We use HENDRICS, you can install it with `pip install hendrics`" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 4, 63 | "id": "ed97efbf-1310-4651-bf46-6830d92fb6f8", 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "fname = \"events_large.evt\"" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 5, 73 | "id": "c2221d2a-a3fa-4119-860e-e090affc17b9", 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "name": "stdout", 78 | "output_type": "stream", 79 | "text": [ 80 | "/Users/meo/devel/StingraySoftware/hendrics/hendrics/io.py:38: UserWarning: Warning! NetCDF is not available. Using pickle format.\n", 81 | " warnings.warn(msg)\n", 82 | "/Users/meo/devel/StingraySoftware/hendrics/hendrics/fold.py:38: UserWarning: PINT is not installed. Some pulsar functionality will not be available\n", 83 | " warnings.warn(\n", 84 | "\u001b[0m" 85 | ] 86 | } 87 | ], 88 | "source": [ 89 | "!HENfake -c 20000 --tstart 0 --tstop 10000 --mjdref 56000 -o events_large.evt" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "id": "b7d9d777-09ad-4a7c-a479-a50548bedc90", 95 | "metadata": {}, 96 | "source": [ 97 | "## Naive procedure: create light curve, then calculate PDS\n" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 6, 103 | "id": "c0b076b3-33f2-4ff2-86e1-f33c796d4e17", 104 | "metadata": {}, 105 | "outputs": [ 106 | { 107 | "name": "stdout", 108 | "output_type": "stream", 109 | "text": [ 110 | "peak memory: 5645.70 MiB, increment: 5347.78 MiB\n" 111 | ] 112 | } 113 | ], 114 | "source": [ 115 | "%memit events = EventList.read(fname, fmt=\"ogip\")\n" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "id": "0c7520ca-69f2-4445-83df-4a888c10082e", 121 | "metadata": {}, 122 | "source": [ 123 | "Loading the observation into memory takes about 5 GB. Now, we want a power spectrum with very high frequencies. Let us do the traditional way, creating first a light curve, then analyzing it with AveragedPowerspectrum" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 7, 129 | "id": "40c1a77b-2ac5-4bb9-8f8c-1204eecbd5fb", 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "fine_sample_time = 0.00001\n", 134 | "segment_size = 128\n" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 8, 140 | "id": "5dde9f16-9fd6-4618-9ef4-8f5013e01f1a", 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "name": "stdout", 145 | "output_type": "stream", 146 | "text": [ 147 | "peak memory: 15315.70 MiB, increment: 9670.00 MiB\n" 148 | ] 149 | } 150 | ], 151 | "source": [ 152 | "%memit lc = events.to_lc(dt=fine_sample_time)" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "id": "42b15eee-88b1-43bb-bdef-4ca7b7946887", 158 | "metadata": {}, 159 | "source": [ 160 | "This very finely sampled light curve will take a _lot_ of memory: 10000 s, sampled at 10 $\\mu$s, will give ~1B float objects, or 8 GB, for the time array and the same for the counts array. Here, the value that comes out is slightly smaller because the operating system is using swap! Some of the swapped data will come back in the main memory when calculating the power spectrum." 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 9, 166 | "id": "b009941b-a1a3-455b-9b64-4c5021affdd7", 167 | "metadata": {}, 168 | "outputs": [ 169 | { 170 | "name": "stderr", 171 | "output_type": "stream", 172 | "text": [ 173 | "78it [00:28, 2.69it/s]" 174 | ] 175 | }, 176 | { 177 | "name": "stdout", 178 | "output_type": "stream", 179 | "text": [ 180 | "peak memory: 14324.80 MiB, increment: 2063.22 MiB\n" 181 | ] 182 | }, 183 | { 184 | "name": "stderr", 185 | "output_type": "stream", 186 | "text": [ 187 | "\n" 188 | ] 189 | }, 190 | { 191 | "data": { 192 | "text/plain": [ 193 | "array([1.02539377e-04, 1.03036920e-04, 9.54479649e-05, ...,\n", 194 | " 1.10340774e-04, 1.07141777e-04, 9.10072280e-05])" 195 | ] 196 | }, 197 | "execution_count": 9, 198 | "metadata": {}, 199 | "output_type": "execute_result" 200 | } 201 | ], 202 | "source": [ 203 | "%memit ps = AveragedPowerspectrum.from_lightcurve(lc, segment_size=segment_size)\n", 204 | "ps.power" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": 10, 210 | "id": "f19ebe91-bdad-41c6-a9c6-ca1bc2cc02e7", 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "data": { 215 | "text/plain": [ 216 | "0" 217 | ] 218 | }, 219 | "execution_count": 10, 220 | "metadata": {}, 221 | "output_type": "execute_result" 222 | } 223 | ], 224 | "source": [ 225 | "del events, lc, ps.power, ps\n", 226 | "gc.collect()" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 11, 232 | "id": "920771d2-0a75-41b4-8533-b9c7f572bdca", 233 | "metadata": {}, 234 | "outputs": [ 235 | { 236 | "name": "stdout", 237 | "output_type": "stream", 238 | "text": [ 239 | "Current memory use (29237): 1876.75 MB\n" 240 | ] 241 | } 242 | ], 243 | "source": [ 244 | "memory_use = python_process.memory_info()[0]/2.**20\n", 245 | "print(f\"Current memory use ({pid}): {memory_use:.2f} MB\")" 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "id": "7c81b95f-3bec-4046-a3ba-af944cb3f34e", 251 | "metadata": {}, 252 | "source": [ 253 | "So, if we want to take the maximum memory usage for the full procedure, we can profile the three steps done until now:" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 12, 259 | "id": "8b7d8223-5f2a-435c-9510-dc4c4d13da09", 260 | "metadata": {}, 261 | "outputs": [ 262 | { 263 | "name": "stderr", 264 | "output_type": "stream", 265 | "text": [ 266 | "78it [00:28, 2.70it/s]\n" 267 | ] 268 | }, 269 | { 270 | "name": "stdout", 271 | "output_type": "stream", 272 | "text": [ 273 | "peak memory: 16715.56 MiB, increment: 14837.95 MiB\n" 274 | ] 275 | }, 276 | { 277 | "data": { 278 | "text/plain": [ 279 | "array([1.02539377e-04, 1.03036920e-04, 9.54479649e-05, ...,\n", 280 | " 1.10340774e-04, 1.07141777e-04, 9.10072280e-05])" 281 | ] 282 | }, 283 | "execution_count": 12, 284 | "metadata": {}, 285 | "output_type": "execute_result" 286 | } 287 | ], 288 | "source": [ 289 | "def legacy_pds_procedure(fname, sample_time, segment_size):\n", 290 | " events = EventList.read(fname, fmt=\"ogip\")\n", 291 | " lc = events.to_lc(dt=fine_sample_time)\n", 292 | " return AveragedPowerspectrum.from_lightcurve(lc, segment_size=segment_size)\n", 293 | "\n", 294 | "\n", 295 | "%memit ps = legacy_pds_procedure(fname, fine_sample_time, segment_size)\n", 296 | "ps.power" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "id": "7838fc58-1231-4bcf-9257-05cb5293cc2c", 302 | "metadata": {}, 303 | "source": [ 304 | "Let's clean up the memory a little bit." 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": 13, 310 | "id": "1db9bc50-c624-46e5-ab43-44cf40f387cd", 311 | "metadata": {}, 312 | "outputs": [ 313 | { 314 | "name": "stdout", 315 | "output_type": "stream", 316 | "text": [ 317 | "Current memory use (29237): 1876.75 MB\n" 318 | ] 319 | } 320 | ], 321 | "source": [ 322 | "del ps.power, ps\n", 323 | "gc.collect()\n", 324 | "python_process.memory_info()[0]/2.**20\n", 325 | "print(f\"Current memory use ({pid}): {memory_use:.2f} MB\")\n" 326 | ] 327 | }, 328 | { 329 | "cell_type": "markdown", 330 | "id": "6d127938-71a9-4815-813f-e1cc5ba97503", 331 | "metadata": {}, 332 | "source": [ 333 | "## Slightly better: PDS from events\n", 334 | "What if we get the power spectrum directly from the events, without previous binning of the full light curve? In this case, the binning will happen only on a segment-by-segment basis, freeing memory." 335 | ] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": 14, 340 | "id": "ef2ebf7f-7526-4ade-b543-7ddb1669e410", 341 | "metadata": {}, 342 | "outputs": [ 343 | { 344 | "name": "stderr", 345 | "output_type": "stream", 346 | "text": [ 347 | "78it [00:28, 2.71it/s]" 348 | ] 349 | }, 350 | { 351 | "name": "stdout", 352 | "output_type": "stream", 353 | "text": [ 354 | "peak memory: 7543.30 MiB, increment: 5701.02 MiB\n" 355 | ] 356 | }, 357 | { 358 | "name": "stderr", 359 | "output_type": "stream", 360 | "text": [ 361 | "\n" 362 | ] 363 | }, 364 | { 365 | "data": { 366 | "text/plain": [ 367 | "array([1.02539377e-04, 1.03036920e-04, 9.54479649e-05, ...,\n", 368 | " 1.10349785e-04, 1.07137039e-04, 9.09968704e-05])" 369 | ] 370 | }, 371 | "execution_count": 14, 372 | "metadata": {}, 373 | "output_type": "execute_result" 374 | } 375 | ], 376 | "source": [ 377 | "def pds_from_events(fname, sample_time, segment_size):\n", 378 | " events = EventList.read(fname, fmt=\"ogip\")\n", 379 | " return AveragedPowerspectrum.from_events(events, dt=sample_time, segment_size=segment_size)\n", 380 | "\n", 381 | "%memit ps = pds_from_events(fname, fine_sample_time, segment_size)\n", 382 | "ps.power" 383 | ] 384 | }, 385 | { 386 | "cell_type": "markdown", 387 | "id": "ce8f04da-9c8e-46d3-ba77-a04d8f60bb86", 388 | "metadata": {}, 389 | "source": [ 390 | "Much better! The memory increment is now dominated by the loading of events, so just about 5.7 GB. Let's clean up the memory a little bit again" 391 | ] 392 | }, 393 | { 394 | "cell_type": "code", 395 | "execution_count": 15, 396 | "id": "f2d79666-b03c-4a11-bd22-bfb5f691e218", 397 | "metadata": {}, 398 | "outputs": [ 399 | { 400 | "name": "stdout", 401 | "output_type": "stream", 402 | "text": [ 403 | "Current memory use (29237): 2245.31 MB\n" 404 | ] 405 | } 406 | ], 407 | "source": [ 408 | "del ps.power, ps\n", 409 | "gc.collect()\n", 410 | "memory_use = python_process.memory_info()[0]/2.**20\n", 411 | "print(f\"Current memory use ({pid}): {memory_use:.2f} MB\")\n" 412 | ] 413 | }, 414 | { 415 | "cell_type": "markdown", 416 | "id": "1eeef29a-56f3-4b41-9691-d276369c99ee", 417 | "metadata": {}, 418 | "source": [ 419 | "## Let's be \"lazy\": lazy loading with FITSTimeseriesReader\n", 420 | "\n", 421 | "Now, let's try not to even pre-load the events. What will happen?\n", 422 | "First of all, we use the new class `FITSTimeseriesReader` to lazy-load the data, meaning that the data remain in the FITS file until we try to access them. This occupies very little memory." 423 | ] 424 | }, 425 | { 426 | "cell_type": "code", 427 | "execution_count": 16, 428 | "id": "74ef9faf-ac33-4590-8f1e-46c11a0882d0", 429 | "metadata": {}, 430 | "outputs": [ 431 | { 432 | "name": "stdout", 433 | "output_type": "stream", 434 | "text": [ 435 | "peak memory: 2245.34 MiB, increment: 0.00 MiB\n" 436 | ] 437 | } 438 | ], 439 | "source": [ 440 | "from stingray.io import FITSTimeseriesReader\n", 441 | "%memit fitsreader = FITSTimeseriesReader(fname, data_kind=\"times\")\n" 442 | ] 443 | }, 444 | { 445 | "cell_type": "code", 446 | "execution_count": 17, 447 | "id": "0e7440ca-3c8d-4e6c-a2fd-cc486156bc11", 448 | "metadata": {}, 449 | "outputs": [ 450 | { 451 | "name": "stdout", 452 | "output_type": "stream", 453 | "text": [ 454 | "peak memory: 2245.36 MiB, increment: 0.00 MiB\n" 455 | ] 456 | } 457 | ], 458 | "source": [ 459 | "from stingray.gti import time_intervals_from_gtis\n", 460 | "start, stop = time_intervals_from_gtis(fitsreader.gti, segment_size)\n", 461 | "%memit interval_times = np.array(list(zip(start, stop)))\n" 462 | ] 463 | }, 464 | { 465 | "cell_type": "markdown", 466 | "id": "89acff6e-1fe9-4705-8891-13ec6cd47fc6", 467 | "metadata": {}, 468 | "source": [ 469 | "Let's create an iterable that uses the FITSTimeseriesReader to send AveragedPowerspectrum the pre-binned light curves for each segment. Events will be read in chunks from the FITS file, and streamed as light curve segments on the fly." 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": 18, 475 | "id": "92518923-fbc7-429a-b1d8-dc81591fc965", 476 | "metadata": {}, 477 | "outputs": [ 478 | { 479 | "name": "stderr", 480 | "output_type": "stream", 481 | "text": [ 482 | "78it [00:32, 2.43it/s]" 483 | ] 484 | }, 485 | { 486 | "name": "stdout", 487 | "output_type": "stream", 488 | "text": [ 489 | "peak memory: 4531.69 MiB, increment: 2286.30 MiB\n" 490 | ] 491 | }, 492 | { 493 | "name": "stderr", 494 | "output_type": "stream", 495 | "text": [ 496 | "\n" 497 | ] 498 | }, 499 | { 500 | "data": { 501 | "text/plain": [ 502 | "array([1.02539377e-04, 1.03036920e-04, 9.54479649e-05, 1.13488540e-04,\n", 503 | " 1.10641888e-04, 1.11452625e-04, 1.15657206e-04, 1.04863608e-04,\n", 504 | " 9.25844488e-05, 9.50754514e-05], dtype=float64)" 505 | ] 506 | }, 507 | "execution_count": 18, 508 | "metadata": {}, 509 | "output_type": "execute_result" 510 | } 511 | ], 512 | "source": [ 513 | "from stingray.utils import histogram\n", 514 | "def fits_times_iterable(fname, segment_size, sample_time):\n", 515 | " \"\"\"Create light curve iterables to be analyzed by AveragedPowerspectrum.from_lc_iterable.\"\"\"\n", 516 | " fitsreader = FITSTimeseriesReader(fname, data_kind=\"times\")\n", 517 | " start, stop = time_intervals_from_gtis(fitsreader.gti, segment_size)\n", 518 | " intvs = [[s, e] for s, e in zip(start,stop)]\n", 519 | " times = fitsreader.filter_at_time_intervals(intvs, check_gtis=True)\n", 520 | " for ts, (s, e) in zip(times, intvs):\n", 521 | " lc = histogram(ts, bins=np.rint((e - s)/sample_time).astype(int), range=[s, e])\n", 522 | " yield lc\n", 523 | "\n", 524 | "\n", 525 | "%memit ps_it = AveragedPowerspectrum.from_lc_iterable(fits_times_iterable(fname, segment_size, fine_sample_time), segment_size=segment_size, dt=fine_sample_time)\n", 526 | "ps_it.power[:10]" 527 | ] 528 | }, 529 | { 530 | "cell_type": "markdown", 531 | "id": "2da603a0-6e82-4076-9e33-576145024735", 532 | "metadata": {}, 533 | "source": [ 534 | "Hurray! We managed to keep the memory increment to ~2GB, comparable with the sole AveragedPowerspectrum operation!" 535 | ] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "execution_count": null, 540 | "id": "3265e2f0-264d-48d8-8187-fb44b10d4f72", 541 | "metadata": {}, 542 | "outputs": [], 543 | "source": [] 544 | } 545 | ], 546 | "metadata": { 547 | "kernelspec": { 548 | "display_name": "Python 3 (ipykernel)", 549 | "language": "python", 550 | "name": "python3" 551 | }, 552 | "language_info": { 553 | "codemirror_mode": { 554 | "name": "ipython", 555 | "version": 3 556 | }, 557 | "file_extension": ".py", 558 | "mimetype": "text/x-python", 559 | "name": "python", 560 | "nbconvert_exporter": "python", 561 | "pygments_lexer": "ipython3", 562 | "version": "3.11.9" 563 | } 564 | }, 565 | "nbformat": 4, 566 | "nbformat_minor": 5 567 | } 568 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Stingray Notebooks 2 | ================== 3 | 4 | .. image:: http://mybinder.org/badge.svg 5 | :target: http://mybinder.org/repo/StingraySoftware/notebooks 6 | 7 | This repository contains Jupyter notebooks with tutorials and 8 | examples of the spectral-timing library 9 | `Stingray `_! 10 | The main Stingray website is 11 | `here `_, 12 | and the Stingray documentation is hosted at 13 | `readthedocs `_. 14 | 15 | Click on the above 'launch binder' button to view and run the notebooks on 16 | a remote server. 17 | 18 | Copyright 19 | ========= 20 | All content © 2015 the authors. The code is distributed under the MIT license. 21 | 22 | `Pull requests `_ 23 | are welcome! If you find a bug, think something could use clarifying, 24 | or are generally interested in the further development of this project, 25 | please get in touch via the 26 | `issues `_! 27 | -------------------------------------------------------------------------------- /Simulator/Concepts/Inverse Transform Sampling.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Inverse Transform Sampling\n", 8 | "\n", 9 | "This notebook will conceptualize how inverse transform sampling works" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 2, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import numpy as np\n", 19 | "from matplotlib import pyplot as plt\n", 20 | "import numpy.random as ra\n", 21 | "\n", 22 | "%matplotlib inline" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "Below is a spectrum which follows an `almost` bell-curve type distribution (anyway, the specific type of distribution is not important here). " 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 118, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "text/plain": [ 40 | "[[1, 2, 3, 4, 5, 6], [2000, 4040, 6500, 6000, 4020, 2070]]" 41 | ] 42 | }, 43 | "execution_count": 118, 44 | "metadata": {}, 45 | "output_type": "execute_result" 46 | } 47 | ], 48 | "source": [ 49 | "spectrum = [[1, 2, 3, 4, 5, 6],[2000, 4040, 6500, 6000, 4020, 2070]]\n", 50 | "energies = np.array(spectrum[0])\n", 51 | "fluxes = np.array(spectrum[1])\n", 52 | "spectrum" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "Below, first we compute probabilities of flux. Afterwards, we compute the cumulative probability." 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 119, 65 | "metadata": {}, 66 | "outputs": [ 67 | { 68 | "data": { 69 | "text/plain": [ 70 | "array([ 0.08120179, 0.2452294 , 0.5091352 , 0.75274056, 0.91595615, 1. ])" 71 | ] 72 | }, 73 | "execution_count": 119, 74 | "metadata": {}, 75 | "output_type": "execute_result" 76 | } 77 | ], 78 | "source": [ 79 | "prob = fluxes/float(sum(fluxes))\n", 80 | "cum_prob = np.cumsum(prob)\n", 81 | "cum_prob" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "We draw ten thousand numbers from uniform random distribution." 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 128, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "data": { 98 | "text/plain": [ 99 | "array([ 0.49834338, 0.31993222, 0.35882619, 0.15837646, 0.22595417,\n", 100 | " 0.85575223, 0.85203039, 0.78380252, 0.04170078])" 101 | ] 102 | }, 103 | "execution_count": 128, 104 | "metadata": {}, 105 | "output_type": "execute_result" 106 | } 107 | ], 108 | "source": [ 109 | "N = 10000\n", 110 | "R = ra.uniform(0, 1, N)\n", 111 | "R[1:10]" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "We assign energies to events corresponding to the random number drawn.\n", 119 | "\n", 120 | "_Note: The command below finds bin interval using a single command. I am not sure though that it's very readble. Would\n", 121 | "we want to split that in multiple lines and maybe use explicit loops to make it more readable? Or is it fine as it is?\n", 122 | "Comments?_" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 129, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "data": { 132 | "text/plain": [ 133 | "[3, 3, 3, 2, 2, 5, 5, 5, 1]" 134 | ] 135 | }, 136 | "execution_count": 129, 137 | "metadata": {}, 138 | "output_type": "execute_result" 139 | } 140 | ], 141 | "source": [ 142 | "gen_energies = [int(energies[np.argwhere(cum_prob == min(cum_prob[(cum_prob - r) > 0]))]) for r in R]\n", 143 | "gen_energies[1:10]" 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": {}, 149 | "source": [ 150 | "Histogram energies to get shape approximation." 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 130, 156 | "metadata": {}, 157 | "outputs": [ 158 | { 159 | "data": { 160 | "text/plain": [ 161 | "array([ 825, 1652, 2626, 2466, 1589, 842], dtype=int64)" 162 | ] 163 | }, 164 | "execution_count": 130, 165 | "metadata": {}, 166 | "output_type": "execute_result" 167 | } 168 | ], 169 | "source": [ 170 | "gen_energies = ((np.array(gen_energies) - 1) / 1).astype(int)\n", 171 | "times = np.arange(1, 6, 1)\n", 172 | "lc = np.bincount(gen_energies, minlength=len(times))\n", 173 | "lc" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 131, 179 | "metadata": {}, 180 | "outputs": [ 181 | { 182 | "data": { 183 | "image/png": "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\nB35ZyuYD6wgeH8zdX91N51mdmfzbZI5fOO50xBRjwIAB9OzZkwEDBnDmzBnWrFnD/v37CQ4O5urV\nq/Fu4+QUnTf7Y6Bhw4bUrl2bv//+m3/++YeBAwfi5+eXhOn+K8VMZ+rJpBPJ/YZNOmRchm8YrmV7\nBej5+0urRkZqdHS0bj+2XQeuGagNJzZUv35+WvGb8tpjYQ9dvHexXoq85Gje5Pq7e+bMGc2WLZtO\nmzbtuufPnTunefLk0dGjR6uqap8+fbR58+batm1b9ff315EjR2qfPn20bdu2sduMHTtWAwMDNSAg\nQD/66KPrJh6Ku+6+fftURHTs2LFapEgRzZMnj/bt2zd2P+vWrdPKlStrjhw5tECBAvrSSy9pZGRk\n7HIR0T179vznvRw/flx9fHw0IiIi3vcaHh6uhQoV0k8++UQDAgK0aNGiOmHChNjlly9f1tdff12L\nFCmi+fLl0xdeeEEvXfr392bGjBn64IMPqp+fn5YoUUIXLFig7777rqZLl04zZ86s2bNn127dusVm\nHDJkiN5zzz1arFix2PccFRUVu7+goKDrJiGqUqWKvvrqq5ojRw4tXry4rlq1SseMGaOFCxfWvHnz\n6tixY2/yL3nnkw45/gWfGLfk+h/NJK1fjvyiAR/76fay+VSPHYt3nStHDumykhn1/dZ5tdI7d2n2\nDzJpnW+q6IAV/9Nfj/6q0dHRSZo5uf7uzp8/X319fa/78rqmQ4cO2qZNG1WN+ZLPkCGDzpo1S1VV\nL168qH369NF27dqpqurvv/+u2bJl01WrVmlkZKS+8cYbmiFDhuuKxLV1r31hPvfcc3r58mXdsmWL\nZsyYUXfs2KGqqhs3btS1a9dqdHS07t+/X++991796quvYnO5KxKqqiVLltQGDRrojBkz9O+//75u\nWXh4uKZPn17feOMNvXLlii5dulSzZs2qu3btUlXV7t27a+PGjfX06dN67tw5bdSokb7zzjuqqrp2\n7Vr19/ePfT+HDx/WnTt3qur1X/ZxM8adznTfvn3q4+Nz0yLh6+sbO4Xpe++9p0WKFNGXXnpJr1y5\nomFhYZo9e3Y9f/6823/LOy0SNnaTSRXOXj5Ly4lP8n/zlNIjfoSAgHjX881XgKq/RlD111/5cO1a\nTq1fxpKlK1i4vj9DHviGi5EXqVWsFsHFgqlVrBb5s+dP4ndyPfnglqMmeER7J6xf5vjx4wQEBODj\n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\n", 184 | "text/plain": [ 185 | "" 186 | ] 187 | }, 188 | "metadata": {}, 189 | "output_type": "display_data" 190 | } 191 | ], 192 | "source": [ 193 | "plot1, = plt.plot(lc/float(sum(lc)), 'r--', label='Assigned energies')\n", 194 | "plot2, = plt.plot(prob,'g',label='Original Spectrum')\n", 195 | "plt.xlabel('Energies')\n", 196 | "plt.ylabel('Probability')\n", 197 | "plt.legend(handles=[plot1,plot2])\n", 198 | "plt.show()" 199 | ] 200 | } 201 | ], 202 | "metadata": { 203 | "kernelspec": { 204 | "display_name": "Python 3", 205 | "language": "python", 206 | "name": "python3" 207 | }, 208 | "language_info": { 209 | "codemirror_mode": { 210 | "name": "ipython", 211 | "version": 3 212 | }, 213 | "file_extension": ".py", 214 | "mimetype": "text/x-python", 215 | "name": "python", 216 | "nbconvert_exporter": "python", 217 | "pygments_lexer": "ipython3", 218 | "version": "3.6.4" 219 | } 220 | }, 221 | "nbformat": 4, 222 | "nbformat_minor": 1 223 | } 224 | -------------------------------------------------------------------------------- /Simulator/Concepts/PowerLaw Spectrum.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Simulating Light Curves from Power Law Power Spectra\n", 8 | "\n", 9 | "In this notebook, we will show how to simulate a light curve from a power spectrum that \n", 10 | "follows a power law shape." 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": { 17 | "collapsed": true 18 | }, 19 | "outputs": [], 20 | "source": [ 21 | "import numpy as np\n", 22 | "from matplotlib import pyplot as plt\n", 23 | "\n", 24 | "%matplotlib inline" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "The power distribution is of the form `S(w) = (1/w)^B`. Define a function to recover time series from power law spectrum." 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 21, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "def simulate(B):\n", 41 | " \n", 42 | " N = 1024\n", 43 | " \n", 44 | " # Define frequencies from 0 to 2*pi\n", 45 | " w = np.linspace(0.001,2*np.pi,N)\n", 46 | " \n", 47 | " # Draw two set of 'N' guassian distributed numbers\n", 48 | " a1 = np.random.normal(size=N)\n", 49 | " a2 = np.random.normal(size=N)\n", 50 | " \n", 51 | " # Multiply by (1/w)^B to get real and imaginary parts\n", 52 | " real = a1 * np.power((1/w),B/2)\n", 53 | " imaginary = a2 * np.power((1/w),B/2)\n", 54 | " \n", 55 | " # Form complex numbers corresponding to each frequency\n", 56 | " f = [complex(r, i) for r,i in zip(real,imaginary)]\n", 57 | " \n", 58 | " # Obtain real valued time series\n", 59 | " f_conj = np.conjugate(np.array(f))\n", 60 | " \n", 61 | " # Obtain time series\n", 62 | " f_inv = np.fft.ifft(f_conj)\n", 63 | "\n", 64 | " return f_inv" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "Start with `B=1` to get a _flicker noise_ distribution." 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 22, 77 | "metadata": {}, 78 | "outputs": [ 79 | { 80 | "data": { 81 | "text/plain": [ 82 | "" 83 | ] 84 | }, 85 | "execution_count": 22, 86 | "metadata": {}, 87 | "output_type": "execute_result" 88 | }, 89 | { 90 | "data": { 91 | "image/png": "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\ngg==\n", 92 | "text/plain": [ 93 | "" 94 | ] 95 | }, 96 | "metadata": {}, 97 | "output_type": "display_data" 98 | } 99 | ], 100 | "source": [ 101 | "f = simulate(1)\n", 102 | "plt.plot(np.real(f)) \n", 103 | "plt.xlabel('Time')\n", 104 | "plt.ylabel('Counts')\n", 105 | "plt.title('Recovered LightCurve with B=1')" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "Try out with `B=2` to get _random walk_ distribution." 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 23, 118 | "metadata": {}, 119 | "outputs": [ 120 | { 121 | "data": { 122 | "text/plain": [ 123 | "" 124 | ] 125 | }, 126 | "execution_count": 23, 127 | "metadata": {}, 128 | "output_type": "execute_result" 129 | }, 130 | { 131 | "data": { 132 | "image/png": "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\ngg==\n", 133 | "text/plain": [ 134 | "" 135 | ] 136 | }, 137 | "metadata": {}, 138 | "output_type": "display_data" 139 | } 140 | ], 141 | "source": [ 142 | "f = simulate(2)\n", 143 | "plt.plot(np.real(f)) \n", 144 | "plt.xlabel('Time')\n", 145 | "plt.ylabel('Counts')\n", 146 | "plt.title('Recovered LightCurve with B=2')" 147 | ] 148 | } 149 | ], 150 | "metadata": { 151 | "kernelspec": { 152 | "display_name": "Python 3", 153 | "language": "python", 154 | "name": "python3" 155 | }, 156 | "language_info": { 157 | "codemirror_mode": { 158 | "name": "ipython", 159 | "version": 3 160 | }, 161 | "file_extension": ".py", 162 | "mimetype": "text/x-python", 163 | "name": "python", 164 | "nbconvert_exporter": "python", 165 | "pygments_lexer": "ipython3", 166 | "version": "3.6.4" 167 | } 168 | }, 169 | "nbformat": 4, 170 | "nbformat_minor": 1 171 | } 172 | -------------------------------------------------------------------------------- /Spectral Timing/epoch_0_data.csv: -------------------------------------------------------------------------------- 1 | 0.31491584,21322.9890449 2 | 0.31718183,19637.30440816 3 | 0.3178791,20124.67122449 4 | 0.31541646,20177.66559184 5 | 0.31163255,20143.96258776 6 | 0.31805821,20539.0451102 7 | 0.31607883,18437.11988936 8 | 0.31781091,19994.05321702 9 | 0.31439316,20693.13957551 10 | 0.31872715,20624.35227755 11 | 0.31767608,19968.43563265 12 | 0.31795691,19247.42695652 13 | 0.31709702,18000.40850612 14 | 0.31425569,20616.97029167 15 | 0.31928812,18601.32719184 16 | 0.31544998,20858.09026122 17 | 0.31819875,19715.29623673 18 | 0.31369992,21416.97766531 19 | 0.31791148,19576.30745306 20 | 0.3163053,20187.04023673 21 | 0.31874025,19656.32399184 22 | 0.31674924,19997.18293061 23 | 0.31812883,19831.49044898 24 | 0.31737681,19946.85754286 25 | 0.31725341,21645.71844898 26 | 0.31753883,19678.04736327 27 | 0.31643732,20377.09758367 28 | 0.31658794,20128.89139592 29 | 0.31700356,19864.60808163 30 | 0.31838127,20093.03293878 31 | 0.31718217,20793.53342857 32 | -------------------------------------------------------------------------------- /Transfer Functions/2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StingraySoftware/notebooks/43ba0594276c66e27a877488ec333b5c3e0b56b3/Transfer Functions/2d.png -------------------------------------------------------------------------------- /Transfer Functions/Data Preparation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import numpy as np\n", 12 | "from matplotlib import pyplot as plt\n", 13 | "%matplotlib inline" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 2, 19 | "metadata": { 20 | "collapsed": true 21 | }, 22 | "outputs": [], 23 | "source": [ 24 | "from stingray.simulator.transfer import TransferFunction" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "## Setting Up Data" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "We use `Image` module from Python Imaging library to digitize 2-d plot from Uttley et al. (2014)" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 3, 44 | "metadata": { 45 | "collapsed": true 46 | }, 47 | "outputs": [], 48 | "source": [ 49 | "from PIL import Image" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 4, 55 | "metadata": { 56 | "collapsed": false 57 | }, 58 | "outputs": [], 59 | "source": [ 60 | "im = Image.open('2d.png')\n", 61 | "width, height = im.size" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "Initialize an intensity array." 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 5, 74 | "metadata": { 75 | "collapsed": false 76 | }, 77 | "outputs": [], 78 | "source": [ 79 | "intensity = np.array([[1 for j in range(width)] for i in range(height)])" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "Below, we retrieve each pixel and then calculate darkness value. The perceived brightness is given by:\n", 87 | "\n", 88 | "_0.2126*R + 0.7152*G + 0.0722*B_\n", 89 | "\n", 90 | "To get darkness, the formula is corrected as follows:\n", 91 | "\n", 92 | "_0.2126*(255-R) + 0.7152*(255-G) + 0.0722*(255-B)_" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 6, 98 | "metadata": { 99 | "collapsed": false 100 | }, 101 | "outputs": [], 102 | "source": [ 103 | "for x in range(0, height):\n", 104 | " for y in range(0, width):\n", 105 | " RGB = im.getpixel((y, x))\n", 106 | " intensity[x][y] = (0.2126 * (255-RGB[0]) + 0.7152 * (255-RGB[1]) + 0.0722 * (255-RGB[2]))" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": {}, 112 | "source": [ 113 | "Invert along Y-axis to account for some conventions." 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 7, 119 | "metadata": { 120 | "collapsed": true 121 | }, 122 | "outputs": [], 123 | "source": [ 124 | "intensity = intensity[::-1]" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 8, 130 | "metadata": { 131 | "collapsed": true 132 | }, 133 | "outputs": [], 134 | "source": [ 135 | "np.savetxt('intensity.txt', intensity)" 136 | ] 137 | } 138 | ], 139 | "metadata": { 140 | "kernelspec": { 141 | "display_name": "py310", 142 | "language": "python", 143 | "name": "python3" 144 | }, 145 | "language_info": { 146 | "codemirror_mode": { 147 | "name": "ipython", 148 | "version": 3 149 | }, 150 | "file_extension": ".py", 151 | "mimetype": "text/x-python", 152 | "name": "python", 153 | "nbconvert_exporter": "python", 154 | "pygments_lexer": "ipython3", 155 | "version": "3.10.8" 156 | } 157 | }, 158 | "nbformat": 4, 159 | "nbformat_minor": 0 160 | } 161 | -------------------------------------------------------------------------------- /Transfer Functions/TransferFunction Tutorial.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Contents" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "This notebook covers the basics of creating TransferFunction object, obtaining time and energy resolved responses, plotting them and using IO methods available. Finally, artificial responses are introduced which provide a way for quick testing." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Setup" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "Set up some useful libraries." 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 1, 34 | "metadata": { 35 | "collapsed": true 36 | }, 37 | "outputs": [], 38 | "source": [ 39 | "import numpy as np\n", 40 | "from matplotlib import pyplot as plt\n", 41 | "%matplotlib inline" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "metadata": {}, 47 | "source": [ 48 | "Import relevant stingray libraries." 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 2, 54 | "metadata": { 55 | "collapsed": true 56 | }, 57 | "outputs": [], 58 | "source": [ 59 | "from stingray.simulator.transfer import TransferFunction\n", 60 | "from stingray.simulator.transfer import simple_ir, relativistic_ir" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "# Creating TransferFunction" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "A transfer function can be initialized by passing a 2-d array containing time across the first dimension and energy across the second. For example, if the 2-d array is defined by `arr`, then `arr[1][5]` defines a time of 5 units and energy of 1 unit.\n", 75 | "\n", 76 | "For the purpose of this tutorial, we have stored a 2-d array in a text file named `intensity.txt`. The script to generate this file is explained in `Data Preparation` notebook." 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 3, 82 | "metadata": { 83 | "collapsed": false 84 | }, 85 | "outputs": [], 86 | "source": [ 87 | "response = np.loadtxt('intensity.txt')" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "Initialize transfer function by passing the array defined above." 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 4, 100 | "metadata": { 101 | "collapsed": false 102 | }, 103 | "outputs": [ 104 | { 105 | "data": { 106 | "text/plain": [ 107 | "(524, 744)" 108 | ] 109 | }, 110 | "execution_count": 4, 111 | "metadata": {}, 112 | "output_type": "execute_result" 113 | } 114 | ], 115 | "source": [ 116 | "transfer = TransferFunction(response)\n", 117 | "transfer.data.shape" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "By default, time and energy spacing across both axes are set to 1. However, they can be changed by supplying additional parameters `dt` and `de`." 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "# Obtaining Time-Resolved Response" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "The 2-d transfer function can be converted into a time-resolved/energy-averaged response." 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 5, 144 | "metadata": { 145 | "collapsed": false 146 | }, 147 | "outputs": [], 148 | "source": [ 149 | "transfer.time_response()" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "This sets `time` parameter which can be accessed by `transfer.time`" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 6, 162 | "metadata": { 163 | "collapsed": false 164 | }, 165 | "outputs": [ 166 | { 167 | "data": { 168 | "text/plain": [ 169 | "array([0., 0., 0., 0., 0., 0., 0., 0., 0.])" 170 | ] 171 | }, 172 | "execution_count": 6, 173 | "metadata": {}, 174 | "output_type": "execute_result" 175 | } 176 | ], 177 | "source": [ 178 | "transfer.time[1:10]" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "Additionally, energy interval over which to average, can be specified by specifying `e0` and `e1` parameters." 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "# Obtaining Energy-Resolved Response" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "Energy-resolved/time-averaged response can be also be formed from 2-d transfer function." 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 7, 205 | "metadata": { 206 | "collapsed": true 207 | }, 208 | "outputs": [], 209 | "source": [ 210 | "transfer.energy_response()" 211 | ] 212 | }, 213 | { 214 | "cell_type": "markdown", 215 | "metadata": {}, 216 | "source": [ 217 | "This sets `energy` parameter which can be accessed by `transfer.energy`" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": 8, 223 | "metadata": { 224 | "collapsed": false 225 | }, 226 | "outputs": [ 227 | { 228 | "data": { 229 | "text/plain": [ 230 | "array([0., 0., 0., 0., 0., 0., 0., 0., 0.])" 231 | ] 232 | }, 233 | "execution_count": 8, 234 | "metadata": {}, 235 | "output_type": "execute_result" 236 | } 237 | ], 238 | "source": [ 239 | "transfer.energy[1:10]" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": {}, 245 | "source": [ 246 | "# Plotting Responses" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "TransferFunction() creates plots of `time-resolved`, `energy-resolved` and `2-d responses`. These plots can be saved by setting `save` parameter. " 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 9, 259 | "metadata": { 260 | "collapsed": false 261 | }, 262 | "outputs": [], 263 | "source": [ 264 | "transfer.plot(response='2d')" 265 | ] 266 | }, 267 | { 268 | "cell_type": "code", 269 | "execution_count": 10, 270 | "metadata": { 271 | "collapsed": false 272 | }, 273 | "outputs": [], 274 | "source": [ 275 | "transfer.plot(response='time')" 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": 11, 281 | "metadata": { 282 | "collapsed": false 283 | }, 284 | "outputs": [], 285 | "source": [ 286 | "transfer.plot(response='energy')" 287 | ] 288 | }, 289 | { 290 | "cell_type": "markdown", 291 | "metadata": {}, 292 | "source": [ 293 | "By enabling `save=True` parameter, the plots can be also saved." 294 | ] 295 | }, 296 | { 297 | "cell_type": "markdown", 298 | "metadata": {}, 299 | "source": [ 300 | "# IO" 301 | ] 302 | }, 303 | { 304 | "cell_type": "markdown", 305 | "metadata": {}, 306 | "source": [ 307 | "TransferFunction can be saved in pickle format and retrieved later." 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 12, 313 | "metadata": { 314 | "collapsed": true 315 | }, 316 | "outputs": [], 317 | "source": [ 318 | "transfer.write('transfer.pickle')" 319 | ] 320 | }, 321 | { 322 | "cell_type": "markdown", 323 | "metadata": {}, 324 | "source": [ 325 | "Saved files can be read using static `read()` method." 326 | ] 327 | }, 328 | { 329 | "cell_type": "code", 330 | "execution_count": 13, 331 | "metadata": { 332 | "collapsed": false 333 | }, 334 | "outputs": [ 335 | { 336 | "data": { 337 | "text/plain": [ 338 | "array([0., 0., 0., 0., 0., 0., 0., 0., 0.])" 339 | ] 340 | }, 341 | "execution_count": 13, 342 | "metadata": {}, 343 | "output_type": "execute_result" 344 | } 345 | ], 346 | "source": [ 347 | "transfer_new = TransferFunction.read('transfer.pickle')\n", 348 | "transfer_new.time[1:10]" 349 | ] 350 | }, 351 | { 352 | "cell_type": "markdown", 353 | "metadata": {}, 354 | "source": [ 355 | "# Artificial Responses" 356 | ] 357 | }, 358 | { 359 | "cell_type": "markdown", 360 | "metadata": {}, 361 | "source": [ 362 | "For quick testing, two helper impulse response models are provided." 363 | ] 364 | }, 365 | { 366 | "cell_type": "markdown", 367 | "metadata": {}, 368 | "source": [ 369 | "### 1- Simple IR" 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": {}, 375 | "source": [ 376 | "simple_ir() allows to define an impulse response of constant height. It takes in time resolution starting time, width and intensity as arguments." 377 | ] 378 | }, 379 | { 380 | "cell_type": "code", 381 | "execution_count": 14, 382 | "metadata": { 383 | "collapsed": false 384 | }, 385 | "outputs": [ 386 | { 387 | "data": { 388 | "text/plain": [ 389 | "[]" 390 | ] 391 | }, 392 | "execution_count": 14, 393 | "metadata": {}, 394 | "output_type": "execute_result" 395 | }, 396 | { 397 | "data": { 398 | "image/png": "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DixlZWU6ceKEVq1apUAgoLy8PNXV1XmTZltbWxUff7HjZsaMGdqwYYNWrFih5cuXa9KkSdqyZYumTp3qlXn88cfV2dmpBx98UKdOndKdd96puro6paSkDMIlAgCAL7uI92GJRezDAgDAl08kf795lhAAAIh5BBYAABDzCCwAACDmEVgAAEDMI7AAAICYR2ABAAAxj8ACAABiHoEFAADEPAILAACIeRFvzR+LejbrDQaDUa4JAADor56/2/3ZdN9EYDl9+rQkKTMzM8o1AQAAkTp9+rTS0tL6LGPiWUKO4+j48eMaPXq04uLiBvXcwWBQmZmZOnr0KM8p6gfaKzK0V//RVpGhvSJDe0VmsNrLdV2dPn1aGRkZYQ9O7o2JHpb4+HiNHz9+SH9GamoqN3EEaK/I0F79R1tFhvaKDO0VmcForyv1rPRg0i0AAIh5BBYAABDzCCxXkJycrNWrVys5OTnaVflSoL0iQ3v1H20VGdorMrRXZKLRXiYm3QIAANvoYQEAADGPwAIAAGIegQUAAMQ8AgsAAIh5BJYrqKmpUVZWllJSUlRYWKimpqZoVynqqqurNX36dI0ePVrXX3+9SktLdfDgwbAyZ8+e1YIFCzR27Fhde+21+t73vqe2trYo1Ti2PPXUU4qLi9PixYu9Y7RXuGPHjun73/++xo4dq5EjRyonJ0d79+713nddV6tWrdINN9ygkSNHqri4WIcOHYpijaMjFApp5cqVmjhxokaOHKmvfvWreuKJJ8KeyzKc2+o3v/mNvvOd7ygjI0NxcXHasmVL2Pv9aZtPP/1Uc+bMUWpqqsaMGaP58+frs88+u4pXcfX01V7nzp3T0qVLlZOTo1GjRikjI0Nz587V8ePHw84xlO1FYOnDpk2bVFlZqdWrV6ulpUW5ubkqKSlRe3t7tKsWVTt37tSCBQv07rvvqr6+XufOndO3v/1tdXZ2emUeffRRvf7669q8ebN27typ48eP6957741irWPDnj179NOf/lS33HJL2HHa66L//u//1h133KERI0bojTfe0AcffKA1a9boK1/5ilfmmWee0QsvvKDa2lrt3r1bo0aNUklJic6ePRvFml99Tz/9tF566SWtW7dOH374oZ5++mk988wzevHFF70yw7mtOjs7lZubq5qaml7f70/bzJkzR++//77q6+u1bds2/eY3v9GDDz54tS7hquqrvc6cOaOWlhatXLlSLS0tevXVV3Xw4EHdfffdYeWGtL1cXFZBQYG7YMEC7/tQKORmZGS41dXVUaxV7Glvb3cluTt37nRd13VPnTrljhgxwt28ebNX5sMPP3QluY2NjdGqZtSdPn3anTRpkltfX+/OnDnTXbRokeu6tNcfW7p0qXvnnXde9n3HcVy/3+/+/d//vXfs1KlTbnJysvvLX/7yalQxZsyePdv9wQ9+EHbs3nvvdefMmeO6Lm11KUnua6+95n3fn7b54IMPXEnunj17vDJvvPGGGxcX5x47duyq1T0a/ri9etPU1ORKco8cOeK67tC3Fz0sl9Hd3a3m5mYVFxd7x+Lj41VcXKzGxsYo1iz2dHR0SJKuu+46SVJzc7POnTsX1nbZ2dmaMGHCsG67BQsWaPbs2WHtItFef2zr1q3Kz8/XX/3VX+n666/Xrbfeqn/4h3/w3j98+LACgUBYe6WlpamwsHDYtdeMGTPU0NCgjz/+WJL0H//xH3rnnXf053/+55Joq770p20aGxs1ZswY5efne2WKi4sVHx+v3bt3X/U6x5qOjg7FxcVpzJgxkoa+vUw8/HAonDx5UqFQSD6fL+y4z+fTRx99FKVaxR7HcbR48WLdcccdmjp1qiQpEAgoKSnJu4l7+Hw+BQKBKNQy+jZu3KiWlhbt2bPnC+/RXuF+//vf66WXXlJlZaWWL1+uPXv26JFHHlFSUpIqKiq8Nunt3+Zwa69ly5YpGAwqOztbCQkJCoVCevLJJzVnzhxJoq360J+2CQQCuv7668PeT0xM1HXXXTfs2+/s2bNaunSpysvLvYcfDnV7EVjwJ1mwYIEOHDigd955J9pViVlHjx7VokWLVF9fr5SUlGhXJ+Y5jqP8/Hz93d/9nSTp1ltv1YEDB1RbW6uKiooo1y62/Mu//IteeeUVbdiwQTfffLP279+vxYsXKyMjg7bCkDl37pzuu+8+ua6rl1566ar9XIaELiM9PV0JCQlfWKnR1tYmv98fpVrFlocffljbtm3Tjh07NH78eO+43+9Xd3e3Tp06FVZ+uLZdc3Oz2tvbddtttykxMVGJiYnauXOnXnjhBSUmJsrn89Fel7jhhhs0ZcqUsGOTJ09Wa2urJHltwr9NacmSJVq2bJnuv/9+5eTk6IEHHtCjjz6q6upqSbRVX/rTNn6//wuLLP7whz/o008/Hbbt1xNWjhw5ovr6eq93RRr69iKwXEZSUpKmTZumhoYG75jjOGpoaFBRUVEUaxZ9ruvq4Ycf1muvvaa33npLEydODHt/2rRpGjFiRFjbHTx4UK2trcOy7b71rW/pd7/7nfbv3++98vPzNWfOHO+/aa+L7rjjji8sk//444914403SpImTpwov98f1l7BYFC7d+8edu115swZxceH/xpPSEiQ4ziSaKu+9KdtioqKdOrUKTU3N3tl3nrrLTmOo8LCwqte52jrCSuHDh3Sm2++qbFjx4a9P+Tt9SdP2zVs48aNbnJysvvyyy+7H3zwgfvggw+6Y8aMcQOBQLSrFlV//dd/7aalpblvv/22+8knn3ivM2fOeGUeeughd8KECe5bb73l7t271y0qKnKLioqiWOvYcukqIdelvS7V1NTkJiYmuk8++aR76NAh95VXXnGvueYa9xe/+IVX5qmnnnLHjBnj/uu//qv73nvvud/97nfdiRMnup9//nkUa371VVRUuOPGjXO3bdvmHj582H311Vfd9PR09/HHH/fKDOe2On36tLtv3z533759riT3ueeec/ft2+etaulP28yaNcu99dZb3d27d7vvvPOOO2nSJLe8vDxalzSk+mqv7u5u9+6773bHjx/v7t+/P+x3f1dXl3eOoWwvAssVvPjii+6ECRPcpKQkt6CgwH333XejXaWok9Tr6+c//7lX5vPPP3f/5m/+xv3KV77iXnPNNe4999zjfvLJJ9GrdIz548BCe4V7/fXX3alTp7rJycludna2u379+rD3HcdxV65c6fp8Pjc5Odn91re+5R48eDBKtY2eYDDoLlq0yJ0wYYKbkpLi3nTTTe6PfvSjsD8gw7mtduzY0evvqoqKCtd1+9c2//Vf/+WWl5e71157rZuamurOmzfPPX36dBSuZuj11V6HDx++7O/+HTt2eOcYyvaKc91LtkQEAACIQcxhAQAAMY/AAgAAYh6BBQAAxDwCCwAAiHkEFgAAEPMILAAAIOYRWAAAQMwjsAAAgJhHYAEAADGPwAIAAGIegQUAAMQ8AgsAAIh5/x8uvy+k5PrzdQAAAABJRU5ErkJggg==", 399 | "text/plain": [ 400 | "
" 401 | ] 402 | }, 403 | "metadata": {}, 404 | "output_type": "display_data" 405 | } 406 | ], 407 | "source": [ 408 | "s_ir = simple_ir(dt=0.125, start=10, width=5, intensity=0.1)\n", 409 | "plt.plot(s_ir)" 410 | ] 411 | }, 412 | { 413 | "cell_type": "markdown", 414 | "metadata": {}, 415 | "source": [ 416 | "### 2- Relativistic IR" 417 | ] 418 | }, 419 | { 420 | "cell_type": "markdown", 421 | "metadata": {}, 422 | "source": [ 423 | "A more realistic impulse response mimicking black hole dynamics can be created using relativistic_ir(). Its arguments are: time_resolution, primary peak time, secondary peak time, end time, primary peak value, secondary peak value, rise slope and decay slope. These paramaters are set to appropriate values by default." 424 | ] 425 | }, 426 | { 427 | "cell_type": "code", 428 | "execution_count": 15, 429 | "metadata": { 430 | "collapsed": false 431 | }, 432 | "outputs": [ 433 | { 434 | "data": { 435 | "text/plain": [ 436 | "[]" 437 | ] 438 | }, 439 | "execution_count": 15, 440 | "metadata": {}, 441 | "output_type": "execute_result" 442 | }, 443 | { 444 | "data": { 445 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy89olMNAAAACXBIWXMAAA9hAAAPYQGoP6dpAABEzklEQVR4nO3deXhU5fk38O+ZNetMNjJZyMYuW4gBYkRFJYpIaV3aolJBrPbVUoumrRIVkFqJ/qwWqwiKILaKoFRxAVGMAqIIJBAWZU8gISEbIZmsM5mZ8/6RzCSBBDLJJGfOzPdzXXMBZ86ZuY9j7tzzPPd5jiCKoggiIiIiiSikDoCIiIi8G4sRIiIikhSLESIiIpIUixEiIiKSFIsRIiIikhSLESIiIpIUixEiIiKSFIsRIiIikpRK6gC6wmazobi4GIGBgRAEQepwiIiIqAtEUURNTQ2ioqKgUHQ+/iGLYqS4uBgxMTFSh0FERETdUFhYiP79+3f6vCyKkcDAQADNJ6PT6SSOhoiIiLrCaDQiJibG8Xu8M7IoRuxTMzqdjsUIERGRzFyuxYINrERERCQpFiNEREQkKRYjREREJCkWI0RERCQpFiNEREQkKRYjREREJCkWI0RERCQpFiNEREQkKRYjREREJCmni5Ht27dj2rRpiIqKgiAI2LBhQ5eP/f7776FSqTBmzBhn35aIiIg8lNPFSF1dHRITE7F06VKnjquqqsLMmTMxadIkZ9+SiIiIPJjT96aZMmUKpkyZ4vQbPfTQQ7jnnnugVCqdGk0hIiIiz9YnPSNvv/028vLysHDhwi7tbzKZYDQa2z2I6NLqzRYs23oSpyrqpA6FiMgpvV6MHD9+HPPmzcO7774LlaprAzGZmZnQ6/WOR0xMTC9HSSR/G/YV44XNR7Dk62NSh0JE5JReLUasVivuueceLFq0CEOGDOnycRkZGaiurnY8CgsLezFKIs9w+lzziEh5rUniSIiInON0z4gzampqkJ2djX379uFPf/oTAMBms0EURahUKnz11Ve48cYbLzpOq9VCq9X2ZmhEHudMVQMAoKbRInEkRETO6dViRKfT4eDBg+22vf766/jmm2+wfv16JCQk9ObbE3mVYhYjRCRTThcjtbW1OHHihOPf+fn5yM3NRUhICGJjY5GRkYGioiL85z//gUKhwMiRI9sdHx4eDh8fn4u2E1HPtBYjTRJHQkTkHKeLkezsbNxwww2Of6enpwMAZs2ahdWrV+Ps2bMoKChwXYREdFlmiw1lNc29IkaOjBCRzAiiKIpSB3E5RqMRer0e1dXV0Ol0UodD5HYKztXjuhe/dfz76D9ugVallDAiIqKu//7mvWmIPEBRyxSNHftGiEhOWIwQeYBiFiNEJGMsRog8wMUjI2xiJSL5YDFC5AE4MkJEcsZihMgDcGSEiOSMxQiRB7CPjPiqm6+gMTZwZISI5IPFCJHMiaLoGBkZYggAABg5MkJEMsJihEjmztc3obHJBgAYbAgEwJ4RIpIXFiNEMmefoukXqEVogAYAixEikhcWI0Qyd+Z8czESHeQLnY8aABtYiUheWIwQyZx9ZCQ6yBeBPs23m+LICBHJCYsRIpmzFyNRQT6txYiJIyNEJB8sRohkrrjaXoz4IlBrn6bhyAgRyQeLESKZKzrPaRoikjeV1AEQUc8UVTUCaB4ZUQgCADawEpG8sBghkrHGJisqak0AmkdGak3NIyJGjowQkYywGCGSsbPVzaMivmolgvzUjpERs8UGk8UKrUopZXhERF3CnhEiGXNc1hvsC0EQEODT+v2CfSNEJBcsRohkrKiq9UoaAFAqBPhrmkdDWIwQkVywGCGSsdYFz3wc2wK5CisRyQyLESIZa3tZrx0v7yUiuWExQiRjbRc8s9P5cmSEiOSFxQiRjBW3WWPEzj4ywst7iUguWIwQyZTNJjoaWNtP03BJeCKSFxYjRDJ1rs4Ms8UGQQAi9G0bWO09I5ymISJ5YDFCJFP2K2kMgT5QK1t/lNnASkRyw2KESKaKHWuM+LTbruOlvUQkMyxGiGTqwgXP7DgyQkRyw2KESKaK2iwF3xaLESKSGxYjRDJV3MGVNAAQqOU0DRHJC4sRIplyTNPoOTJCRPLGYoRIpjpa8AxoXWeEi54RkVywGCGSoQazFZV1ZgCX6hnhNA0RyQOLESIZst+TJkCrgq6l+LCzX9prsthgttj6PDYiImexGCGSIfvdeqOCfCAIQrvnAtoUJxwdISI5YDFCJEOdXUkDAEqFAH+NEgCbWIlIHliMEMlQcScLntnxZnlEJCdOFyPbt2/HtGnTEBUVBUEQsGHDhkvu/9FHH+Gmm25Cv379oNPpkJqaii+//LK78RIRgDOXLUbYxEpE8uF0MVJXV4fExEQsXbq0S/tv374dN910EzZt2oScnBzccMMNmDZtGvbt2+d0sETU7FLTNEBrMcLLe4lIDlSX36W9KVOmYMqUKV3ef8mSJe3+vXjxYnzyySf47LPPkJSU5OzbExFa1xi58LJeu0DeLI+IZMTpYqSnbDYbampqEBIS0uk+JpMJJpPJ8W+j0dgXoRHJgs0m4mx1V6dpODJCRO6vzxtY//nPf6K2tha//e1vO90nMzMTer3e8YiJienDCInc28nyWjRZRfiqlTAEajvchw2sRCQnfVqMrFmzBosWLcIHH3yA8PDwTvfLyMhAdXW141FYWNiHURK5t92nKgEASbFBUCk7/hHWsYGViGSkz6Zp1q5diwceeAAffvgh0tLSLrmvVquFVtvxNz4ib5d96jwAYGx851OdnKYhIjnpk5GR999/H7Nnz8b777+PqVOn9sVbEnmsPS0jI+PigzvdxzFNY+LICBG5P6dHRmpra3HixAnHv/Pz85Gbm4uQkBDExsYiIyMDRUVF+M9//gOgeWpm1qxZeOWVV5CSkoKSkhIAgK+vL/R6vYtOg8g7nK1uwJnzDVAIQFLspYqRlkt7GzgyQkTuz+mRkezsbCQlJTkuy01PT0dSUhIWLFgAADh79iwKCgoc+7/55puwWCyYM2cOIiMjHY+5c+e66BSIvId9imZElB4B2s6/S/DSXiKSE6dHRq6//nqIotjp86tXr273761btzr7FkTUieyWKZqxl5iiAdgzQkTywnvTEMnInpaRkXGXaF4FuAIrEckLixEimTA2NuFwSfMCgGPjLj0youM0DRHJCIsRIpnYe/o8RBGIC/VDuM7nkvvaR0ZMFhvMFltfhEdE1G0sRohkwrG+SNylp2gAtGtu5egIEbk7FiNEMtGV9UXsVEoF/DRKAGxiJSL3x2KESAbMFhtyC6sAAOMSLj8yAvCKGiKSDxYjRDJwqLgaJosNIf4aDAjz79IxXGuEiOSCxQiRDOzJb1lfJC4YgiB06Rhe3ktEcsFihEgGurq+SFscGSEiuWAxQuTmbDYROae7tvJqWzr2jBCRTLAYIXJzeRW1OF/fBB+1AiOiun5zydaRERYjROTeWIwQuTn7FM2YmCBoVF3/kW0dGeE0DRG5NxYjRG6udX2RrveLALy0l4jkg8UIkZvL7kbzKtBmmsbEkREicm8sRojcWKmxEQWV9VAIQFJskFPHcmSEiOSCxQiRG7NP0VwRqXOMdHSVfX+uM0JE7o7FCJEb253fvX4RoO3ICKdpiMi9sRghclN1Jgs+yS0GAEwYFOb08ZymISK5YDFC5KbW7ilEdUMTEsL8ceOwcKeP13EFViKSCRYjRG7IbLHhre/yAAB/uG4AlIqu3Y+mLfvISGOTDU1Wm0vjIyJyJRYjRG7o0/3FOFvdiH6BWtyeFN2t1wjQqhx/51QNEbkzFiNEbsZmE/HGtpMAgPsnJMBHrezW66iUCvhpmo/lVA0RuTMWI0RuJutIGY6X1SJQq8KMq2J79FpsYiUiOWAxQuRmlreMisy4Ks7RhNpdrWuNcGSEiNwXixEiN7LnVCVyTp+HRqnA/RPie/x6HBkhIjlgMULkRpZvbR4VuTM5GuE6nx6/nuP+NCxGiMiNsRghchNHS2qQdaQMggD84bqBLnlNrsJKRHLAYoTITdivoJkyMgIJYf4ueU0dp2mISAZYjBC5gZPltfh0f/PS7w9NdM2oCNB2moYjI0TkvliMEEms1NiIWat2w2ITce3gMIzuH+Sy1w7UcmSEiNwfixEiCVXVm3Hvyl04c74B8aF+ePm3Y1z6+ryahojkgMUIkUTqzRbMXr0Hx0prYdBp8d/fp6BfoNal78F1RohIDliMEEnAZLHi//03B/sKqhDkp8Z/f5+CmBA/l78PR0aISA5YjBD1MatNRPq6/fjueAX8NEq8fd84DDEE9sp7sYGViORAdfldiMhVKmpN+PtnP2PjwbNQKwW8cW8ykmKDe+39ODJCRHLAYoSoD9SbLVj5XT7e2J6HWpMFCgF45a4kXDu4X6++r44rsBKRDLAYIepFFqsNH2SfwZKvj6GsxgQAGN1fjydvvQJXDQjt9fe3j4w0NFnRZLVBreTMLBG5H6cz0/bt2zFt2jRERUVBEARs2LDhssds3boVV155JbRaLQYNGoTVq1d3I1QiebDZRPxcbMQb205i8pLtePLjgyirMSEmxBev3p2EDX+c0CeFCAAE+LR+3+DoCBG5K6dHRurq6pCYmIj7778fd9xxx2X3z8/Px9SpU/HQQw/hvffeQ1ZWFh544AFERkZi8uTJ3QqayJ2Iooiz1Y34Me8cvjtege+OV6Ci1uR4PthPjT9PGowZKXHQqPp2ZEKtVMBXrURDkxU1jU0I8df06fsTEXWF08XIlClTMGXKlC7vv3z5ciQkJOCll14CAFxxxRXYsWMH/vWvf7EYIdmwWG0ormrE6co6nDpXj9MVdThdWY+Cc/U4XVmHxiZbu/191UqkDgzFdYPDcEdyf0fvhhQCfVQtxQhHRojIPfV6z8jOnTuRlpbWbtvkyZPx6KOPdnqMyWSCydT6zdJoNPZWeEQdqqwzY/m2kzhWWoPT5+pRWFkPi03sdH+FAFwRqcN1Q/rhusH9cGVcELQqZR9G3LlAHxXKakxc+IyI3FavFyMlJSUwGAztthkMBhiNRjQ0NMDX1/eiYzIzM7Fo0aLeDo2oU+v2FOLN7XnttmlUCsSF+CEu1A9xof6IC/VDbIgf4kP9ER3s67bNocF+GgB1KDOaLrsvEZEU3PJqmoyMDKSnpzv+bTQaERMTI2FE5G3sowgTh/TD/5s4APGh/ojQ+UChECSOzHmj+wch+/R55Jw+j9uSoqUOh4joIr1ejERERKC0tLTdttLSUuh0ug5HRQBAq9VCq3XtPTqInNFkae4BGRYZiKsHhkkcTc+MTwjBqu/zsTu/UupQiIg61OvjyqmpqcjKymq3bcuWLUhNTe3ttybqtiZrczGicdOpF2eMi29e4fVoaQ3O15kljoaI6GJOZ9ra2lrk5uYiNzcXQPOlu7m5uSgoKADQPMUyc+ZMx/4PPfQQ8vLy8Pjjj+PIkSN4/fXX8cEHH+Cxxx5zzRkQ9QKztblZ1V37QJwRGqDFoPAAAMCeUxwdISL343Smzc7ORlJSEpKSkgAA6enpSEpKwoIFCwAAZ8+edRQmAJCQkICNGzdiy5YtSExMxEsvvYS33nqLl/WSW7OPjHhCMQI0T9UA4FQNEbklp3tGrr/+eohi55c4drS66vXXX499+/Y5+1ZEkmktRuTXsNqRlIQQrNlVgN0cGSEiN+QZX/uIXMzRM9LHK6b2lnHxzSMjh4qqUWvi4mdE5F48I9MSuZjZ4jk9IwAQFeSLmBBf2EQg5/R5qcMhImrHMzItkYt5Ws8IAIyPb7453+78cxJHQkTUnudkWiIX8rSeEaC5bwRgEysRuR8WI0Qd8KR1RuzsV9TsL6xGY5NV4miIiFp5TqYlciFPWmfELi7UD+GBWpitNuQWVkkdDhGRg+dkWiIXsi8Hr/aQq2kAQBAErjdCRG7JczItkQt5Ys8IwL4RInJPLEaIOuCJPSMAMD6h+YqanNPnHedIRCQ1z8q0RC7S5IE9IwAwODwAQX5qNDRZcaioWupwiIgAsBgh6pDZA9cZAQCFQnCsxsqpGiJyF56VaYlcpHU5eM/qGQHYN0JE7ofFCFEHHFfTeNjICNC63sieU5Ww2Tq/6SURUV/xvExL5AKe2jMCAMMjdfDXKGFstOBoaY3U4RARsRghupAoih7bMwIAKqUCV8YFA+BUDRG5B8/LtEQ9ZGkzdeFpl/basW+EiNyJZ2Zaoh5ou/6G2gMbWIHW9UZ25Z+DKLJvhIikxWKE6AJNltZfzp44TQMAiTF6+KqVqKg1s2+EiCTnmZmWqAfs/SKCAKgUnjkyolUpHVfV7DheIXE0ROTtWIwQXaCpTfOqIHhmMQIA1wwKAwDsOMFihIikxWKE6AKeel+aC10zuLkY2ZVXCZPFKnE0ROTNPDvbEnWDp96x90JDDYEIC9CgocmKfQVVUodDRF6MxQjRBcwWz13wrC2FQsAE+1QN+0aISEKenW2JuqHJgxc8uxD7RojIHXh+tiVyUutN8jz/x8PeN3LgTBWq65skjoaIvJXnZ1siJ5m9pGcEACL1vhjYzx82EdiZx9ERIpIGixGiC3jyTfI6wqkaIpKad2RbIic0WbynZwQArhncDwCbWIlIOt6RbYmc4C3rjNhdNSAESoWAU+fqUVhZL3U4ROSFvCPbEjnB0TPioTfJu1CgjxpjYoIAAN9zqoaIJMBihOgC3tYzArBvhIik5T3ZlqiLvGmdETv7Jb4/nDwHm028zN5ERK7lPdmWqIu8rWcEAMbEBCFAq0JlnRk/nzVKHQ4ReRnvybZEXWS2eM86I3ZqpQJXDQgBwKkaIup7LEaILuCNPSMAeJ8aIpKMd2Vboi5w9Ix4wXLwbV3b0jey+1QlGpusEkdDRN7Eu7ItURd4Y88IAAzsFwCDTguzxYbsU+elDoeIvEi3su3SpUsRHx8PHx8fpKSkYPfu3Zfcf8mSJRg6dCh8fX0RExODxx57DI2Njd0KmKi3edO9adoSBAHXDGpejfW74+USR0NE3sTpYmTdunVIT0/HwoULsXfvXiQmJmLy5MkoKyvrcP81a9Zg3rx5WLhwIQ4fPoyVK1di3bp1ePLJJ3scPFFvaLJ4Z88IAEwc2lyMfHu0459nIqLe4HS2ffnll/Hggw9i9uzZGD58OJYvXw4/Pz+sWrWqw/1/+OEHTJgwAffccw/i4+Nx88034+67777saAqRVLxxnRG7iYP7QakQcKy0lkvDE1GfcSrbms1m5OTkIC0trfUFFAqkpaVh586dHR5z9dVXIycnx1F85OXlYdOmTbj11ls7fR+TyQSj0djuQdRXHD0jXtbACgB6PzXGxgUDAL45wtERIuobTmXbiooKWK1WGAyGdtsNBgNKSko6POaee+7B3//+d1xzzTVQq9UYOHAgrr/++ktO02RmZkKv1zseMTExzoRJ1CPe2jNiN+mKcABAFosRIuojvf7Vb+vWrVi8eDFef/117N27Fx999BE2btyIZ599ttNjMjIyUF1d7XgUFhb2dphEDt66zojdjcOav2z8ePIc6kwWiaMhIm+gcmbnsLAwKJVKlJaWttteWlqKiIiIDo+ZP38+7r33XjzwwAMAgFGjRqGurg5/+MMf8NRTT0GhuDjha7VaaLVaZ0Ijcpkmi/f2jADAwH7+iAv1w+lz9dhxogKTR3T8s01E5CpOZVuNRoPk5GRkZWU5ttlsNmRlZSE1NbXDY+rr6y8qOJRKJQBAFHlDLnI/3rrOiJ0gCLhhaPNUzTeHOVVDRL3P6Wybnp6OFStW4J133sHhw4fx8MMPo66uDrNnzwYAzJw5ExkZGY79p02bhmXLlmHt2rXIz8/Hli1bMH/+fEybNs1RlBC5E0fPiMo7e0aA1r6Rb46W8S6+RNTrnJqmAYDp06ejvLwcCxYsQElJCcaMGYPNmzc7mloLCgrajYQ8/fTTEAQBTz/9NIqKitCvXz9MmzYNzz33nOvOgsiFvPnSXrvxCSHw1yhRXmPCoeJqjO4fJHVIROTBBFEGcyVGoxF6vR7V1dXQ6XRSh0Me7s5lPyDn9Hm8cW+yV/dLPPTfHGz+qQRzJw3GYzcNkTocIpKhrv7+9t6vfkSdMFu8u2fE7kb7VA0v8SWiXubd2ZaoA5ymaWZvYj1YVI1SI+8lRUS9x7uzLVEHvH3RM7t+gVokxgQBAL7l6AgR9SIWI0QXcIyMeOFy8BeaNIyrsRJR72O2JbqA/a693t4zAgA3thQjO45XoLHJKnE0ROSpmG2JLsCekVYjonQw6LRoaLLix7xzUodDRB6K2ZboAuwZaSUIguNeNbyqhoh6C4sRogtwZKQ9R9/I4TLewoGIegWzLdEF7Hft1bCBFQAwYVAYtCoFiqoacLS0RupwiMgDMdsStWG1ibC23IuFIyPNfDVKXDs4DADwxcESiaMhIk/EbEvUhn2KBmDPSFtTRkYCAL44dFbiSIjIE7EYIWqjfTHCHw+7tCsMUCsFHCutxYkyTtUQkWsx2xK1Ye8XAViMtKX3U2PCIE7VEFHvYLYlasM+MqJUCFAqOE3T1q0tUzWbDrEYISLXYjFC1Ib9jr3sF7nYzSMMUCkEHD5rRH5FndThEJEHYTFC1AbXGOlckJ8GqQNDAbCRlYhcixmXqA3HGiMsRjp066iWq2rYN0JELsSMS9QGR0Yu7ebhBigE4GBRNQor66UOh4g8BDMuURuO+9Ko2DPSkdAALa4awKkaInItFiNEbTRZODJyOVNapmo2cqqGiFyEGZeoDfaMXN7kEQYIArC/sApnznOqhoh6jhmXqA32jFxeeKAPxsWHAAA2c80RInIBZlyiNhw9I1xn5JJuHRkBAPiCxQgRuQCLEaI2ODLSNfa+kZzT51FS3ShxNEQkd8y4RG3YixGNij8al2LQ+WBsXDAAYDOvqiGiHmLGJWqjydLcwMqRkcuzj45s4lU1RNRDzLhEbbBnpOtuHRUBQQB2n6rkVTVE1CMsRojaYM9I10XqfXFVQvMCaBv2FUkcDRHJGTMuURuOnhEWI11yx5XRAICP9hVBFEWJoyEiuWLGJWrDvugZR0a6ZsqoSPioFcgrr8OBM9VSh0NEMsWMS9SG2cJ70zgjQKvCzcOb1xz5mFM1RNRNLEaI2mDPiPNub5mq+XR/seO/HxGRM5hxidpgz4jzrh0UhrAALSrrzNh2tFzqcIhIhphxidpgz4jzVEoFfpkYBYBTNUTUPcy4RG2YOU3TLfararYcLkV1Q5PE0RCR3DDjErXRxAbWbhkRpcMQQwDMFhu+OMjl4YnIOSxGiNpgz0j3CIKA25P6A2hec4SIyBndyrhLly5FfHw8fHx8kJKSgt27d19y/6qqKsyZMweRkZHQarUYMmQINm3a1K2AiXoTe0a677akqObl4fMrUVjJ5eGJqOuczrjr1q1Deno6Fi5ciL179yIxMRGTJ09GWVlZh/ubzWbcdNNNOHXqFNavX4+jR49ixYoViI6O7nHwRK7GnpHui9T7InUAl4cnIuc5nXFffvllPPjgg5g9ezaGDx+O5cuXw8/PD6tWrepw/1WrVqGyshIbNmzAhAkTEB8fj4kTJyIxMbHHwRO5WhNvlNcjd1zZPFXzMZeHJyInOFWMmM1m5OTkIC0trfUFFAqkpaVh586dHR7z6aefIjU1FXPmzIHBYMDIkSOxePFiWK3WTt/HZDLBaDS2exD1BUfPiIojI91xy8iI5uXhK+qwn8vDE1EXOZVxKyoqYLVaYTAY2m03GAwoKSnp8Ji8vDysX78eVqsVmzZtwvz58/HSSy/hH//4R6fvk5mZCb1e73jExMQ4EyZRtzVZ2DPSEwFaFSaPaF4e/oPsQomjISK56PWMa7PZEB4ejjfffBPJycmYPn06nnrqKSxfvrzTYzIyMlBdXe14FBYyqVHfYM9Iz00f1/zl4ZN9Rag1WSSOhojkQOXMzmFhYVAqlSgtLW23vbS0FBERER0eExkZCbVaDaVS6dh2xRVXoKSkBGazGRqN5qJjtFottFqtM6ERuQSnaXoudUAoBoT5I6+iDp/mFuOelFipQyIiN+dUxtVoNEhOTkZWVpZjm81mQ1ZWFlJTUzs8ZsKECThx4gRsttYbaB07dgyRkZEdFiJEUmIDa88JgoC7xzcXIGt2n5Y4GiKSA6e//qWnp2PFihV45513cPjwYTz88MOoq6vD7NmzAQAzZ85ERkaGY/+HH34YlZWVmDt3Lo4dO4aNGzdi8eLFmDNnjuvOgshF7OuMcNGznrkzuT80SgUOFRlx4EyV1OEQkZtzapoGAKZPn47y8nIsWLAAJSUlGDNmDDZv3uxoai0oKIBC0ZrIY2Ji8OWXX+Kxxx7D6NGjER0djblz5+KJJ55w3VkQuYjZwp4RVwjx12DKqAh8kluMNbsKMLp/kNQhEZEbE0QZLAZgNBqh1+tRXV0NnU4ndTjkwcY/9zXKakzY9OdrMTyK/6/1xO78Svz2jZ3w0yjx45OToPNRSx0SEfWxrv7+5tc/ojZaG1jZM9JT4+KDMSg8APVmKz7hiqxEdAksRoja4L1pXEcQBNzT0sj63q4CrshKRJ1ixiVqg+uMuNadV/aHVqXAkZIa7CuskjocInJTzLhELURRbHNpL380XEHvp8bU0ZEAgDW7CiSOhojcFTMuUQurTYR9JoGX9rrOjJQ4AMDnB4pR3dAkcTRE5I6YcYla2PtFAEDNBlaXuTI2CMMiAtHYZMPHe89IHQ4RuSEWI0Qt7P0iAKdpXEkQBMeS8GxkJaKOMOMStWhqU4yoFBwZcaXbkqLhq1bieFktduadkzocInIzLEaIWjjWGFEqIAgsRlxJ56PGr5P7AwBWfpcvcTRE5G5YjBC1aLLY1xhhIdIbZk+IhyAAWUfKcLK8VupwiMiNsBghauFYY0TFH4veMKBfACYNa76H1codHB0holbMukQtuMZI73vw2gQAwP9yzqCyzixxNETkLph1iVq07Rmh3jE+IQSjovUwWWx478fTUodDRG6CWZeoRevICHtGeosgCHigZXTknZ2nYbJYJY6IiNwBixGiFmYLb5LXF24dFYlIvQ8qak34JLdY6nCIyA0w6xK1YM9I31ArFbjv6ngAzZf5chE0ImLWJWrRxKtp+sxd42Phr1HiaGkNdpyokDocIpIYsy5Ri9YGVvaM9Da9rxq/HRcDAFjBRdCIvB6LEaIWZit7RvrS/RMSoBCA7cfKcbSkRupwiEhCzLpELZos7BnpSzEhfrhlZAQA4K3v8iSOhoikxKxL1IINrH3vgWsHAAA+3leEwsp6iaMhIqkw6xK1cPSMqNgz0leujA3GNYPCYLGJWLbtpNThEJFEWIwQtWDPiDTmpg0GAHyYXYiiqgaJoyEiKTDrErXgNI00xsWHIHVAKJqsIpZv5egIkTdi1iVqwQZW6dhHR9btKcTZao6OEHkbZl2iFlxnRDpXDQjF+IQQmK02jo4QeSEWI0Qt2DMirUcnNY+OvL+nEKXGRomjIaK+xKxL1ILLwUsrdWAoxsYFw2yxYTmvrCHyKsy6RC3YwCotQRAcvSNrdhWgrIajI0TeglmXqAV7RqR3zaAwJMUGwWSx4c1tXJWVyFuwGCFqYeLVNJITBAFzW3pH3t11GuU1JokjIqK+wKxL1KKJDaxuYeKQfkiMCUJjkw1Lvz0hdThE1AeYdYlaONYZYQOrpARBwOOThwIA3v3xNE5V1EkcERH1NmZdohbsGXEfEwaFYeKQfrDYRLz45VGpwyGiXsZihKiFmVfTuJV5U4ZBEICNB89iX8F5qcMhol7ErEvUgpf2upcrInW488r+AIDMTUcgiqLEERFRb2HWJWrBBlb385ebh0CrUmD3qUp8fbhM6nCIqJd0K+suXboU8fHx8PHxQUpKCnbv3t2l49auXQtBEHDbbbd1522JepWjZ0TFnhF3Ean3xe+vSQAAPP/FYVhaPiMi8ixOFyPr1q1Deno6Fi5ciL179yIxMRGTJ09GWdmlv7WcOnUKf/3rX3Httdd2O1ii3mTmOiNu6aHrByLYT42T5XVYl10odThE1Auczrovv/wyHnzwQcyePRvDhw/H8uXL4efnh1WrVnV6jNVqxYwZM7Bo0SIMGDCgRwET9Rb2jLgnnY8af25ZCO1fW46jzmSROCIicjWnsq7ZbEZOTg7S0tJaX0ChQFpaGnbu3NnpcX//+98RHh6O3//+9116H5PJBKPR2O5B1NvYM+K+ZqTEIS7UDxW1Jqz4jsvEE3kap7JuRUUFrFYrDAZDu+0GgwElJSUdHrNjxw6sXLkSK1as6PL7ZGZmQq/XOx4xMTHOhEnULa3rjLAYcTcalQKPTx4GAHhjWx7OVjdIHBERuVKvZt2amhrce++9WLFiBcLCwrp8XEZGBqqrqx2PwkLOE1Pvc0zTsIHVLd06KgJj44LR0GTFs5//LHU4RORCKmd2DgsLg1KpRGlpabvtpaWliIiIuGj/kydP4tSpU5g2bZpjm83WnPBVKhWOHj2KgQMHXnScVquFVqt1JjSiHmMDq3sTBAHP3jYSv3h1BzYdLMH2Y+W4bkg/qcMiIhdwKutqNBokJycjKyvLsc1msyErKwupqakX7T9s2DAcPHgQubm5jscvf/lL3HDDDcjNzeX0C7kVe88Ip2nc1xWROsxKjQcALPz0J5gsVmkDIiKXcGpkBADS09Mxa9YsjB07FuPHj8eSJUtQV1eH2bNnAwBmzpyJ6OhoZGZmwsfHByNHjmx3fFBQEABctJ1IaryaRh4eu2kwPj9QjPyKOry5LQ+PtFxpQ0Ty5XQxMn36dJSXl2PBggUoKSnBmDFjsHnzZkdTa0FBARQKJnOSF5tNhMVmv5qGPSPuLNBHjaemXoG5a3Px2rcncFtSNGJC/KQOi4h6QBBlcMMHo9EIvV6P6upq6HQ6qcMhD2SyWDH06c0AgAPP3Aydj1riiOhSRFHEjLd24YeT5zBpWDhW3jdO6pCIqANd/f3NIQwitPaLAOwZkQNBEPD3X42EWikg60gZtvxcevmDiMhtMesSAWiytN7zhD0j8jAoPAAPXNu8ovMzn/6EBjObWYnkilmXCK3NqwoBUCrYMyIXj9w4CNFBviiqasC/vzkudThE1E0sRogAmHkljSz5aVRYOG04AODN7XnYX1glbUBE1C3MvETgGiNydvOICPwyMQpWm4i/frgfjU2criGSG2ZeIrRdCp4/EnK06JcjEBagxfGyWiz5mtM1RHLDzEuEtkvBs19EjoL9NVh8e/NCim9uP4m9BecljoiInMFihAhcfdUT3DwiAnckRcMmgtM1RDLDzEsE9ox4ioXTRiA8UIu88jq89NVRqcMhoi5i5iUCR0Y8hd5PjefvHAUAeGtHPrJPVUocERF1BTMvEdpc2qtiz4jc3TjMgN8k94fYMl1Tb7ZIHRIRXQaLESK0rsDKkRHP8PQvhiNS74NT5+qx6NOfpQ6HiC6DmZcIrT0jLEY8g95XjZd+mwhBANZlF2LDviKpQyKiS2DmJUJrzwgbWD3H1QPD8OcbBwMAnvz4IPLKayWOiIg6w8xLhLbLwbNnxJP8edJgXDUgBPVmK+as2cfLfYncFIsRIvBqGk+lVAh45a4khPprcPisEf/YyP4RInfEzEuENg2sXA7e4xh0PvjX9DEAgHd/LMDGA2elDYiILsLMSwQueubprhvSD3+8fiAAYN7/DuD0uTqJIyKitph5icCeEW+QftMQjI0LRo3Jgjlr9rJ/hMiNsBghQpuraThN47FUSgX+fXcSgv3UOFRkxN/WH4AoilKHRURgMUIEgA2s3iIqyBfLfpcMlULAZ/uL8frWk1KHRERgMUIEgD0j3uSqAaFY9KsRAIAXvzyKr34qkTgiImLmJQJg5nLwXmVGShxmpsYBAB5dl4sjJUaJIyLybsy8ROA0jTea/4vhuHpgKOrNVjzwTjbO1ZqkDonIazHzEqFNMcK79noNtVKB12dcibhQP5w534CH39vrGCEjor7FYoQI7BnxVkF+Grw1cywCtCrszq/EvI94hQ2RFJh5idB2nRH+SHibwYZAvHp3EpQKAR/tLcLzXxyROiQir8PMS4Q2y8GzGPFKNwwLx/N3jAIAvLE9D29u5yW/RH2JmZcIbRtY2TPirX4zNgbzpgwDACzedATrc85IHBGR92AxQoQ2PSNcgdWr/b/rBuDBaxMAAE/87wCyDpdKHBGRd2DmJQJ7RqiZIAjImHIF7rgyGlabiD++txfZpyqlDovI4zHzEoHrjFArhULAC3eOxo3DwmGy2HD/6j04VFQtdVhEHo2ZlwjsGaH21EoFlt5zJZLjgmFstOCeFT/iwJkqqcMi8lgsRogANFm4zgi156tRYvXscY6CZMZbu5BbWCV1WEQeiZmXCG1XYOWPBLUK9FHjnfvHY1x8MGoaLbj3rV3YV3Be6rCIPA4zLxHYwEqdC9CqsHr2eIyPD0GNyYJ7V+5GzmkWJESuxMxLBPaM0KX5a1V4e/Y4pCSEoNZkwcyVu7CHV9kQuUy3ipGlS5ciPj4ePj4+SElJwe7duzvdd8WKFbj22msRHByM4OBgpKWlXXJ/Iinw3jR0OfaCJHVAKOrMVty7che+/pnrkBC5gtOZd926dUhPT8fChQuxd+9eJCYmYvLkySgrK+tw/61bt+Luu+/Gt99+i507dyImJgY333wzioqKehw8katwOXjqCj+NCqvuG4frh/ZDY5MNf/hvNtbuLpA6LCLZE0Qnb1GZkpKCcePG4bXXXgMA2Gw2xMTE4JFHHsG8efMue7zVakVwcDBee+01zJw5s0vvaTQaodfrUV1dDZ1O50y4RF0y9OkvYLLY8P28GxEd5Ct1OOTmmqw2ZHx00LFk/KNpgzF30mAIAqf5iNrq6u9vp74Gms1m5OTkIC0trfUFFAqkpaVh586dXXqN+vp6NDU1ISQkpNN9TCYTjEZjuwdRb2LPCDlDrVTgxV+Pxp9uGAQAWPL1cTz58UFYWv4/IiLnOFWMVFRUwGq1wmAwtNtuMBhQUlLSpdd44oknEBUV1a6guVBmZib0er3jERMT40yYRE6x2kTYWsYH2TNCXSUIAv46eSievW0kFALw/u5CPPRuDurNFqlDI5KdPs28zz//PNauXYuPP/4YPj4+ne6XkZGB6upqx6OwsLAPoyRv09Tm2yx7RshZ914Vh2W/S4ZWpcDXh8vw62U7UVhZL3VYRLLiVOYNCwuDUqlEaWn7DvLS0lJERERc8th//vOfeP755/HVV19h9OjRl9xXq9VCp9O1exD1FjOLEeqhySMi8N4DKQj11+Dns0b8aun32HnynNRhEcmGU5lXo9EgOTkZWVlZjm02mw1ZWVlITU3t9Lj/+7//w7PPPovNmzdj7Nix3Y+WqBfYr6QB2DNC3Tc2PgSfPXINRkbrUFlnxu9W7sLq7/Ph5DUCRF7J6a+B6enpWLFiBd555x0cPnwYDz/8MOrq6jB79mwAwMyZM5GRkeHY/4UXXsD8+fOxatUqxMfHo6SkBCUlJaitrXXdWRD1gH2NEbVS4NUQ1CNRQb5Y/9DVuD0pGlabiGc++xl/W38AjU1WqUMjcmsqZw+YPn06ysvLsWDBApSUlGDMmDHYvHmzo6m1oKAACkVrjbNs2TKYzWb8+te/bvc6CxcuxDPPPNOz6IlcoIlLwZML+aiVePm3iRgRpcPiTYexPucMjpfW4LV7rkRMiJ/U4RG5JafXGZEC1xmh3nSyvBaTXtoGva8a+xfeLHU45EF2HK/AnDV7Ud3QhECtCovvGIVpiVFSh0XUZ3plnREiT8SREeot1wwOw8Y/X4PkuGDUmCx45P19eHz9fl7+S3QBZl/yek0W+31p2C9Crtc/2A/r/nAVHrlxEAQB+CD7DH7x6g78VFwtdWhEboPFCHk9+6W9ahV/HKh3qJQK/OXmoVjzwFUw6LTIK6/D7Ut/wFvf5cFqc/uZcqJex+xLXo/TNNRXUgeG4ou51yHtinCYrTb8Y+Nh/Gb5DzhRxqsLybsx+5LXYzFCfSnEX4MVM8di8e2jEKBVYW9BFW7993dYtvUk721DXovZl7yevRhhzwj1FUEQcE9KLL567DpMHNIPZosNL2w+gjuW/YAjJbwxKHkfFiPk9cwW+6Jn/HGgvhUV5IvVs8fhn79JhM5HhQNnqjHt1R14/osjqDPxihvyHsy+5PU4TUNSEgQBv07uj6/TJ+Km4QY0WUUs33YSk17ahk/3F3M5efIKzL7k9Zp4NQ25gXCdD968NxlvzRyL2BA/lBgb8ef39+GuN3/k1A15PGZf8nrsGSF3IQgC0oYb8NVj1+EvNw2Bj1qBXfmVmPrvHVj4ySGcqzVJHSJRr2AxQl7PbGXPCLkXH7USj0wajK/TJ2LKyAhYbSLe2XkaE1/cile+Ps5+EvI4zL7k9cwW9oyQe+of7Idlv0vGew+kYFS0HrUmC/719TFMfPFb/GfnKcf/u0Ryx+xLXo8NrOTuJgwKwydzJuDVu5MQF+qHilozFnzyE9Je3ob/5Zzh+iQke8y+5PWaWr5dalTsGSH3pVAImJYYha/TJ+LZX41AWIAWBZX1+MuH+3HDS1vx/u4CmCxWqcMk6hYWI+T1ODJCcqJWKnBvajy2/e16PH7LUIT6a1BY2YCMjw7i+he3YvX3+WhsYlFC8sLsS16PDawkR/5aFf54/SDseOJGLPjFcBh0WpytbsQzn/2Ma174Bku+PobyGl59Q/LA7EtejyMjJGe+GiXuvyYB2x+/Ac/dPhL9g31RUWvGkq+PY8Lz3+AvH+zHoaJqqcMkuiSV1AEQSY3rjJAn0KqUmJESh9+OjcGXP5Vg5Y587Cuowv/2nsH/9p7B+IQQzL46HmnDDSy8ye2wGCGvx5ER8iRqpQK/GB2FX4yOwr6C83j7+1PYdPAsdudXYnd+JcICNLgzuT/uGheLhDB/qcMlAsBihKj1RnlcDp48TFJsMJJig5Fx6zD8d+dpfJB9BhW1JryxLQ9vbMvDVQNCcPf4WEweEQEftVLqcMmLsRghr8eREfJ0kXpfPH7LMDx20xBkHS7D2j0F2HasHD/mVeLHvEoEaFW4ZWQEbhsTjdSBoVAqOGVJfYvFCHk99oyQt1ArFbhlZARuGRmBoqoGfLCnEOtzzqCoqgHrc85gfc4ZhAdq8cvEKPxqTDRGRusgCPy5oN7HYoS8HkdGyBtFB/nisZuGYO6kwcg+fR4bcouw8cBZlNWY8NaOfLy1Ix/9g31xy4gITBkVgaSYYCg4YkK9hMUIeT2uM0LeTKEQMD4hBOMTQvDMtBHYerQMn+QWI+tIKc6cb3AUJuGBWtw8woCbh0dgfEIIe0zIpViMkNezLwfPBlbydhqVAjePiMDNIyLQYLZi27EybD5UgqzDZSirMeHdHwvw7o8F8FUrMWFQGG4Y1g/XDw1HdJCv1KGTzLEYIa/HnhGii/lqlLhlZCRuGRkJs8WG709W4MtDJfj2aBlKjSZ8fbgUXx8uBQAMNQTimsFhmDAoFOMTQhGg5a8Wcg7/jyGvx54RokvTqBS4YWg4bhgaDlEU8fNZI7YeLce3R8qwt+A8jpbW4GhpDVbuyIdKISAxJggTBoYidWAYkmKDOKVDl8VihLwee0aIuk4QBIyI0mNElB5zbhiE83Vm7DhRgR9OVuD7E+dQUFmPnNPnkXP6PP79zQmolQJGRusxPj4E4+JDMDY+GEF+GqlPg9wMixHyehwZIeq+YH8NpiVGYVpiFACgsLIe35+owPcnz2FX3jmU1Ziwr6AK+wqq8Mb2PADAwH7+GBMTjDExeoyJCcawyED+/Hk5FiPk9Rw9Iyr2jBD1VEyIH+4aH4u7xsdCFEUUVjZg96lKZJ+qxO5Tlcgrr8PJlsf/9p4BAGhVCoyI0mFktB4jo/QYHqXDEEMgNGwq9xosRsjrOa6m4TczIpcSBAGxoX6IDfXDr5P7AwDO1Zqw/0wVcguqsK+wCvsLq2BstGBvQRX2FlQ5jlUrBQwxBGJ4pA5DIwIxLEKHIREB6Beg5UJsHojFCHk99owQ9Z3QAC1uHGbAjcMMAABRFJFfUYcDZ6rxU3E1DhUZ8VNxNYyNFvxUbMRPxcZ2x4f4azDUEIjBhgAM7NfyCPdHhM6HRYqMsRghr8eeESLpCIKAAf0CMKBfAG5LigbQXKCcOd+An4qrcfhsDY6W1OBYaQ1OnatDZZ0ZO/POYWfeuXav469RYkC/AMSH+SM+1A/xof6ID/NDXKg/Qv01LFTcHIsR8nqt64ywGCFyB4IgICbEDzEhfrhlZKRje2OTFcdLa3G0tAYnympxsrz5cfpcPerMVhwsqsbBouqLXs9fo0RMiB/6B/uhf7Bv82sH+yIqyBfRQb4I8lOzWJEYixHyeo6RETawErk1H7USo/rrMaq/vt12s8WGgsrmptjT5+pw6lx9858V9SiubkCd2YojJTU4UlLTyesqHIVJpN4HETofhOua/4zQ+8Cg80Gov4b35ulFLEbIq4miiCb2jBDJmkalwKDwQAwKD7zoucYmK4qqGlBYWY/C8w04U1mPwvP1KKxswNnqBlTUmtHYZENeeR3yyus6fQ+lQkBYgAb9ArXoF6Bt/jNQi1B/LUIDNAgLaP4z1F+LYD81VMwnTmExQl7NXogALEaIPJGPWulodO1IY5MVJdWNKK5qQHF1I85WNaDE2IhSY2PLnyZU1JpgtYkoNZpQajR16X31vmoE+6kR7K9BiJ8GQX4aBPupEeSnht5XDb2fBkG+LX/3VUPnq0agj8pr81C3ipGlS5fixRdfRElJCRITE/Hqq69i/Pjxne7/4YcfYv78+Th16hQGDx6MF154Abfeemu3gyZyFfsUDcCeESJv5KNWNje9hvl3uk+T1YZztWaU15hQXtvY/GfLo6LOjMpaM87VmXCu1ozKejNEEahuaEJ1QxNOnat3Kh4/jRI6HzV0vioEaFUI8GkuUgK1KgT6qOCvbd7ur7X/XQl/TfPf/TRKx59+GhWUMppWcroYWbduHdLT07F8+XKkpKRgyZIlmDx5Mo4ePYrw8PCL9v/hhx9w9913IzMzE7/4xS+wZs0a3Hbbbdi7dy9GjhzpkpMg6q62xYiaN8ojog6olQpE6Jv7RwD9Jfe12kRU1Ztxvr4J5+vNqKwz43xdc5FSXd+EqvrmIqWqwez4e02jBbUmCwCg3mxFvdmKEuMl36ZLtCoF/DRK+KqV8G0pUHzVSvholPBVK+Cjbn7Op+UxIyUWMSF+PX/jbhBEURQvv1urlJQUjBs3Dq+99hoAwGazISYmBo888gjmzZt30f7Tp09HXV0dPv/8c8e2q666CmPGjMHy5cu79J5GoxF6vR7V1dXQ6XTOhEt0SWU1jRj/XBYEAchbfCs76olIEharDbUmC4wNlpYCpQnGliKlprEJtY0W1Jia/13X8qh1/NuKerMF9SYr6swW2Jz6rd7qoz9ejStjg116Xl39/e3UyIjZbEZOTg4yMjIc2xQKBdLS0rBz584Oj9m5cyfS09PbbZs8eTI2bNjQ6fuYTCaYTK3zckajC0rEDqzckY8z550bQiPPUtfybUStVLAQISLJqJQKBLX0lvSEKIowWWyoM1lQb7aiscnqGG2x/72xyYqGpuY/W/9uQ4TOx0Vn4zynipGKigpYrVYYDIZ22w0GA44cOdLhMSUlJR3uX1JS0un7ZGZmYtGiRc6E1i0bDxS3W36YvFewn1rqEIiIekwQBMe0S6jUwTjBLa+mycjIaDeaYjQaERMT4/L3uTO5P1IHyunjot5y/dCL+52IiKhvOFWMhIWFQalUorS0tN320tJSREREdHhMRESEU/sDgFarhVardSa0bpmREtfr70FERESX5tS1jBqNBsnJycjKynJss9lsyMrKQmpqaofHpKamttsfALZs2dLp/kRERORdnJ6mSU9Px6xZszB27FiMHz8eS5YsQV1dHWbPng0AmDlzJqKjo5GZmQkAmDt3LiZOnIiXXnoJU6dOxdq1a5GdnY0333zTtWdCREREsuR0MTJ9+nSUl5djwYIFKCkpwZgxY7B582ZHk2pBQQEUitYBl6uvvhpr1qzB008/jSeffBKDBw/Ghg0buMYIERERAejGOiNS4DojRERE8tPV399c/5qIiIgkxWKEiIiIJMVihIiIiCTFYoSIiIgkxWKEiIiIJMVihIiIiCTFYoSIiIgkxWKEiIiIJMVihIiIiCTl9HLwUrAvEms0GiWOhIiIiLrK/nv7cou9y6IYqampAQDExMRIHAkRERE5q6amBnq9vtPnZXFvGpvNhuLiYgQGBkIQBJe9rtFoRExMDAoLCz32njeefo48P/nz9HPk+cmfp59jb56fKIqoqalBVFRUu5voXkgWIyMKhQL9+/fvtdfX6XQe+T9YW55+jjw/+fP0c+T5yZ+nn2Nvnd+lRkTs2MBKREREkmIxQkRERJLy6mJEq9Vi4cKF0Gq1UofSazz9HHl+8ufp58jzkz9PP0d3OD9ZNLASERGR5/LqkREiIiKSHosRIiIikhSLESIiIpIUixEiIiKSlFcXI0uXLkV8fDx8fHyQkpKC3bt3Sx1St2zfvh3Tpk1DVFQUBEHAhg0b2j0viiIWLFiAyMhI+Pr6Ii0tDcePH5cm2G7IzMzEuHHjEBgYiPDwcNx22204evRou30aGxsxZ84chIaGIiAgAHfeeSdKS0slith5y5Ytw+jRox2LDqWmpuKLL75wPC/387vQ888/D0EQ8Oijjzq2yfkcn3nmGQiC0O4xbNgwx/NyPre2ioqK8Lvf/Q6hoaHw9fXFqFGjkJ2d7XhezrkmPj7+os9QEATMmTMHgPw/Q6vVivnz5yMhIQG+vr4YOHAgnn322Xb3jJH08xO91Nq1a0WNRiOuWrVK/Omnn8QHH3xQDAoKEktLS6UOzWmbNm0Sn3rqKfGjjz4SAYgff/xxu+eff/55Ua/Xixs2bBD3798v/vKXvxQTEhLEhoYGaQJ20uTJk8W3335bPHTokJibmyveeuutYmxsrFhbW+vY56GHHhJjYmLErKwsMTs7W7zqqqvEq6++WsKonfPpp5+KGzduFI8dOyYePXpUfPLJJ0W1Wi0eOnRIFEX5n19bu3fvFuPj48XRo0eLc+fOdWyX8zkuXLhQHDFihHj27FnHo7y83PG8nM/NrrKyUoyLixPvu+8+cdeuXWJeXp745ZdfiidOnHDsI+dcU1ZW1u7z27JliwhA/Pbbb0VRlP9n+Nxzz4mhoaHi559/Lubn54sffvihGBAQIL7yyiuOfaT8/Ly2GBk/frw4Z84cx7+tVqsYFRUlZmZmShhVz11YjNhsNjEiIkJ88cUXHduqqqpErVYrvv/++xJE2HNlZWUiAHHbtm2iKDafj1qtFj/88EPHPocPHxYBiDt37pQqzB4LDg4W33rrLY86v5qaGnHw4MHili1bxIkTJzqKEbmf48KFC8XExMQOn5P7udk98cQT4jXXXNPp856Wa+bOnSsOHDhQtNlsHvEZTp06Vbz//vvbbbvjjjvEGTNmiKIo/efnldM0ZrMZOTk5SEtLc2xTKBRIS0vDzp07JYzM9fLz81FSUtLuXPV6PVJSUmR7rtXV1QCAkJAQAEBOTg6ampraneOwYcMQGxsry3O0Wq1Yu3Yt6urqkJqa6lHnN2fOHEydOrXduQCe8RkeP34cUVFRGDBgAGbMmIGCggIAnnFuAPDpp59i7Nix+M1vfoPw8HAkJSVhxYoVjuc9KdeYzWa8++67uP/++yEIgkd8hldffTWysrJw7NgxAMD+/fuxY8cOTJkyBYD0n58sbpTnahUVFbBarTAYDO22GwwGHDlyRKKoekdJSQkAdHiu9ufkxGaz4dFHH8WECRMwcuRIAM3nqNFoEBQU1G5fuZ3jwYMHkZqaisbGRgQEBODjjz/G8OHDkZub6xHnt3btWuzduxd79uy56Dm5f4YpKSlYvXo1hg4dirNnz2LRokW49tprcejQIdmfm11eXh6WLVuG9PR0PPnkk9izZw/+/Oc/Q6PRYNasWR6VazZs2ICqqircd999AOT//ycAzJs3D0ajEcOGDYNSqYTVasVzzz2HGTNmAJD+d4VXFiMkX3PmzMGhQ4ewY8cOqUNxuaFDhyI3NxfV1dVYv349Zs2ahW3btkkdlksUFhZi7ty52LJlC3x8fKQOx+Xs3y4BYPTo0UhJSUFcXBw++OAD+Pr6ShiZ69hsNowdOxaLFy8GACQlJeHQoUNYvnw5Zs2aJXF0rrVy5UpMmTIFUVFRUofiMh988AHee+89rFmzBiNGjEBubi4effRRREVFucXn55XTNGFhYVAqlRd1QpeWliIiIkKiqHqH/Xw84Vz/9Kc/4fPPP8e3336L/v37O7ZHRETAbDajqqqq3f5yO0eNRoNBgwYhOTkZmZmZSExMxCuvvOIR55eTk4OysjJceeWVUKlUUKlU2LZtG/79739DpVLBYDDI/hzbCgoKwpAhQ3DixAmP+PwAIDIyEsOHD2+37YorrnBMR3lKrjl9+jS+/vprPPDAA45tnvAZ/u1vf8O8efNw1113YdSoUbj33nvx2GOPITMzE4D0n59XFiMajQbJycnIyspybLPZbMjKykJqaqqEkbleQkICIiIi2p2r0WjErl27ZHOuoijiT3/6Ez7++GN88803SEhIaPd8cnIy1Gp1u3M8evQoCgoKZHOOHbHZbDCZTB5xfpMmTcLBgweRm5vreIwdOxYzZsxw/F3u59hWbW0tTp48icjISI/4/ABgwoQJF11Sf+zYMcTFxQHwjFwDAG+//TbCw8MxdepUxzZP+Azr6+uhULT/la9UKmGz2QC4wefX6y2ybmrt2rWiVqsVV69eLf7888/iH/7wBzEoKEgsKSmROjSn1dTUiPv27RP37dsnAhBffvllcd++feLp06dFUWy+XCsoKEj85JNPxAMHDoi/+tWvZHO5nSiK4sMPPyzq9Xpx69at7S69q6+vd+zz0EMPibGxseI333wjZmdni6mpqWJqaqqEUTtn3rx54rZt28T8/HzxwIED4rx580RBEMSvvvpKFEX5n19H2l5NI4ryPse//OUv4tatW8X8/Hzx+++/F9PS0sSwsDCxrKxMFEV5n5vd7t27RZVKJT733HPi8ePHxffee0/08/MT3333Xcc+cs81VqtVjI2NFZ944omLnpP7Zzhr1iwxOjracWnvRx99JIaFhYmPP/64Yx8pPz+vLUZEURRfffVVMTY2VtRoNOL48ePFH3/8UeqQuuXbb78VAVz0mDVrliiKzZdszZ8/XzQYDKJWqxUnTZokHj16VNqgndDRuQEQ3377bcc+DQ0N4h//+EcxODhY9PPzE2+//Xbx7Nmz0gXtpPvvv1+Mi4sTNRqN2K9fP3HSpEmOQkQU5X9+HbmwGJHzOU6fPl2MjIwUNRqNGB0dLU6fPr3d+htyPre2PvvsM3HkyJGiVqsVhw0bJr755pvtnpd7rvnyyy9FAB3GLPfP0Gg0inPnzhVjY2NFHx8fccCAAeJTTz0lmkwmxz5Sfn6CKLZZfo2IiIioj3llzwgRERG5DxYjREREJCkWI0RERCQpFiNEREQkKRYjREREJCkWI0RERCQpFiNEREQkKRYjREREJCkWI0RERCQpFiNEREQkKRYjREREJCkWI0RERCSp/w/ZCdN0aTpNywAAAABJRU5ErkJggg==", 446 | "text/plain": [ 447 | "
" 448 | ] 449 | }, 450 | "metadata": {}, 451 | "output_type": "display_data" 452 | } 453 | ], 454 | "source": [ 455 | "r_ir = relativistic_ir(dt=0.125)\n", 456 | "plt.plot(r_ir)" 457 | ] 458 | } 459 | ], 460 | "metadata": { 461 | "kernelspec": { 462 | "display_name": "py310", 463 | "language": "python", 464 | "name": "python3" 465 | }, 466 | "language_info": { 467 | "codemirror_mode": { 468 | "name": "ipython", 469 | "version": 3 470 | }, 471 | "file_extension": ".py", 472 | "mimetype": "text/x-python", 473 | "name": "python", 474 | "nbconvert_exporter": "python", 475 | "pygments_lexer": "ipython3", 476 | "version": "3.10.8" 477 | } 478 | }, 479 | "nbformat": 4, 480 | "nbformat_minor": 0 481 | } 482 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | matplotlib 4 | emcee 5 | corner 6 | -e git+https://github.com/StingraySoftware/stingray.git#egg=stingray 7 | --------------------------------------------------------------------------------