├── .gitignore ├── 01-behavioral_data_analysis ├── .ipynb_checkpoints │ ├── 01-training_progress_analysis-checkpoint.ipynb │ └── 02-fmri_performance_analysis-checkpoint.ipynb ├── 00-log_processing.ipynb ├── 01-training_progress_analysis.ipynb ├── 02-fmri_performance_analysis.ipynb └── 03-exclusion_variability.ipynb ├── 02-fmri_data_preparation ├── 01-aCompCor_denoising.ipynb ├── 02-timeseries_extraction.ipynb ├── 03-static_FC_estimation.ipynb ├── 04-dynamic_FC_estimation.ipynb ├── 05-motion_and_outliers_control.ipynb └── 06-FC_density_plots.ipynb ├── 03-static_FC_analyses ├── 00-degree_distribution.ipynb ├── 01-static_modularity_calculation.m ├── 02-tidying_normalized_modularity.ipynb ├── 03-normalized_modularity_stats.ipynb ├── 04-modularity-behaviour_stats.ipynb └── load_data.py ├── 04-dynamic_FC_analyses ├── 01-multilayer_modularity_calculation.m ├── 02-module_allegiance_matrix_calculation.ipynb ├── 03-fp_dm_plotting.ipynb ├── 04-whole-brain_normalized_recr_integ.ipynb ├── 05-whole-brain_normalized_recr_integ_stats.ipynb ├── 06-whole-brain_mlm_networks_summary.ipynb ├── 07-behavioral_variability_and_recruitmnent_stats.ipynb ├── 08-multilayer_modularity_calculation_signed.m └── 10-dm_temporal_expansion.ipynb ├── 05-glm_analysis ├── 01-first_level_GLM_analysis.ipynb ├── 02-group_level_GLM_analysis.ipynb ├── 03-changes_in_brain_activity_stats.ipynb └── 04-activity_vs_recruitment_stats.ipynb ├── LICENCE.txt ├── README.md ├── environment.yml ├── fctools ├── __init__.py ├── denoise.py ├── figures.py ├── networks.py └── stats.py └── support ├── modules.txt └── onsets_dualnback.csv /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | */.ipynb_checkpoints/* 3 | */*/.ipynb_checkpoints/*.ipynb 4 | 5 | -------------------------------------------------------------------------------- /01-behavioral_data_analysis/00-log_processing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# **Working memory training**: processing behavioral logs\n", 8 | "**Last edited:** 12-20-2019" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "import matplotlib.pyplot as plt\n", 18 | "import pandas as pd\n", 19 | "import numpy as np\n", 20 | "import json\n", 21 | "import os\n", 22 | "from scipy.stats import norm" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 2, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "def convert_logfile(fname: str, task_meta: dict) -> pd.DataFrame:\n", 32 | " '''Converts logfile into concise and easy to work DataFrame\n", 33 | " \n", 34 | " Args:\n", 35 | " fname: path to log file\n", 36 | " task_meta: task metadata\n", 37 | " \n", 38 | " Returns:\n", 39 | " Table containing information about each trial. Each row contain block\n", 40 | " number, task condition, correct and actual response for both visual and\n", 41 | " auditory stimuli. \n", 42 | " '''\n", 43 | " # Setup local variables\n", 44 | " n_stims = task_meta['n_stims']\n", 45 | " n_blocks = task_meta['n_blocks']\n", 46 | " n_conditions = task_meta['n_conditions']\n", 47 | " n_trials = n_stims * n_blocks * n_conditions\n", 48 | " ttr = task_meta['ttr']\n", 49 | " \n", 50 | " # Create block and condition indices\n", 51 | " ind_block = np.repeat(np.arange(n_blocks), n_stims * n_conditions)[:, np.newaxis]\n", 52 | " ind_cond = np.tile(\n", 53 | " np.concatenate((np.ones(n_stims), 2*np.ones(n_stims))), n_blocks\n", 54 | " )[:, np.newaxis]\n", 55 | "\n", 56 | " df_ind = pd.DataFrame(\n", 57 | " np.hstack((ind_block, ind_cond)), \n", 58 | " columns=['block', 'condition']).astype('int')\n", 59 | "\n", 60 | " # Load stimulus data\n", 61 | " df = pd.read_csv(fname, delimiter='\\t', skiprows=3)\n", 62 | "\n", 63 | " stim_filter = df['Code'].str.contains('yes') | df['Code'].str.contains('no')\n", 64 | " df_stim = df.loc[stim_filter, :]\n", 65 | "\n", 66 | " # Split visual and audio stimuli\n", 67 | " df_stim_vis = df_stim.loc[df_stim['Event Type'] == 'Picture', \n", 68 | " ['xs(str)', 'Time']].reset_index(drop=True)\n", 69 | " df_stim_aud = df_stim.loc[df_stim['Event Type'] == 'Sound', \n", 70 | " 'xs(str)'].reset_index(drop=True)\n", 71 | " df_stim_vis.columns = ['ans_vis', 'stim_onset']\n", 72 | " df_stim_aud.name = 'ans_aud'\n", 73 | "\n", 74 | " # Merge visual and audio stimuli again & add response columns\n", 75 | " df_stim = pd.concat([df_ind, df_stim_vis, df_stim_aud], axis=1, sort=False)\n", 76 | " df_stim['resp_aud'], df_stim['resp_aud_time'], \\\n", 77 | " df_stim['resp_vis'], df_stim['resp_vis_time'] = np.zeros((4, n_trials), dtype='int')\n", 78 | " \n", 79 | " # Load response data\n", 80 | " resp_filer = df['Code'].isin(['1', '2'])\n", 81 | " df_resp = df.loc[resp_filer, :]\n", 82 | "\n", 83 | " # Analyze trialwise responses\n", 84 | " for i, row in df_stim.iterrows():\n", 85 | "\n", 86 | " r = df_resp.loc[(df_resp['Time'] > row['stim_onset']) & \\\n", 87 | " (df_resp['Time'] < row['stim_onset'] + ttr), \n", 88 | " ['Code', 'Time']]\n", 89 | "\n", 90 | " if '2' in r['Code'].unique():\n", 91 | " df_stim.loc[i, 'resp_aud'] = 1\n", 92 | " df_stim.loc[i, 'resp_aud_time'] = r.loc[r['Code']=='2', 'Time'].values[0] \n", 93 | " if '1' in r['Code'].unique():\n", 94 | " df_stim.loc[i, 'resp_vis'] = 1\n", 95 | " df_stim.loc[i, 'resp_vis_time'] = r.loc[r['Code']=='1', 'Time'].values[0] \n", 96 | "\n", 97 | " for modality in ['vis', 'aud']:\n", 98 | " df_stim[f'resp_{modality}_time'] -= df_stim['stim_onset'] \n", 99 | " df_stim.loc[df_stim[f'resp_{modality}_time'] < 0, \n", 100 | " f'resp_{modality}_time'] = np.nan\n", 101 | " df_stim[f'resp_{modality}_time'] /= 10\n", 102 | " df_stim[f'ans_{modality}'] = df_stim[f'ans_{modality}'].map({' yes': 1, ' no': 0})\n", 103 | "\n", 104 | " # Drop and reorder columns\n", 105 | " df_stim = df_stim[['block', 'condition', \n", 106 | " 'ans_vis', 'resp_vis', 'resp_vis_time',\n", 107 | " 'ans_aud', 'resp_aud', 'resp_aud_time']]\n", 108 | " \n", 109 | " return df_stim" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "# Behavioral measures\n", 117 | "\n", 118 | "## Introduction\n", 119 | "\n", 120 | "We assume that each measure is calculated separately for single subject, session, task condition (1-back or 2-back) and stimuli modality (visual or auditory). Each behavioral response can be divided into one of four categories: *hit*, *miss*, *correct rejection* or *false alarm*:\n", 121 | "\n", 122 | "| Stimuli\\Response \t| Congruent \t| Incongruent \t|\n", 123 | "|------------------\t|-------------\t|-------------------\t|\n", 124 | "| Congruent \t| hit \t| miss \t|\n", 125 | "| Incongruent \t| false alarm \t| correct rejection \t|\n", 126 | "\n", 127 | "Subjects were instructed to respond with their thumb to congruent stimuli and omit response to incongruent stimuli. Note that in this task setting \"real misses\", i.e. when subject failed to respond within required time window cannot be distinguished from correct rejections and misses. Number of responses of each type was calculated on the level of entire run and for individual task blocks. Reaction time (RT) was calculated for hits and false alarms.\n", 128 | "\n", 129 | "## Measures\n", 130 | "\n", 131 | "### Accuracy\n", 132 | "\n", 133 | "Accuracy was calculated as the actual number of hits divided by the maximum number of hits.\n", 134 | "$$accuracy = \\frac{\\#hits}{N_{congruent}}$$\n", 135 | "\n", 136 | "This imperfect definition is prone to *respond to all stimuli* behavior. In this case accuracy will be one.\n", 137 | "\n", 138 | "### Penalized reaction time\n", 139 | "\n", 140 | "Penalized reaction time (PRT) tries to combine accuracy with the reaction time. Calculating PRT consists of three steps. First, all labeled reaction times are selected. Second, all reaction times for false alarms are set to 2000ms (maximal possible RT). Third, fake reaction times for misses are added to penalize for not responding. Then mean is calculated for task runs and individual blocks. Note that mean PRT over blocks is usually different than the one calculated for the enire task mean (some blocks consist of more responses than others). Formally, PRT is defined as\n", 141 | "$$prt = \\frac{1}{\\#false\\ alarms + \\#hits + \\#misses}(\\sum_{r=1}^{N_{responses}} prt_{r} + \\#misses \\times 2000\\text{ms})$$\n", 142 | "where $prt_{r}$ is 2000ms for false alarms and RT for hits.\n", 143 | "\n", 144 | "### D-prime\n", 145 | "\n", 146 | "D-prime based on signal detection theory takes into account both response sensitivity and specificity. First, *hit rate* $hr$ and *false alarm rate* $fr$ is calculated as:\n", 147 | "$$hr = \\frac{\\#hits}{\\#hits + \\#misses}$$\n", 148 | "$$fr = \\frac{\\#false\\ alarms}{\\#false\\ alarms + \\#correct\\ rejections}$$\n", 149 | "Second, to avoid problems with infinite values, all $hr$ or $fr$ values equal to 1 are set to 0.99 and all $hr$ or $fr$ values equal to 0 are set to 0.01. Finally, d-prime is calculated as difference between pdf transormed values of $hr$ and $fr$:\n", 150 | "$$d'=f(hr)-f(fr)$$\n", 151 | "where $f(x)$ is the inverse of the cumulative distribution function for Gaussian distribution.\n", 152 | "Note that mean d-prime over task blocks is not equal to mean calculated for the entire task." 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": 3, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [ 161 | "def calculate_behavioral_measures(df_stim: pd.DataFrame, task_meta: dict) -> tuple:\n", 162 | " '''Calculates main three behavioral measures: accuracy, pRT and D-prime.\n", 163 | " \n", 164 | " Args: \n", 165 | " df_stim: trialwise task information\n", 166 | " task_meta: task_meta\n", 167 | " \n", 168 | " Returns:\n", 169 | " Aggregated behavioral measures for entire task. \n", 170 | " (n_measures x n_conditions x n_modalities) \n", 171 | " Aggregated behavioral measures for specific blocks.\n", 172 | " (n_measures x n_conditions x n_modalities x n_blocks)\n", 173 | " '''\n", 174 | "\n", 175 | " def _get_resp_patterns(df_signal, filt_rows, modality):\n", 176 | " '''Calculates number of hits, correct rejections, misses and false alarms.\n", 177 | "\n", 178 | " Args: \n", 179 | " modality (str): either 'vis' or 'aud'\n", 180 | "\n", 181 | " Returns:\n", 182 | " Number of hits, correct rejections, misses and false alarms.\n", 183 | "\n", 184 | " '''\n", 185 | " no_hit = df_signal.loc[filt_rows, f'hit_{modality}'].sum()\n", 186 | " no_crr = df_signal.loc[filt_rows, f'crr_{modality}'].sum()\n", 187 | " no_mis = df_signal.loc[filt_rows, f'mis_{modality}'].sum()\n", 188 | " no_fal = df_signal.loc[filt_rows, f'fal_{modality}'].sum()\n", 189 | "\n", 190 | " return (no_hit, no_crr, no_mis, no_fal)\n", 191 | "\n", 192 | " def _calculate_dprime(no_hit, no_crr, no_mis, no_fal):\n", 193 | " '''Calculates d-prime signal detection index\n", 194 | "\n", 195 | " Args: \n", 196 | " no_hit (int): number of hits\n", 197 | " no_crr (int): number of correct rejections\n", 198 | " no_mis (int): number of misses\n", 199 | " no_fal (int): number of false alarms\n", 200 | "\n", 201 | " Returns:\n", 202 | " (float) D-prime index. \n", 203 | " '''\n", 204 | "\n", 205 | " hit_rate = no_hit / (no_hit + no_mis)\n", 206 | " fal_rate = no_fal / (no_fal + no_crr)\n", 207 | "\n", 208 | " # Corner cases (infinity problem)\n", 209 | " if fal_rate == 0: fal_rate = 0.01\n", 210 | " if fal_rate == 1: fal_rate = 0.99\n", 211 | "\n", 212 | " if hit_rate == 0: hit_rate = 0.01\n", 213 | " if hit_rate == 1: hit_rate = 0.99\n", 214 | "\n", 215 | " return norm.ppf(hit_rate) - norm.ppf(fal_rate)\n", 216 | "\n", 217 | " df_signal = df_stim[['block', 'condition']].copy()\n", 218 | " n_modalities = task_meta['n_modalities']\n", 219 | " n_conditions = task_meta['n_conditions']\n", 220 | " n_blocks = task_meta['n_blocks']\n", 221 | " ttr = task_meta['ttr'] / 10\n", 222 | "\n", 223 | " # Signal theory measures\n", 224 | " for s in ['vis', 'aud']:\n", 225 | " df_signal[f'hit_{s}'] = (df_stim[f'ans_{s}'] == 1) & (df_stim[f'resp_{s}'] == 1)\n", 226 | " df_signal[f'crr_{s}'] = (df_stim[f'ans_{s}'] == 0) & (df_stim[f'resp_{s}'] == 0)\n", 227 | " df_signal[f'mis_{s}'] = (df_stim[f'ans_{s}'] == 1) & (df_stim[f'resp_{s}'] == 0)\n", 228 | " df_signal[f'fal_{s}'] = (df_stim[f'ans_{s}'] == 0) & (df_stim[f'resp_{s}'] == 1)\n", 229 | " df_signal[f'hit_time_{s}'] = df_signal[f'hit_{s}'].replace(False, np.nan) \\\n", 230 | " * df_stim[f'resp_{s}_time']\n", 231 | " df_signal[f'fal_time_{s}'] = df_signal[f'fal_{s}'].replace(False, np.nan) \\\n", 232 | " * df_stim[f'resp_{s}_time']\n", 233 | "\n", 234 | " acc_block, prt_block, dpr_block = np.zeros((3, n_conditions, n_modalities, n_blocks))\n", 235 | " acc, prt, dpr = np.zeros((3, n_conditions, n_modalities))\n", 236 | " hit_rate, fal_rate = np.zeros((2, n_conditions, n_modalities))\n", 237 | "\n", 238 | " for idx_c, condition in enumerate([1, 2]):\n", 239 | " for idx_m, modality in enumerate(['vis', 'aud']):\n", 240 | "\n", 241 | " filt_rows = (df_signal['condition'] == condition)\n", 242 | "\n", 243 | " # Count hits, correct rejections, misses and false alarms\n", 244 | " no_hit, no_crr, no_mis, no_fal = _get_resp_patterns(df_signal, filt_rows, modality)\n", 245 | "\n", 246 | " # Calculate behavioral measures (whole task)\n", 247 | " prt[idx_c, idx_m] = \\\n", 248 | " (df_signal.loc[filt_rows, f'hit_time_{modality}'].sum() + ttr * (no_fal + no_mis)) \\\n", 249 | " / (no_hit + no_fal + no_mis)\n", 250 | " dpr[idx_c, idx_m] = _calculate_dprime(no_hit, no_crr, no_mis, no_fal)\n", 251 | " \n", 252 | " # Grab also simpler measures for exclusion criteria\n", 253 | " hit_rate[idx_c, idx_m] = no_hit / (no_hit + no_mis)\n", 254 | " fal_rate[idx_c, idx_m] = no_fal / (no_fal + no_crr)\n", 255 | "\n", 256 | " for idx_b in range(n_blocks):\n", 257 | "\n", 258 | " filt_rows = (df_signal['condition'] == condition) \\\n", 259 | " & (df_signal['block'] == idx_b)\n", 260 | "\n", 261 | " # Count hits, correct rejections, misses and false alarms\n", 262 | " no_hit, no_crr, no_mis, no_fal = _get_resp_patterns(\n", 263 | " df_signal, filt_rows, modality\n", 264 | " )\n", 265 | "\n", 266 | " # Calculate behavioral measures (block level)\n", 267 | " acc_block[idx_c, idx_m, idx_b] = no_hit / (no_hit + no_mis)\n", 268 | " prt_block[idx_c, idx_m, idx_b] = \\\n", 269 | " (df_signal.loc[filt_rows, f'hit_time_{modality}'].sum() + ttr * (no_fal + no_mis)) \\\n", 270 | " / (no_hit + no_fal + no_mis)\n", 271 | " dpr_block[idx_c, idx_m, idx_b] = _calculate_dprime(no_hit, no_crr, no_mis, no_fal)\n", 272 | "\n", 273 | " acc = np.nanmean(acc_block, axis=2)\n", 274 | " \n", 275 | " return (np.stack((acc, prt, dpr, hit_rate, fal_rate)), np.stack((acc_block, prt_block, dpr_block)))" 276 | ] 277 | }, 278 | { 279 | "cell_type": "markdown", 280 | "metadata": {}, 281 | "source": [ 282 | "Load group assignment table and exclude subjects with incomplete data." 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 4, 288 | "metadata": {}, 289 | "outputs": [ 290 | { 291 | "data": { 292 | "text/html": [ 293 | "
\n", 294 | "\n", 307 | "\n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | "
subgroup
0sub-01Control
1sub-02Control
3sub-04Control
4sub-05Experimental
5sub-06Experimental
\n", 343 | "
" 344 | ], 345 | "text/plain": [ 346 | " sub group\n", 347 | "0 sub-01 Control\n", 348 | "1 sub-02 Control\n", 349 | "3 sub-04 Control\n", 350 | "4 sub-05 Experimental\n", 351 | "5 sub-06 Experimental" 352 | ] 353 | }, 354 | "execution_count": 4, 355 | "metadata": {}, 356 | "output_type": "execute_result" 357 | } 358 | ], 359 | "source": [ 360 | "df_group = pd.read_csv('data/group_assignment.csv')\n", 361 | "df_group = df_group.loc[~df_group['group'].isna(), :]\n", 362 | "df_group.head()" 363 | ] 364 | }, 365 | { 366 | "cell_type": "markdown", 367 | "metadata": {}, 368 | "source": [ 369 | "Process all logs and save aggregated behavioral data to file. Data description:\n", 370 | "- `beh`: np.array containing behavioral measures calculated for entire dual n-back run\n", 371 | "- `beh_block`: contains the same measures calculated for individual task blocks\n", 372 | "- `meta`: dictionary describing fields in `beh` and `beh_block`" 373 | ] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "execution_count": 5, 378 | "metadata": {}, 379 | "outputs": [ 380 | { 381 | "name": "stdout", 382 | "output_type": "stream", 383 | "text": [ 384 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/001d_1-dual_n-back_modified.log\n", 385 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/002d_1-dual_n-back_modified.log\n", 386 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/004d_1-dual_n-back_modified.log\n", 387 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/005d_1-dual_n-back_modified.log\n", 388 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/006d_1-dual_n-back_modified.log\n", 389 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/007d_1-dual_n-back_modified.log\n", 390 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/008d_1-dual_n-back_modified.log\n", 391 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/010d_1-dual_n-back_modified.log\n", 392 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/011d_1-dual_n-back_modified.log\n", 393 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/012d_1-dual_n-back_modified.log\n", 394 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/013d_1-dual_n-back_modified.log\n", 395 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/014d_1-dual_n-back_modified.log\n", 396 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/015d_1-dual_n-back_modified.log\n", 397 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/016d_1-dual_n-back_modified.log\n", 398 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/018d_1-dual_n-back_modified.log\n", 399 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/019d_1-dual_n-back_modified.log\n", 400 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/020d_1-dual_n-back_modified.log\n", 401 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/021d_1-dual_n-back_modified.log\n", 402 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/023d_1-dual_n-back_modified.log\n", 403 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/024d_1-dual_n-back_modified.log\n", 404 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/025d_1-dual_n-back_modified.log\n", 405 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/026d_1-dual_n-back_modified.log\n", 406 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/027d_1-dual_n-back_modified.log\n", 407 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/028d_1-dual_n-back_modified.log\n", 408 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/029d_1-dual_n-back_modified.log\n", 409 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/030d_1-dual_n-back_modified.log\n", 410 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/033d_1-dual_n-back_modified.log\n", 411 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/035d_1-dual_n-back_modified.log\n", 412 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/036d_1-dual_n-back_modified.log\n", 413 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/037d_1-dual_n-back_modified.log\n", 414 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/039d_1-dual_n-back_modified.log\n", 415 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/041d_1-dual_n-back_modified.log\n", 416 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/042d_1-dual_n-back_modified.log\n", 417 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/043d_1-dual_n-back_modified.log\n", 418 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/044d_1-dual_n-back_modified.log\n", 419 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/045d_1-dual_n-back_modified.log\n", 420 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/046d_1-dual_n-back_modified.log\n", 421 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/047d_1-dual_n-back_modified.log\n", 422 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/048d_1-dual_n-back_modified.log\n", 423 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/050d_1-dual_n-back_modified.log\n", 424 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/051d_1-dual_n-back_modified.log\n", 425 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/052d_1-dual_n-back_modified.log\n", 426 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/053d_1-dual_n-back_modified.log\n", 427 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/054d_1-dual_n-back_modified.log\n", 428 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/055d_1-dual_n-back_modified.log\n", 429 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/056d_1-dual_n-back_modified.log\n", 430 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/001d_2-dual_n-back_modified.log\n", 431 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/002d_2-dual_n-back_modified.log\n", 432 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/004d_2-dual_n-back_modified.log\n", 433 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/005d_2-dual_n-back_modified.log\n", 434 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/006d_2-dual_n-back_modified.log\n", 435 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/007d_2-dual_n-back_modified.log\n", 436 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/008d_2-dual_n-back_modified.log\n", 437 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/010d_2-dual_n-back_modified.log\n", 438 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/011d_2-dual_n-back_modified.log\n", 439 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/012d_2-dual_n-back_modified.log\n", 440 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/013d_2-dual_n-back_modified.log\n", 441 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/014d_2-dual_n-back_modified.log\n", 442 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/015d_2-dual_n-back_modified.log\n", 443 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/016d_2-dual_n-back_modified.log\n", 444 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/018d_2-dual_n-back_modified.log\n", 445 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/019d_2-dual_n-back_modified.log\n", 446 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/020d_2-dual_n-back_modified.log\n", 447 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/021d_2-dual_n-back_modified.log\n", 448 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/023d_2-dual_n-back_modified.log\n", 449 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/024d_2-dual_n-back_modified.log\n", 450 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/025d_2-dual_n-back_modified.log\n", 451 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/026d_2-dual_n-back_modified.log\n", 452 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/027d_2-dual_n-back_modified.log\n", 453 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/028d_2-dual_n-back_modified.log\n", 454 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/029d_2-dual_n-back_modified.log\n", 455 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/030d_2-dual_n-back_modified.log\n", 456 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/033d_2-dual_n-back_modified.log\n", 457 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/035d_2-dual_n-back_modified.log\n", 458 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/036d_2-dual_n-back_modified.log\n", 459 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/037d_2-dual_n-back_modified.log\n", 460 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/039d_2-dual_n-back_modified.log\n", 461 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/041d_2-dual_n-back_modified.log\n", 462 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/042d_2-dual_n-back_modified.log\n", 463 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/043d_2-dual_n-back_modified.log\n", 464 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/044d_2-dual_n-back_modified.log\n", 465 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/045d_2-dual_n-back_modified.log\n", 466 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/046d_2-dual_n-back_modified.log\n", 467 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/047d_2-dual_n-back_modified.log\n", 468 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/048d_2-dual_n-back_modified.log\n", 469 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/050d_2-dual_n-back_modified.log\n", 470 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/051d_2-dual_n-back_modified.log\n", 471 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/052d_2-dual_n-back_modified.log\n", 472 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/053d_2-dual_n-back_modified.log\n", 473 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/054d_2-dual_n-back_modified.log\n", 474 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/055d_2-dual_n-back_modified.log\n", 475 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/056d_2-dual_n-back_modified.log\n", 476 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/001d_3-dual_n-back_modified.log\n", 477 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/002d_3-dual_n-back_modified.log\n", 478 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/004d_3-dual_n-back_modified.log\n", 479 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/005d_3-dual_n-back_modified.log\n", 480 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/006d_3-dual_n-back_modified.log\n", 481 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/007d_3-dual_n-back_modified.log\n", 482 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/008d_3-dual_n-back_modified.log\n", 483 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/010d_3-dual_n-back_modified.log\n", 484 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/011d_3-dual_n-back_modified.log\n", 485 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/012d_3-dual_n-back_modified.log\n", 486 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/013d_3-dual_n-back_modified.log\n", 487 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/014d_3-dual_n-back_modified.log\n", 488 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/015d_3-dual_n-back_modified.log\n", 489 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/016d_3-dual_n-back_modified.log\n", 490 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/018d_3-dual_n-back_modified.log\n", 491 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/019d_3-dual_n-back_modified.log\n", 492 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/020d_3-dual_n-back_modified.log\n", 493 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/021d_3-dual_n-back_modified.log\n", 494 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/023d_3-dual_n-back_modified.log\n", 495 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/024d_3-dual_n-back_modified.log\n", 496 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/025d_3-dual_n-back_modified.log\n", 497 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/026d_3-dual_n-back_modified.log\n", 498 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/027d_3-dual_n-back_modified.log\n", 499 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/028d_3-dual_n-back_modified.log\n", 500 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/029d_3-dual_n-back_modified.log\n", 501 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/030d_3-dual_n-back_modified.log\n", 502 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/033d_3-dual_n-back_modified.log\n", 503 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/035d_3-dual_n-back_modified.log\n", 504 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/036d_3-dual_n-back_modified.log\n", 505 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/037d_3-dual_n-back_modified.log\n", 506 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/039d_3-dual_n-back_modified.log\n", 507 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/041d_3-dual_n-back_modified.log\n", 508 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/042d_3-dual_n-back_modified.log\n", 509 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/043d_3-dual_n-back_modified.log\n", 510 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/044d_3-dual_n-back_modified.log\n", 511 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/045d_3-dual_n-back_modified.log\n", 512 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/046d_3-dual_n-back_modified.log\n", 513 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/047d_3-dual_n-back_modified.log\n", 514 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/048d_3-dual_n-back_modified.log\n", 515 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/050d_3-dual_n-back_modified.log\n", 516 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/051d_3-dual_n-back_modified.log\n", 517 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/052d_3-dual_n-back_modified.log\n", 518 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/053d_3-dual_n-back_modified.log\n", 519 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/054d_3-dual_n-back_modified.log\n", 520 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/055d_3-dual_n-back_modified.log\n", 521 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/056d_3-dual_n-back_modified.log\n", 522 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/001d_4-dual_n-back_modified.log\n", 523 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/002d_4-dual_n-back_modified.log\n", 524 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/004d_4-dual_n-back_modified.log\n", 525 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/005d_4-dual_n-back_modified.log\n", 526 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/006d_4-dual_n-back_modified.log\n", 527 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/007d_4-dual_n-back_modified.log\n", 528 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/008d_4-dual_n-back_modified.log\n", 529 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/010d_4-dual_n-back_modified.log\n", 530 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/011d_4-dual_n-back_modified.log\n", 531 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/012d_4-dual_n-back_modified.log\n", 532 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/013d_4-dual_n-back_modified.log\n", 533 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/014d_4-dual_n-back_modified.log\n", 534 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/015d_4-dual_n-back_modified.log\n", 535 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/016d_4-dual_n-back_modified.log\n", 536 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/018d_4-dual_n-back_modified.log\n", 537 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/019d_4-dual_n-back_modified.log\n", 538 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/020d_4-dual_n-back_modified.log\n", 539 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/021d_4-dual_n-back_modified.log\n", 540 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/023d_4-dual_n-back_modified.log\n", 541 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/024d_4-dual_n-back_modified.log\n", 542 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/025d_4-dual_n-back_modified.log\n", 543 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/026d_4-dual_n-back_modified.log\n", 544 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/027d_4-dual_n-back_modified.log\n", 545 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/028d_4-dual_n-back_modified.log\n", 546 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/029d_4-dual_n-back_modified.log\n", 547 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/030d_4-dual_n-back_modified.log\n", 548 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/033d_4-dual_n-back_modified.log\n", 549 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/035d_4-dual_n-back_modified.log\n", 550 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/036d_4-dual_n-back_modified.log\n", 551 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/037d_4-dual_n-back_modified.log\n", 552 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/039d_4-dual_n-back_modified.log\n", 553 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/041d_4-dual_n-back_modified.log\n", 554 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/042d_4-dual_n-back_modified.log\n", 555 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/043d_4-dual_n-back_modified.log\n", 556 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/044d_4-dual_n-back_modified.log\n", 557 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/045d_4-dual_n-back_modified.log\n", 558 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/046d_4-dual_n-back_modified.log\n", 559 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/047d_4-dual_n-back_modified.log\n", 560 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/048d_4-dual_n-back_modified.log\n", 561 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/050d_4-dual_n-back_modified.log\n", 562 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/051d_4-dual_n-back_modified.log\n", 563 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/052d_4-dual_n-back_modified.log\n", 564 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/053d_4-dual_n-back_modified.log\n", 565 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/054d_4-dual_n-back_modified.log\n", 566 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/055d_4-dual_n-back_modified.log\n", 567 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/056d_4-dual_n-back_modified.log\n" 568 | ] 569 | } 570 | ], 571 | "source": [ 572 | "root = '/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral'\n", 573 | "\n", 574 | "task_meta = {\n", 575 | " 'n_stims': 12,\n", 576 | " 'n_blocks': 10,\n", 577 | " 'n_modalities': 2,\n", 578 | " 'n_conditions': 2,\n", 579 | " 'n_sessions': 4,\n", 580 | " 'n_measures': 3,\n", 581 | " 'ttr': 20000,\n", 582 | " 'n_subjects': df_group.shape[0]\n", 583 | "}\n", 584 | "\n", 585 | "beh = np.full((task_meta['n_subjects'], task_meta['n_sessions'], \n", 586 | " task_meta['n_measures'] + 2, task_meta['n_conditions'], \n", 587 | " task_meta['n_modalities']), \n", 588 | " np.nan)\n", 589 | "beh_block = np.full((task_meta['n_subjects'], task_meta['n_sessions'], \n", 590 | " task_meta['n_measures'], task_meta['n_conditions'], \n", 591 | " task_meta['n_modalities'], task_meta['n_blocks']), \n", 592 | " np.nan)\n", 593 | "\n", 594 | "for ix_ses, ses in enumerate(['1', '2', '3', '4']):\n", 595 | " for ix_sub, sub in enumerate(df_group['sub']):\n", 596 | " \n", 597 | " logpath = os.path.join(root, f'0{sub[-2:]}d_{ses}-dual_n-back_modified.log')\n", 598 | " print(logpath)\n", 599 | " \n", 600 | " if os.path.exists(logpath):\n", 601 | "\n", 602 | " beh[ix_sub, ix_ses], beh_block[ix_sub, ix_ses] = \\\n", 603 | " calculate_behavioral_measures(convert_logfile(logpath, task_meta), task_meta)\n", 604 | " \n", 605 | "# Create metadata describing beh and beh_block fields\n", 606 | "meta = {\n", 607 | " 'dim1': df_group['sub'].tolist(),\n", 608 | " 'dim2': [f'ses-{ses}' for ses in range(1, task_meta['n_sessions'] + 1)],\n", 609 | " 'dim3': ['acc', 'prt', 'dpr', 'hit_rate', 'fal_rate'],\n", 610 | " 'dim4': ['1-back', '2-back'],\n", 611 | " 'dim5': ['vis', 'aud'],\n", 612 | " 'dim6': [f'block-{block:02}' for block in range(1, task_meta['n_blocks'] + 1)],\n", 613 | " 'exp': list(df_group['group'] == 'Experimental'),\n", 614 | " 'con': list(df_group['group'] == 'Control'),\n", 615 | "}\n", 616 | "\n", 617 | "# Save aggregated behavioral measures\n", 618 | "np.save('data/aggregated_behavioral_data.npy', beh)\n", 619 | "np.save('data/aggregated_behavioral_data_block.npy', beh_block)\n", 620 | "with open('data/aggregated_behavioral_data.json', 'w') as f:\n", 621 | " json.dump(meta, f)" 622 | ] 623 | } 624 | ], 625 | "metadata": { 626 | "kernelspec": { 627 | "display_name": "Python 3", 628 | "language": "python", 629 | "name": "python3" 630 | }, 631 | "language_info": { 632 | "codemirror_mode": { 633 | "name": "ipython", 634 | "version": 3 635 | }, 636 | "file_extension": ".py", 637 | "mimetype": "text/x-python", 638 | "name": "python", 639 | "nbconvert_exporter": "python", 640 | "pygments_lexer": "ipython3", 641 | "version": "3.7.3" 642 | } 643 | }, 644 | "nbformat": 4, 645 | "nbformat_minor": 4 646 | } 647 | -------------------------------------------------------------------------------- /02-fmri_data_preparation/02-timeseries_extraction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# **Working memory training**: Timeseries extraction\n", 8 | "\n", 9 | "Timeseries extraction of data from working memory training experiment.\n", 10 | "\n", 11 | "Filtering:\n", 12 | "- 0.008 - 0.25 Hz\n", 13 | "\n", 14 | "**Last edited:** 09-11-2018\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "Step 0: Loading libraries\n", 22 | "-----------------------" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 2, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "%matplotlib inline\n", 32 | "\n", 33 | "import sys\n", 34 | "sys.path.append(\"..\")\n", 35 | "\n", 36 | "import os\n", 37 | "import pandas as pd\n", 38 | "import nibabel as nib\n", 39 | "import numpy as np \n", 40 | "import matplotlib.pyplot as plt \n", 41 | "import warnings\n", 42 | "warnings.filterwarnings('ignore')\n", 43 | "\n", 44 | "from nilearn import datasets, plotting, input_data, signal, image \n", 45 | "from nilearn.input_data import NiftiLabelsMasker\n", 46 | "\n", 47 | "from fctools import denoise" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "Step 1: Preparing paths to files\n", 55 | "------------------------------" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 3, 61 | "metadata": {}, 62 | "outputs": [ 63 | { 64 | "name": "stdout", 65 | "output_type": "stream", 66 | "text": [ 67 | "Sample size: 46\n" 68 | ] 69 | } 70 | ], 71 | "source": [ 72 | "# Setting directories for input and output files\n", 73 | "top_dir = '/media/finc/Elements/LearningBrain_fmriprep/'\n", 74 | "out_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/01-extracted_timeseries/'\n", 75 | "\n", 76 | "# Selecting subjects who finished the study\n", 77 | "groups = pd.read_csv('../data/behavioral/group_assignment.csv')\n", 78 | "subs = pd.Series.tolist(groups['sub'][groups['group'].isin(['Experimental', 'Control'])])\n", 79 | "\n", 80 | "# Setting sessions and task names\n", 81 | "sess = ['ses-1', 'ses-2', 'ses-3', 'ses-4']\n", 82 | "tasks = {'rest': 305, 'dualnback': 340}\n", 83 | "t_r = 2\n", 84 | "\n", 85 | "suffix = '_bold_space-MNI152NLin2009cAsym_preproc.nii.gz'\n", 86 | "denoising = '_denoised_acompcor_task_effects.nii.gz'\n", 87 | "\n", 88 | "print(f'Sample size: {len(subs)}')" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "Step 2: Creating parcellations \n", 96 | "--------------------------------" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 4, 102 | "metadata": {}, 103 | "outputs": [ 104 | { 105 | "data": { 106 | "image/png": "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\n", 107 | "text/plain": [ 108 | "
" 109 | ] 110 | }, 111 | "metadata": {}, 112 | "output_type": "display_data" 113 | } 114 | ], 115 | "source": [ 116 | "# Loading Power ROIs coordinates\n", 117 | "power = datasets.fetch_coords_power_2011()\n", 118 | "power_coords = np.vstack((power.rois['x'], power.rois['y'], power.rois['z'])).T\n", 119 | "\n", 120 | "# Creating masker file\n", 121 | "power = input_data.NiftiSpheresMasker(\n", 122 | " seeds = power_coords, \n", 123 | " radius = 5,\n", 124 | ")\n", 125 | "\n", 126 | "# Loading Schaefer atlas (300 regions)\n", 127 | "atlas_filename = '/home/finc/Dropbox/Projects/LearningBrain/support/Schaefer2018_300Parcels_7Networks_order_FSLMNI152_2mm.nii.gz'\n", 128 | "plotting.plot_roi(atlas_filename)\n", 129 | "schaefer = input_data.NiftiLabelsMasker(atlas_filename)\n", 130 | "\n", 131 | "\n", 132 | "parcellations = np.asarray([[power, 'power', 264], \n", 133 | " [schaefer, 'schaefer', 300]])\n" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "Step 3: Extracting timeseries\n", 141 | "----------------------" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": 47, 147 | "metadata": {}, 148 | "outputs": [ 149 | { 150 | "name": "stdout", 151 | "output_type": "stream", 152 | "text": [ 153 | "Extracting timeseries: schaefer_new parcellation, rest\n", 154 | "Extracting timeseries sub-01\n", 155 | "Extracting timeseries sub-02\n", 156 | "Extracting timeseries sub-04\n", 157 | "Extracting timeseries sub-05\n", 158 | "Extracting timeseries sub-06\n", 159 | "Extracting timeseries sub-07\n", 160 | "Extracting timeseries sub-08\n", 161 | "Extracting timeseries sub-10\n", 162 | "Extracting timeseries sub-11\n", 163 | "Extracting timeseries sub-12\n", 164 | "Extracting timeseries sub-13\n", 165 | "Extracting timeseries sub-14\n", 166 | "Extracting timeseries sub-15\n", 167 | "Extracting timeseries sub-16\n", 168 | "Extracting timeseries sub-18\n", 169 | "Extracting timeseries sub-19\n", 170 | "Extracting timeseries sub-20\n", 171 | "sub-20ses-2rest does not exist\n", 172 | "Extracting timeseries sub-21\n", 173 | "Extracting timeseries sub-23\n", 174 | "Extracting timeseries sub-24\n", 175 | "Extracting timeseries sub-25\n", 176 | "Extracting timeseries sub-26\n", 177 | "Extracting timeseries sub-27\n", 178 | "Extracting timeseries sub-28\n", 179 | "Extracting timeseries sub-29\n", 180 | "Extracting timeseries sub-30\n", 181 | "Extracting timeseries sub-33\n", 182 | "Extracting timeseries sub-35\n", 183 | "Extracting timeseries sub-36\n", 184 | "Extracting timeseries sub-37\n", 185 | "Extracting timeseries sub-39\n", 186 | "Extracting timeseries sub-41\n", 187 | "Extracting timeseries sub-42\n", 188 | "Extracting timeseries sub-43\n", 189 | "Extracting timeseries sub-44\n", 190 | "sub-44ses-2rest does not exist\n", 191 | "Extracting timeseries sub-45\n", 192 | "Extracting timeseries sub-46\n", 193 | "Extracting timeseries sub-47\n", 194 | "Extracting timeseries sub-48\n", 195 | "Extracting timeseries sub-50\n", 196 | "Extracting timeseries sub-51\n", 197 | "Extracting timeseries sub-52\n", 198 | "Extracting timeseries sub-53\n", 199 | "Extracting timeseries sub-54\n", 200 | "Extracting timeseries sub-55\n", 201 | "Extracting timeseries sub-56\n", 202 | "Extracting timeseries: schaefer_new parcellation, dualnback\n", 203 | "Extracting timeseries sub-01\n", 204 | "Extracting timeseries sub-02\n", 205 | "Extracting timeseries sub-04\n", 206 | "Extracting timeseries sub-05\n", 207 | "Extracting timeseries sub-06\n", 208 | "Extracting timeseries sub-07\n", 209 | "Extracting timeseries sub-08\n", 210 | "Extracting timeseries sub-10\n", 211 | "Extracting timeseries sub-11\n", 212 | "Extracting timeseries sub-12\n", 213 | "Extracting timeseries sub-13\n", 214 | "Extracting timeseries sub-14\n", 215 | "Extracting timeseries sub-15\n", 216 | "Extracting timeseries sub-16\n", 217 | "Extracting timeseries sub-18\n", 218 | "Extracting timeseries sub-19\n", 219 | "Extracting timeseries sub-20\n", 220 | "Extracting timeseries sub-21\n", 221 | "Extracting timeseries sub-23\n", 222 | "Extracting timeseries sub-24\n", 223 | "Extracting timeseries sub-25\n", 224 | "Extracting timeseries sub-26\n", 225 | "Extracting timeseries sub-27\n", 226 | "Extracting timeseries sub-28\n", 227 | "Extracting timeseries sub-29\n", 228 | "Extracting timeseries sub-30\n", 229 | "Extracting timeseries sub-33\n", 230 | "Extracting timeseries sub-35\n", 231 | "Extracting timeseries sub-36\n", 232 | "Extracting timeseries sub-37\n", 233 | "Extracting timeseries sub-39\n", 234 | "Extracting timeseries sub-41\n", 235 | "Extracting timeseries sub-42\n", 236 | "Extracting timeseries sub-43\n", 237 | "Extracting timeseries sub-44\n", 238 | "Extracting timeseries sub-45\n", 239 | "Extracting timeseries sub-46\n", 240 | "Extracting timeseries sub-47\n", 241 | "Extracting timeseries sub-48\n", 242 | "Extracting timeseries sub-50\n", 243 | "Extracting timeseries sub-51\n", 244 | "Extracting timeseries sub-52\n", 245 | "Extracting timeseries sub-53\n", 246 | "Extracting timeseries sub-54\n", 247 | "Extracting timeseries sub-55\n", 248 | "Extracting timeseries sub-56\n" 249 | ] 250 | } 251 | ], 252 | "source": [ 253 | "# Iterating over parcellations\n", 254 | "for p in range(parcellations.shape[0]):\n", 255 | " n_roi = parcellations[p,2]\n", 256 | " \n", 257 | " # Iterating over tasks\n", 258 | " for task, n_scans in tasks.items():\n", 259 | " print(f'Extracting timeseries: {parcellations[p,1]} parcellation, {task}')\n", 260 | " timeseries_all = np.zeros((len(subs), len(sess), n_scans, n_roi))\n", 261 | " \n", 262 | " # Iterating over subjects, sessiosns\n", 263 | " for i, sub in enumerate(subs):\n", 264 | " print(f'Extracting timeseries {sub}')\n", 265 | " for j, ses in enumerate(sess):\n", 266 | " \n", 267 | " # Getting directory/file names\n", 268 | " sub_dir = f'{top_dir}{sub}/{ses}/func/'\n", 269 | " sub_name = f'{sub}_{ses}_task-{task}' \n", 270 | " denoised_data = f'{sub_dir}{sub_name}{suffix[:-7]}{denoising}'\n", 271 | "\n", 272 | " if not os.path.exists(denoised_data):\n", 273 | " print(f'{sub}{ses}{task} does not exist')\n", 274 | " else:\n", 275 | " # Extracting timeseries for specified atlas\n", 276 | " timeseries = parcellations[p,0].fit_transform(denoised_data, confounds=None)\n", 277 | " # Filtering data\n", 278 | " timeseries = signal.clean(timeseries, \n", 279 | " low_pass=0.25, \n", 280 | " high_pass=0.008, \n", 281 | " t_r=t_r, \n", 282 | " detrend=False, \n", 283 | " standardize=True,\n", 284 | " )\n", 285 | " timeseries_all[i, j, :, :] = timeseries\n", 286 | " np.save(f'{out_dir}/{task}/LB_{task}_timeseries_{parcellations[p,1]}_denoised_acompcor_no_smooth.npy', timeseries_all)" 287 | ] 288 | } 289 | ], 290 | "metadata": { 291 | "kernelspec": { 292 | "display_name": "Python 3", 293 | "language": "python", 294 | "name": "python3" 295 | }, 296 | "language_info": { 297 | "codemirror_mode": { 298 | "name": "ipython", 299 | "version": 3 300 | }, 301 | "file_extension": ".py", 302 | "mimetype": "text/x-python", 303 | "name": "python", 304 | "nbconvert_exporter": "python", 305 | "pygments_lexer": "ipython3", 306 | "version": "3.7.3" 307 | } 308 | }, 309 | "nbformat": 4, 310 | "nbformat_minor": 2 311 | } 312 | -------------------------------------------------------------------------------- /02-fmri_data_preparation/03-static_FC_estimation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# **Working memory training**: Static connectivity estimation" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Step 0: Loading libraries\n", 15 | "--------------------------------" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 2, 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "name": "stderr", 25 | "output_type": "stream", 26 | "text": [ 27 | "/home/finc/anaconda3/lib/python3.7/site-packages/matplotlib/__init__.py:855: MatplotlibDeprecationWarning: \n", 28 | "examples.directory is deprecated; in the future, examples will be found relative to the 'datapath' directory.\n", 29 | " \"found relative to the 'datapath' directory.\".format(key))\n", 30 | "/home/finc/anaconda3/lib/python3.7/site-packages/matplotlib/__init__.py:846: MatplotlibDeprecationWarning: \n", 31 | "The text.latex.unicode rcparam was deprecated in Matplotlib 2.2 and will be removed in 3.1.\n", 32 | " \"2.2\", name=key, obj_type=\"rcparam\", addendum=addendum)\n" 33 | ] 34 | } 35 | ], 36 | "source": [ 37 | "%matplotlib inline\n", 38 | "\n", 39 | "\n", 40 | "import sys\n", 41 | "sys.path.append(\"..\")\n", 42 | "\n", 43 | "import os\n", 44 | "\n", 45 | "import pandas as pd\n", 46 | "import numpy as np \n", 47 | "import matplotlib.pyplot as plt \n", 48 | "\n", 49 | "from nilearn import datasets, plotting, input_data, signal # for fetching atlas\n", 50 | "\n", 51 | "from nilearn.input_data import NiftiLabelsMasker\n", 52 | "from nilearn.connectome import ConnectivityMeasure\n", 53 | "from nistats.reporting import plot_design_matrix\n", 54 | "from nistats.design_matrix import make_first_level_design_matrix\n", 55 | "from sklearn.covariance import EmpiricalCovariance\n", 56 | "\n", 57 | "import seaborn as sns\n", 58 | "sns.reset_orig()\n", 59 | "\n", 60 | "from fctools import denoise, stats" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "Step 1: Design specification\n", 68 | "--------------------------------" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 3, 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "name": "stderr", 78 | "output_type": "stream", 79 | "text": [ 80 | "/home/finc/anaconda3/lib/python3.7/site-packages/nistats/utils.py:276: UserWarning: Matrix is singular at working precision, regularizing...\n", 81 | " warn('Matrix is singular at working precision, regularizing...')\n" 82 | ] 83 | }, 84 | { 85 | "data": { 86 | "text/plain": [ 87 | "[]" 88 | ] 89 | }, 90 | "execution_count": 3, 91 | "metadata": {}, 92 | "output_type": "execute_result" 93 | }, 94 | { 95 | "data": { 96 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYAAAAD8CAYAAAB+UHOxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJztvXmcXFd17/tdNfSkqVtSyxpag41lG4MnWR4wZnIw2M5gAuQBIUyB+JKLE0jCJ/iFB+HeJBfuyyPvhgfYzwHHTMEJ4AQHzBQggDGDZXmesGxZUkuWpZZaU6u7a9r3j1On6nR1VXedvffZu7vr/D4ff6zuru511jn7rLXXbw1blFKkSJEiRYrOQ8b3BaRIkSJFCj9IHUCKFClSdChSB5AiRYoUHYrUAaRIkSJFhyJ1AClSpEjRoUgdQIoUKVJ0KFIHkCJFihQditQBpEiRIkWHInUAKVKkSNGhyPm+gJmwcuVKtWnTJt+XkSJFihTzBvfee++IUmqwnc/OaQewadMmtm3b5vsyUqRIkWLeQER2tfvZlAJKkSJFig5F6gBSpEiRokOROoAUKVKk6FCkDiBFihQpOhSpA0iRIkWKDkXqAFKkSJGiQ5E6gBQpUqToUHSUA3h03zE+/7NnePbouFO5Sim+9ItdfO/R56hU3B7BuePAcW796U72HD7pVC7Av2zbw7cffpayY52fGRnjH3+6k50jY07lAvzbfXv5xoP7KJYrTuXuPTLOLXftZMeB407lAnzzwWf5+v17mSyVnco9cGyCW+7ayWPPHnMqF+B7jz7H1+4dZrzgVmfb6CgH8Pff/xUf/voj/MXtDzmVu3NkjA/+68P8wee3ce/uUaeyb/zPp/nIvz/Kn/3LA07lHjg2wZ9/9UHe/cXt/PjJg05l33r3M/y3f3+U//ql7U7ljk2WeN8/38/1/3Qf3354v1PZ//SLXfz3bzzK79/qtnGyUlG855+2897b7udft+91Kvtr2/fy37/xKG/4/3/mVC7AH3x+G3/2lQf40i/a7rmak+goB3Cy6q2fPTrhRS7AviNuo4+ThVIg13HUMxbR+dkjbu/32GSgs+tIL/qcXcsemwxk7z86gVLuIq7JUj3S2ef8vQqe87GJEhNFdzvx6P11bUtso6McQLhIRk4UnModjyzOQ55kO5dbiOo86VZ2VecjJ4tOqZgJj885lF0oVzg2UXImd+radvyco2tszN39LkTWlGudbaOjHEC4WA+PTTrl4qcuVD8vyXixXNsxOZFb9PNywlRDPOpQdlRnv5sMd2tsLmxuAtnudJ4oRByA47VtG53lAKrGsKLgyHjRndw5sDMEGDnuTnZU7kFPEQC4NcRzwdFDB+ns6b2Kyj14PI0A5g0mihV68oHKIy53DNUF053LOJUbyI7o7PAFDXXuyWech8kTxQrdOX/PuSfv4TmX6s/Z6W54ytp2u7mZjKxtl5uMKWs7jQBARG4RkQMi8nCLn79ZRB6s/ne3iJxnQ25cTBTLDA30AX4Mw9BArxdqINTZxy5paKDPS/5haKAXcLsrDXVe19/rPtIrRNa2Q6M0dW27jwDW9Vefs6e1fXis4Ly02yZsRQC3AlfN8POdwMuUUucCfwXcbEluLATG0MOCKUSMoYcwOdTZ5Qta19m9YZjw5PQmGpyey2qc8WKZNct6EIERh7RE1Bgenyg57QUYL5RZsaib3nzWS95jaKCXckU5pZNtw4oDUEr9GDg8w8/vVkqFBfA/B4ZsyI0DpZQ/Y1gMkkZDA71OeXgIdob1XZKfqGf0ZJGSw2qc8WKZwSXddGUzTqmB0DCsX97rpRpnSU+Ogb4ut1FPxNGD+514T1eWlUu63Eb003Sev3kAHzmAdwLfci10slRBKVi9tIdsRryEjGv7e51X40yUyizrzbOkJ+c2ORjZGQIcPulWdl9XlhWLuxxHeqGjD6MPt4a4J59lxSLHOjc8Z9cRV28+w4pF3U65+EadXdO6NuHUAYjIKwgcwAdm+Mx1IrJNRLYdPGivgzTckfZ15Vi+yO0uaaJYpiefYXBJN+DuJSmWKxTLit58lpWLux1TQPWoB9xWII0XyvTmQwfghxoAtyWCgTEMdPaV3wK3hQbjxcDprVzc5Wlz455NsA1nDkBEzgU+A1yrlDrU6nNKqZuVUluVUlsHB9s617gtTFRpmN6uwBgedFwS2ZvPMrg4cACuaInw5Qx0drsznCiV6cpmOGVpD+AuGVupKCZLlaph6HZqGCYad4YOufhwja1c3O14Fx68V+uX+9XZrdOr6uwh0rMNJw5ARDYAtwNvUUr9yoXMRoReu7e6Y3DNk4a7M3AXAYQ6B9SA6wggiHpWLAp0diU7HE3Q2xXo7DrvkRFYsyxweq6qccL8Vm1z0yFRT432WtzltBon1HnNsh4yMr8poJyNPyIiXwZeDqwUkWHgL4E8gFLqJuDDwArg0yICUFJKbbUhu12EyarQKO065G46ZhiqrlgcUkCOIoAqDRO+JL98xu1ueKrOjp1eLhNQA2NBNU513SUru+roly8KHb2b51woV6io4Dl3ZTO1apzuXDZx2eF7tbyvy3nPx0SxUnP05Yri6HiRgeq9T1RuoR5ZL1/U7byyzyasOACl1Jtm+fm7gHfZkKWL6G7YfchYT9CBu93wRCka9XQzerJAqVwhl00+8At3pEt7cnRl3TUJjU+hvboplCocnyyxtCfvRHZvV5Z8NsNAX97dc444+r6uwOgfHiuwZllv8rKLZbpzGTIZcUq5lcoVCuVKsLarubWRE5NOHMBUW+I2/2AbHdMJPBGhgFYs7uZkwV01TmgYevJZlnS7q8YZr+1Ugt2wUu6qccLdsIg4TUzWIz0/lFu4617hkIuP0pu1TYajHFe4tiHQ2d3mJnR6GVbWNlbudM5nhXw243wzaRsd4wDGI2Gbc8NQNYZAUJniiCedkgPwQMX0RHV2nfj2QblFjaHDcsx61JOp6eyqGie6tle61LnQ5Dk71Hnq2k4jgDmPKB0yWFswbh5cMI+n+pIsdpeYnJr4dusAJouVumFY7K5Ou7HyCdztDCeiOi/pdmaEo05v0PFznig1Pme3Ooc0DDhc26XyVJ3TCGDuoxk14KpkbcrO0CEdMlmcHvU4o2Km7Ia7nd3rZk7PJf0U3Q271nnK2naoc+Nu2EU1TtTR9/d1VatxHD7nyPs8VijP26MhO8YBTDSjQ1yFjMUyPdXplD644Z5clpWLHBvDavMbMKUaJ3G5EUdfr8ZxmAPI15/zsYkShVLyIzAmIjr3dWWdVuNMRJ7zisXdlCqKYxPJz8aJru1sRli+yF0yNnifQ0fv9r2yjY5xANHqkBUekkbhjmHl4m4OV6txEpdbqNfEL+3Nkc+K0wR0lPYKq3ESlxtx9Plshn6X1TjFqdQAuNlkRKMeEbfVOFPXtrvoI5rTC2S7S8aOFyv0hHKXuI24bKNzHEBYKpfL0JPPsqw3z35H53lGqYFVS7pRyk03cNQYigirlvTw3DE3OkeN4aqlgTF8zsH9jlIDAKcs6WG/I52jxnBVtTTRxRobb9B51ZJuL2s77Pref9Tt2gYYXNLtbm0XghlEAKuWBDq7km0bHeMAwtEEYQ380EAvw6PJN4NFRxOEcgH2jiZ/aHg0OQiwbqDXidxQdm+DzsNHXOhcjXoiOg/70Hl59Tl70HlooM+JXAjeq3Bth1NnXbxXTXV29ZxLTda2I9m20TEOYLxQ52cheHAuXpLJUr1JJ5AbzA9xsWDC0QT5rFRlu3F6MLUM1KXO9Z1h3dHvdaVzoZkxdKdzd0TnfUfGKbtIxkZ0XrMsmLTrxulNf86HxgpOenuiz3lZb57F3bnUAcx1lCoVurJRB9DH8Oh44onJYiVwAFEjDG52ScWyIp/N1MYgDA30sf/YBMWE8w+ViqKiIF+934OLg9n8LnQOcyv5SKR3bKLEUQeHdpQqqvacl/Tk6e/LO9W5q6ZzH6WKckJLFCuqdq9z2Qyrl/Y4MYbFJs8Z3ETWpYjOIlLdWKUOYE6jXFFkM/V5MOv6ezlZKDN6MlnDUC4HDiZXlR3WLbvYJZUrlZpcgKH+XioqeV66VN155qrGMJMR1vb3OHs5AbIRpwfuDEM2U3+l1vW7odzCnX64vtcNuKOfyhU1dY05ijLLDWvMJc1Yaniv1vW7YROSQMc4gFJ5+kKF5HfiNYMUiT7WVaOPpFFqcHqhznsS1rnRIAWy3ehcrigyEjidQK67iKu5MXTn9HKZqbthV9GHj+dcalhjLmnGcnn6e+WKWrWNjnEA5Yoim526UCH5BVPbqXgwDOWKmjL4zZXOpSrt5csY5jLudVZKTYsyXdGM0yKAMP9w2E8EsP/YROL9D+UGp+eUZqyoWuQB9fOQXdCMttExDqDRMGxY0YcI7DhwImG5wYsQNQybVvSx5/DJWiIrOdlTDdKa/h66shmeSljnZhHAxhWLGDkxyZGEh9E1GuGBvuA4zB0H3eica3jO48Uy+5Km3JrQjGuW9SSuM1TXWMQYblrZh1Kwc2QscblQX2OZjLBhRV/iaxumr7GNK4JNRtK2JAl0kAOYGqou7s5x+uBitu8eneG3LMgtTzcM568foFRRPLT3aMKyp3KV+WyGs9cuTVznYhOdz1u/DID7dh9JWPZUnUWE89f3s31Xws+5RvVFde4HcCC7gkRoL4DzhvoTf86B7KkRwHlDVZ0Tf6+mR5nnr+9n++4jyRd2lCtTNpPnV5/zfQ7ut210jgNoyAEAXLhxgPt2H0l0dknjTgXggg2uDMPUnQoEOj84fDTREL0eAdSX13lD/WQzkrhhaKT6ALZsGOBXzx3nRIKdyKUmEcDz1yylJ59J3hhWmq/tPYfHOZjgPKI67VV/zqeuXMRAX96dw43ovWXDAIfHCokf9tQYAaxa2sPQQK8Th2sbHeMAyg28HQQL5uh4kacTDFdDY5iPcPErF3ezcUUf9yb8kjTysxDoPFmq8NizxxKTW8sBRO73ou4cZ61e4sgYTl3WWzYOUFHwwJ7koo96tVdddj6b4dyhYFeaJBoNEsCWjcnvxGtruyHi2rJhwImjh6nvlQudobnD3bJhgO27kn3OScCKAxCRW0TkgIg83OLnIiKfEJEdIvKgiGyxITcOGkv0AC45bTkA33zw2QTlTs8BAFx66gru2jGSKCdeakgCA1y0aYCMwDcfSk7nZnw4wKWnreCenaMcSLA+vdwk0rtgQz9d2QzfcPCcGzcZl562goeGj7A7wV1pqazIN6ztF6xdxqKubMJrezrtBYHOTx0cS3iTEciOPurNq5awfFFXojpD883kpaetYP+xCe7ddThR2bZhKwK4Fbhqhp9fDWyu/ncdcKMluW2j2W5444pFXHHWKm69e2diGfxWxvDtL97EyUKZW+7amYhcaG4MVy3t4TfOXcuXfr4rsQFWzcJzgLe+aCOlSoWbfvR0InJD2Y1yl/bked2FQ3zt3uHE6rWbJb4B3nzJBnKZDJ/64Y5E5AayK9OMcE8+y5sv3cg3HtzHUwklg1ut7d/ZOsSiriyf/MGOxPj4sMcletZzNiO87UWb+P7jB3g4ofyaUqrpZvI1F6xloC/P/5egzknA1pnAPxaRTTN85Frg8yq4Mz8XkX4RWaOUStZVR9CYBA7xx7+2mdffeDevv/Fu3nDRelYv62HrxuWsXtZjSW5zw/D8NUv59XPW8Ikf7ODgiQIXbOhn7bJeLnveiinJPFPZzXS+/orT+fYj+3n9jXfz5ks2csqyHrZs6K+VTJqisUQvxMYVi3j9hUPc8tOdHJsocvGm5axa2s1LNg82vU492ZVpuzOAP3zZ8/j6/Xv5P276GW950UbWLOvh/PX9bFyxyIrcZjkACAak/d6lG7nlpzsZL5Z58ekrGFwS6Jy3dDZzM0oC4J2Xn8ptv9zNm27+OW+7bBNDA728cN0ynje42JpcYJox7O/r4p2Xn8onfrCD0hcrvPzMVQwu7uYlZ6y0dlB9q7X9tss28oWfP8Nbb/kl77hsE+uX93H22qWcccoSK3LDdGHj/e7ryvGHL38e/+POx/n9W+/hyrNXs2JxFy87Y7A2NmIuwooDaAPrgD2Rr4er35vmAETkOoIogQ0bNli7gHKkfTuK89f384/vuIgPf/0R/vqbjwHBWNvv/snLavPkTeXCdGMI8HdvOI+lvXlu3z7Ml3+5G4DrX3E673/1mcZyA9mVpobhjFOW8KV3XcJf3P4Qf3NnoPPSnhzf/ZOXWXF8YeVTsxf0b377HPq6cvzzPXv46r3DALz9sk185LdeYCwXWhuGDSv6uO26S7nhaw/xsW89DgSDxL713pewaaW5E2iW+A7xwV9/Pl25DF/8+S7ueGAfAK+/cIj/53fOM5Ybym6m8ylLe/jKuy/jz7/6AH/7nSeAYFzEv//R5Zy52twgtooAAP7kyjPIZITP3rWT7zzyHABXv3A1n37zlim7dm3ZTaJbCJzPV959Ge//ygN8/Hu/AoJ1+NV3v4gLNgwYy21F6QL8wUtOQym48UdP8cMnDgLw0jMG+dw7LrKicxJwlQRupn3TOEkpdbNSaqtSauvg4KC1C2hlGABesnmQH/zZy7jng6/ki++8hKPjRT7+3SfsyJ3BGHbnsnz0tefwwF++ip/8+St4zflrufFHT1nji2fS+aJNy/nun7yUe/+vV/KVd7+IYlnxsW89ZkXuTIYhn83wkd96Aff/5ZX85M9fwZsu3sCtdz/DE/uPW5PdTC7AuUP93Pnel7D9Q1fyb+95Mbms8NfffNSK3FYRAATP/oarz2L7h67krg+8gnddfipfvXfYWhFAs8R3iDNXL+Hr11/O/R++km/80eUs6cnxl3c0TdVpyG1tDEWE973yDLZ/6Ep+esMV/PEVp/Oth/fzkydHLMluvbZPXbmIr/3hZTzw4Vfxnfe9lFOWdPOhr9vReaa1LSL8l5c9j20ffCV333AFH7jqLH78q4N8++H9VmQnAVcOYBhYH/l6CNjnSDYws2GA4OENLunm8s0reeG6ZdZKyRpnljRDTz7L+uV9vOGiDZQrylo3Y3kGwwCBzisWd3PRpuVs3TTATmuOp2oYZtC5Oxfo/LsXB1HerkN2KrGa8bONWL6oi/PX93P56St5xtpzbm0MQ3TlMgwN9PHmSzcC9nRuFQFE0d/XxQvXLeMVZ62yv7ZnkJ3PZljX38vvvci+zo0FDo1Y1pfnzNVLeNULVrNrxN6mCmZ+zrlshrX9vbz9sk0A1tZYEnDlAO4A3lqtBroUOOqS/4egOWk2wxCiJ5e11qVbbMMw1ORWR9uGB9ibolSe3TDUZWdrZwiboh3DUJcb6mynL6Gx+W1m2Rafc5Pmt9ZyqzoXLek8y+amUbYtnWeKbqfLDXhwezo3z+m1km3rnWoc7jgTunPhc5675wVbyQGIyJeBlwMrRWQY+EsgD6CUugm4E7gG2AGcBN5hQ24ctOLDm6Enn+H4pJ2qoDgLJomXpDvf3iO2aQzb2SVF5YK9l2QmamC67Iy1e92qCqip3JxdnctxjGEua9XxwMzRbVQuWHzOLXIATWXnMxTL02c1acltMtyxFTIZoSuXseZ8koCtKqA3zfJzBbzHhixdNM4smQmBMbT7kvgwhnEWfE8uUzu8xhSlJk1RrRAeYmIz+mjXMHTn7EU9sYxh+JwtGYZizEhvolRGKWWcmKzTXrM/53xWyIg9nWOt7ch7tajbzOQ1G3Q4o+xchklLtiQJdFQncN4DNdCsY7G1XJ/UgM0IoHlTVCu5YFnnOI7emkEKDUMbTi9n9zk3a0xqhZ58BqWgYOFQoNDptfNeiYj1jVW7ZbQ9FqmYOLQX2H2vkkDHOIBSnByARWpgpkqJaXKtUwN+6ZC2aK8EdG7HCMNUasAUzYb+tUJIDdiMPtpf2/Ycrk9jqBUBWIhw46ztUHbqAOYAfFED8RKidqmBZqMgZpIdUgM25EJ7hsE2NRAvB2DP+cTJAUCwK7WZA2g3uu2u6mxjfbdT4RZFoLO9jVUcIwyWIoCazu43k0mgYxxA7ByARYME7RmGRKiBGC+JLWpgpua3RtimBmIl+21SA3GNoU06JE4OwOIaa9UJ3FK2VcotXnQLdh19rAhgDieBO8YBxK0CskUNxDGG9qmB9qtDbDqfOE4PLOcfYiZEwS414MsYxnE8YCfiimsMuy2WGsfJb3XbpL1iULpgt6Q8CXSMA/BFDcQ2hjapgVilcjapgfiVEn4SoglQAz7q8bVyADZ0jmkMLeeZ4hhhsEx7te18UgpoTiAWHWKRGig3ObloRtmWKyXmTXLQKjXQPj8LtqiBuMbQJu0VryYe7Dzn2HSIxd1w0AcQ8zlbWGM+o9sk0DEOIF4VkD1qoNXM9JlkW00CxzUMNqmBNnW2SQ0UY1B9NqmBOJ3AYNkY+opuYzt6e01RcTuBwbbTa9+W2OqvSQKd4wB8Vw14adWP1yEKnmgvm9RArISofWqg7ZxLPmNt/EW8xHcSaztG3sNTvwd4cnoWKd0k0BEOoFJRVFQ8gwSeygO9UQMed0mWd8M+oh4dY2i3DyCuzjaesw7t5bMKyOLajlXtlToAryirsBvXQ9VAOeyW9GMM26ee7Dm9Ypj3iCHba0WMFcMQV2fbfLi/6Lbd98pqg2WcHIDFqCfOcEdI+wDmBGKX6FmlBiqI0PYpX3apAT+GQa9b0ub4Cx8VMXFzALYrYtrT2ebspdi0l+UGy9hr20Z+K26ux2KDZRLoCAegw8MDVpI3cSiJQLadlyQ8uzR+pYSfPoBJjw1CNp6zDtVnS+dSpRJjF17d3Nh4zjGG/oWyrQ0cbHIOciuEPS42hrLpUH1K1YsE5ho6wgGUNcoSwd5uOM4IWlsvSauzS1uh22KYHL9SwtOIAJsJ0djG0G9NvNX8VgwKqFCuWGuwbPc52xzLHLvCLWcvz5QEOsIBxJlOCXZDxji7cLBXNdDOqVxT5FpsBAt3Se36vW6LeQ+9McEWI4CY5b62Zi+1awxrs5es7objRh921lisjZWlscxxm9+6LW4mk0BHOID44bndqoG4EYAfHt6mzsEuvN158wHt5X4Ets0Tm3SMobXZSzF6XOqzlzw0v1kcNxInAgCP75VF+ikJWHEAInKViDwhIjtE5IYmP18mIv8uIg+IyCMi8g4bcttF/ASd3Xb5eAvVDjWgM6gL7BnDeE7PDjVQqSiUal9nu9RAzJ2h5dlL7Ua3YK/ZUDcCsLfGYkTWlhyATn4LFnAEICJZ4FPA1cDZwJtE5OyGj70HeFQpdR7B0ZEfF5EuU9ntot684WcsQuwIwAI1EGc+PQQH1mQzYq1SIu7uDMypgWJMqg/sUQNhki8bI+oBe9U4cekQXyM/wFbOxc/GSqcTGOxN+LUNGxHAxcAOpdTTSqkCcBtwbcNnFLBEAk5gMXAYKFmQ3RbiHuNmmxqIawxtUANxuUqwaBg0DBKYvyRxqT6wSw1kYpT7Wt1kxI4y7e6GY1ea+VhjlqOe+I13CzQCANYBeyJfD1e/F8UngecD+4CHgPcqpZy5xLiGwXbVQLuJQbBHDcTlKsFeaWI5xkE0oVwwd7hxKYlQtj1HH0dnO4Yhbpc7BIlJm81vsROittZYrE2GJUevMdwRFjAFBDS7E438xauB+4G1wPnAJ0VkadM/JnKdiGwTkW0HDx60cHnxOxbBZtWAarsLGOxRA3HD81C2rx0pmL8kcZt0Atm2qIFKTOrJp9PLWKvEiSPb9hyiOJsMW2OZYw93zC18CmgYWB/5eohgpx/FO4DbVYAdwE7grGZ/TCl1s1Jqq1Jq6+DgoIXLi98JDNUJlZaSg7F2Z2HVgGEvQNx65VC2rQahOAbJls71lzPGc87Zec5xKYluS01oWmvb0uYmLu1lS+dQdrw1Zqe/Jq7Tq+u8cCOAe4DNInJqNbH7RuCOhs/sBn4NQEROAc4EnrYguy3o7JLyGantoo1kx0wC56vGK7xmbbkahiGXlVpYb4K4tFe4kzOtAtKhvXJZMb7XoexYcqvPxXSNxc1vQbDGShaec1zaK4yEy4Y6K6ViJ77zFtc2tB9Zh8/FRvNbEsiZ/gGlVElErge+A2SBW5RSj4jIu6s/vwn4K+BWEXmIgDL6gFJqxFR2u4jLVUIQ4lnrWIxhDLO1BWNnZ9juYeGB7IwdpxfTMIQvibnTi/+ccxk7zzluWWK4Jqw5vZhrzNbajvVOWXrOOo4+m7Hj6OMOd7Tl6JOCsQMAUErdCdzZ8L2bIv/eB7zKhiwdxC2JDD6bsbNg4hqGBWAMdQ2DLafnwzDELX2tG0M7tFe8tW3PGMaNtsDc6cXl4cHm2o433DFrSeekkHYCt0BgGNxzlTXDYLhj0N0ZFq04vXhJ4PCzpgOz4pboBbIzlCx048bNAeQsP+c4m4ysJXqzHGMgWygXzJ2enqO3Gd1qrG0LtiQJdIQDKGkYw5ytHEDMJHB4jV5yABmLOQCtCMAWNRDPGNraGepQfbaec/zo1v2kW1tOT3dt29rQ+VjbSaFDHEBIh8RNiHoIk8NEmSk1oEN7ZW05vbjUgJ3Ed3gQTdzkoA06pBg7KWkp8a1R7mtzbceTa0fnUsxa/EC2vVyPTuJ7ruYAOsMBaBjDrNUcgI9dkk4OIOMlB1CvlPCTA7Cis7ccQPzxF9YSop6S/TqUrq28R+wIIM0B+IcOH24zIZqPUZdunw7xUykRp0nHVt5Dj+qz5+h1jKGt5+wn2a9HexlHtxqNndlMxrj8NJCtl9+yscaSQEc4AB2e1FYSOHYEYD0H4Mfp+agOSXMA7cr2HN1ac3rxKF0vEYAlp5cUOsIBaC0Ym4Yh5ssZ/J4dbjiuMbTDh8dMfNsyhjp8uC9Hb+k5x510G8j24+htRbe6GzobOhfjUn2SRgDeoR8BzN9dklYEYLFb0ovT022KslISqZsDcN8JHJSB2nJ6cRyPnWS/TmOn1SqgGOsrkwlOYEtzAB6hu2D87pLczwKyRg3EOKEKPDe/WaIGdB192dAQ+80BzK8IoKKC6ammsuNE1WAvz5QEOsIB6PKkpo1J4N8Yxu4Q9bkbtmQMvVQBxTQMWcu5nliOPmur4U/P6RVNz7rQpPoAyoYHLcWldMFexJUEOsJInR+cAAAgAElEQVQB6O+S/HUCz+eEaClmh6hX2stzQtTHc/aV38pkBLFAh+hGt9Hf1UXc3gewV4KaBDrCAZR0EqI2qYGYZYlgcSxC3O7nDnR6NnZn8ZP9/pxettrvYePYUR/GULcTGMyjj7jDHcHeYMkk0BkOIOSGYzy4vMXdsF5JpPtOYHsRgF6HqI9OYGs5gLhdsZY6RMsaVF/eksONexg92Gk21OkEtpl/iON4IM0BeId2rbQNPjy2YbBVK60zFsHOQo0/G99fJ7DNcdBxq48COsQ9H24z/xDfGJrnmXQo3bwlneOubaiusXQUhD/oHBVo0zD46ATWrpW2NQtIpxPYR0K0ujszpUPiJoHBDh2i2+Ue/V192ZVY501ASIf46QQGG+9VvB6XQHaaA/AKLZ7UU+egPWpAtynKYwRgawS2BjdsqnZcqg/sUG660W30d7Vle8oB6DZ2gqcIwFJ/TRLoCAcQGmER91VAcQ2DreFRJQ1jaC0HUI63S/KbEA1lG9JPWsbQnHIzMYY2ku6xE6LenJ6dTUbc/FYoe0FHACJylYg8ISI7ROSGFp95uYjcLyKPiMiPbMhtF74eWqWiqCi9emV/ExPdz4kXESuGoawzJthjQtSGzkWDhKiNg1l8JES1GjuzdnSOO94d7NHJScD4SEgRyQKfAq4EhoF7ROQOpdSjkc/0A58GrlJK7RaRVaZy40CnecPGQwubTnx0AuuOwA67Jds98q6pbA3DYMPh6pS+2jynVo8O8dMJHP1dXcR19DAHIgAPiW9bHfZJwEYEcDGwQyn1tFKqANwGXNvwmd8FbldK7QZQSh2wILdt6EUA5lVAWsf1WRoeFffsUrA3iVS3UsJHJ7Ct/IPOiADfxtDG+tZxejZq8cFXZK23mVzIncDrgD2Rr4er34viDGBARP5TRO4Vkbe2+mMicp2IbBORbQcPHrRweQYGycOB3baGR5UqqnYaUbuwsUtSSmkZBqsRQKyci60BZZoRgLWzn+ONRgY740a8RABak25tVQHpUX0LOQJodjcatc0BFwK/Drwa+JCInNHsjymlblZKbVVKbR0cHLRweUFXrQ4lEdIhuihpNCZBsLBtdALrGKTgd/Udn84uPPy8D8NgQ2cIuPjYxtBCpZluJzDYoRn9OPr4jZ1WO4HTHMAUDAPrI18PAfuafGZEKTUGjInIj4HzgF9ZkD8rdMK2sMa4rBSZpj5udujUpYeft/Fy6uzOwGyXpMPDQ7CDtZUcjKN2zQF4oUPs6azTCWzD+cR/ryx0AvvMAWhsJm11mycBGxHAPcBmETlVRLqANwJ3NHzm68BLRCQnIn3AJcBjFmS3Bd0cAJgtGB2uMvy8DcMQ2whbMAxmEYA55ZaLW+5roexWKWWQELVDM2qVvlpxeu6T/X5zADoRgJ2ztpOAcQSglCqJyPXAd4AscItS6hEReXf15zcppR4TkW8DDwIV4DNKqYdNZbeL4Fxe98aw1rGo0SHqo0Ij5JFtRAA6CVErL2dsftY8BxD+ahweHizlAHS63K31mlS03itbFW5x3isbaxviD3eEuZ0DsEEBoZS6E7iz4Xs3NXz9t8Df2pAXF7p9AGBWHVLWmNMSfN5Og5CuzlYiAC3D4L4Sx0ZJpM5BNBBSff5yAL7WmLXqOi/lvrol5Qu3CmjOo1zWMAwWGkdqh7LoGEMPZYk2SiJ1jaGtCEDf6blPfNt09HG73MPfNYFelOmn9NXWwEHtptJ0GJw/GEUA8zYHML+MYS6TseD09HZnYCnx7aPyydNzrlQUSsXrcQlk++kEtpn38OH0kkJHOIBypaK1Cwc7OQAfw6O0dmcWEt/18cR+cgBeaC8NHj6UbT6awK/T80X1Qb1psi25tvIeWiXlczcJ3BEOwKQKyGTHoNMJHHzeUhWQpjE06UEwcXp+5rTYS3xnNZLAXiMAK2s7vmwbtfgZidnlbq30Vc/hFtMcgD/oNm+AaQ7Ab1OUTlUKmNJe+jkAG9MpdSo0wI4x1IsAzHWOc94EREaOW0h8e1nbGvktG2Xd4XBHraF/aQ7AH7TmllsIGU06gX006WStJL71jGHewuylooZhyFt4zjpHUYK/CMDGsaM6J5EFsu0cCanf5W7g6DWGO0KwxuZqGWhnOIBKRbsixlcOwHR4lMkoCDs5AB8RgAHt5akKyHTkh25ZInha2xaiHt2mO8DovTKhdNMcgEfoJQfnfyew9kviow/Adw7AQt5DLwLwU5YItta2e2OoQ/X5dXoLexz0nEep4rcTWIeLt1Ot4C8h6mM0su4JVWDH6cXl4m0Mg9MdTQBmeQ+THhcbU3Z11hcYOj2P0W1S6AgHYFIeaLJD0xnUFcr2MRbBxphgk1lANqgBnUFd4KcTOO+rCsiCziaJb/OT3/THnFhJfHtwekmhIxyASVes0S5JN1FmoW5YyxhacHomncBWIoB51Pxm5dAhnS53i9Gt3iloHhLfVjZ0aQQwL2EWAbjnw61FAB7rw+PvkmxUPulXh3RiJ7ANY6hTjmlaEqnT2GmD6vOZ+E4KHeEAtJo3LNAhZn0APqqA/HYC+40AbNAh7nMAJV9d7tploJ4jACsRfXynp5TZ4VJJoSMcQFnr5KKQM/RTNmY+s0S/CqjoyemZdoj6d3ruHb3R+AtvzW/uT+WyEwFoNr9lzUuNk0JHOACdczyt5AAM+gC8NAhZTHzPvxzA/KT6TEpfbRhDnXJMH8l+ETFeYyY5gOjvzyV0jAOYb53ANspAY5clenV65jkAnbOfa53ABtFHUdPp2cgBlHUKHGx0AhvUxJvSIToD8MDc4dYOePJAuSUFKw5ARK4SkSdEZIeI3DDD5y4SkbKIvN6G3HYRLJh51AlsKQnsw+np7pLsGENPzW/a00DtJL5jRx7iNwdgLFtjbYM55aZL6drIPyQFYwcgIlngU8DVwNnAm0Tk7Baf+58ER0c6xbzsBDbmw/0Yw1LNGOrkPSzkADSqj8LfNZELmiWRFiZjxpWbyQgZsdUH4KEhS4PqC2X7mHSbtdCDkBRsRAAXAzuUUk8rpQrAbcC1TT73R8DXgAMWZMaCUQ7ARgQQtxPYUoeoj4SozyMhyxVF3mO5rw7lVjGlQzSNoWnZrUlTVPT39WTHf59D2T4m3do6gS0J2HAA64A9ka+Hq9+rQUTWAb8NTDkn2BVMkoO+OoF9HdcX/q6JXNDZJdlJiOqG5zbGIsTuBA4pN2XmfHToEFsJUf33yjQCiG+6TPNMJW2qz9zpJQUbDqDZ3Wi8y/8L+IBSqjzrHxO5TkS2ici2gwcPGl+cUsqoK9YPNWDh2DwDY+ijCsheQjQ+HSJiqynKPc2o0+UOIf3kh/aK/r6ubL85gIUTAeQs/I1hYH3k6yFgX8NntgK3VQ+uXglcIyIlpdS/Nf4xpdTNwM0AW7duNb5j4T33slMx2DFYiQC8dkvqnRWrlIp1wHmj7Lg5ADBPuvs0htoRgOGxoyadwNHf15PttwrIx3uVFGw4gHuAzSJyKrAXeCPwu9EPKKVODf8tIrcC32hm/JOAbngeLmwbSSO9eSnuk4M2pkTWdkma3LDOELu6bH3D4DUhakg/6eUAxErDn67TM2n605l0G8r2MQLbxnuVFIwdgFKqJCLXE1T3ZIFblFKPiMi7qz/3wvuH0A7PLdRKh0Y47o7WTgQQ3zCEHzfZqRSNeVJFLqsnW58aME2ImpZEujeGpscUmuS3gt83zAFobBJMI4DQaS2kHICNCACl1J3AnQ3fa2r4lVJvtyGzXcxXrtJEbnh2aVzZImKBJ/VXKWFSHmhG9fkzhvoVMXYSoj76AMoaOT2oNljaiG4XUA5gwXcC62bu7QyP0gzPs2bdkrqVOGCPJ83GjHqszGvXSHxDeGareVesj1OqdHMAOcMcgC4fbqPUuOg7B+DB6SWFhe8AajNLNMcieIgATGXXa/H1qkNMd0kZCapr4soNf18Xuny4aQSgXfpqZRBd/C73QLafxLeVQXS6OQBbie/YJ/yZP+eksOAdQK1JR4MOsZEcjNscBObGUHdqIdgxDDqOx5QnDWkvbTrEymRM96XGurSXcUK0SnvltUuNzdZY3Hk84C8CsOH0ksKCdwC6XGX4Oz4jAN3xsbpcJQS7Gx88vKlhCJupvDg908S3SUWMZumr6RwiXdorayHxrU17GfY+aOe3LMzYSgoL3gHojiYAG40j+iV6oJ9/8JoDMKhKCX9fB7olemCedC9XKogB7TUvIwBdPtxW4luT9vJD9c3dKqAF7wBKBobBWwRgmBA1MYZ5X07PcJdk6vRME6K6yX7Q11m3yx3mQA7AQ+I7n80YRx6QVgHNK+juVMLfmY90iJExNJzJo2+QDJ2eKdVnmAPQpSRAX+fw1/TXtvtOYCsnsPlK9htMuoW0CsgLdDuBg9/JGHcCm1UBaeYADIyhjYSoidPT1Vl3OmX4O74oCdBvNjRb23ZGI8cVXctvGeQ9jHIAFmgv7ZHjaRLYPcwjAIOFWtYf1AUWqoA0KyVMjaHfHID7hKhxBGCosy7lZmMeT9wud3s5gPlU7pvmALxBl6sMf2c+9wHo75JMRhPEP6EqlAt+aC9Tqs+EkgB9nYtGtJd5FZCPtV2pKJTSTfabdj+n5wHMO+jydhB0iBobBg1jmDdMDurO4wF/EYBpJ3C93Fe3CsjDcDLDDlGTCMA02a9zGD1YWNueo1tIO4HnFUx5Ui+jeq1RAz5KIn0lvvWb3+zkAPR24WCD6tOsAvKQ+J7P0a3ucMe0E9gj6sf16SVEzWYBqdidkoFcO8ZQr0HIb0JUO/Ft0O9hIwegO3YD/EQA5k6vYtjlrpv4NoxuvRZ1pA7AOXzmAEx3SaadwNpnxZpWAc3DHIDp6VgmOQDdTmCzLnfzjm8v0a0BvZnLmp2BYN7YmSaBnaNskAMwn5iomxA1pQbMnJ7XKiAPzW/mjr7ipQ/AtMvdtOPbZ8Nf3OGO4HFtpzkAf5jPEYCXHIDhaGT9XVLV6XkYf2Fa7ms6/sLc0bs3huWK7gwij7RXJmM0d8lXfitJLHgHYD4LyD01YG2X5KMk0nQWkLZh8JvsN6n28mMMzc9A0CsysJP49rK2K/pjN8Lfn2uw4gBE5CoReUJEdojIDU1+/mYRebD6390icp4Nue3AuArIa6WEbg7AZBy0WfdzWdcwGE6J1J3IGf6OT8PgqxPY59rW7QQ2cXqmY07KurTXQu4EFpEs8CngauBs4E0icnbDx3YCL1NKnQv8FXCzqdx2UUuUxSzdgrBxRH+XVCybccM+GoRMjWGxomJPxQR7dIiebLPEd6lSQecce9McgNnaNj8fV1cuzNe1rfc+h79iQjMmBRsRwMXADqXU00qpAnAbcG30A0qpu5VSo9Uvfw4MWZDbFgrVnUZ33j1PWihX6NY44dw0ZCyUqjrnNHQ2zAEUShUtuaZjEUx0NjUMgc76z1lXttnaNqsCKpQr2u8UeFrb1XJfpfRl68gNz9peqBTQOmBP5Ovh6vda4Z3At1r9UESuE5FtIrLt4MGDxhc3USwD0KPxguYNQ8aJYoUejZfEtFuypnM+vs6mxnCyWNaT61NnT8/ZlBow0dn0HOSJYlnznTJ8zqVA527NtQ31KaqxZRcrWnLBvO8iKdhwAM1ioqaaisgrCBzAB1r9MaXUzUqprUqprYODg8YXN1EMFrnOS2IaAUwUy14igImSWdRjZgzL9JhEAIaGQd/pGRpDnfVlmOyvrW3NNWa2tvUigJAO0X7OBhs609zaZKms5ejBfA5RUrDhAIaB9ZGvh4B9jR8SkXOBzwDXKqUOWZDbFsIFo0cNmD20yWJF2yCBPmc46TECmCjp6WyaEK07en1qQBcTJc2ox9Tp1Z6z+5Efuk4vpEP017b+czbNP+hGPWDucJOCDQdwD7BZRE4VkS7gjcAd0Q+IyAbgduAtSqlfWZDZNiZKZbpyGe3EpPYZtRVFoaxHDZj2AZjtkgyNYVFvl2TNGGrobBqe61JA5k5P39FnMxmUCqZr6mBS09EHsvWdj5nOpmtM7zmDedltUsiZ/gGlVElErge+A2SBW5RSj4jIu6s/vwn4MLAC+HR1kFJJKbXVVHY7mCxWtCgJMHtok0aUhFl9+ESxQkZ05x/pG0OllD4dYrw7M6P6TKqAtKk+CUsi3VN90QmVXRqbI12qD6prTFtns+gWzDZWJk5vLkYAxg4AQCl1J3Bnw/duivz7XcC7bMiKC+OHpr1YQn7WfaVEqHPcqYWhbN1uyWJZUVG+nJ4J1We2O9Ol+jIZISP6Ts+E6jN3uGbvlcnmBjSpvlrjnWbEpUn1gfm8qaSw4DuBTRaqSXWIaSUO6A+PMl2oxhUaBk7PRLYJ1VfRpENMqD4wyzMZ0V6GCVEjOiSrX4JqQ2eTKFNX5+wCrgKa0zB6aL64SsPhURMmtFc2oz0x0YbT0+0QNaX6AMoa9eEmVB+YDRw0ofpM8kxKKaNNRtYg4jKh+mxQQDpUXyBb/71KEgvfARjthvWHR5mEqlaqFTxEAJMGL2cmI4gBHWJGSejXpptQfYFss02GLtVnknQvlCsoTaovlG1a4KBF9RmW3epSfRDmAOZeEnjhOwCD0i0rdIinJLBuw0qYrNLpljQpSwTIG9Ihui9n3iDiMol6wHyN6Uce5k5PxwgHss101qf69N8rc6ovzQF4gW7DCpgNj/LJVZo1rOjLNmlMArNKCVOqD/RGUZs6AJOyWxOqz6QpyiT5DGZ5DytUn4ZsO1Rf6gCcwz8dotEtWaVDjHbDukbYZDds+pKYUAOGiW/QM4YmVF8oW7/SzFxnI0fvoSTStPoIDJ+ztsNduJ3AcxpmDSv6w6PsUAMeKjSMDENIe5lUSug3RelHHgZ0iAHVF8g2K4k0kQumjt59f40/p+eP6ksSC94BmDasgN7wKNPdsI3koJ5cfZ7UlAIyGU9gQvWZJERNqD4wqwIynU0DhsZwnlJ9PnI9JpVPSaIzHIDPkNHgBTXplvS7S9J/QX1SA1rcsOFzNnb0BkYY9EoiTSkgI0dvWNUHprSXAdWXRgDu4ZsOMXlBfcwsMXN6HpODBlRfWB6o04NggxrQL4n0vLZ9OXpDp6f1nD1SfUliQTsAGw0rYEiHGO2S9HlS/YYVA8NgMJsGbBgGwyogD4lvsyogg7VtcASnFUdv4PS0qT6DPgBjqi+NANzDRsMK6IbJ+g0rYGYMTRpWwvpwHZ3NywNFuxPYRnLQzNFr9j6YJL6tVD7pO3oz2mt+PWdzqs/srO2ksKAdgGnDisnwKJOGFdCnBmw0rICfhKi/5KDfhKhXqs9oc+N+xpYR1Rc+Zw/9HqaHDiWFBe0ATHekecPkoC4lAfoDs0wbVkxm1JvMpoFAZx3DYEr15Yw6gc2pPhPaS9cImxzNaCPS80n1eelxMTx2NCksbAdQMm9YAf1dkq5c0K+UMG1YMY0AdGfThLJ1DIMtqk/P6ZlTfUZdsR4q3CaNKSCTHIC5o0+rgOpY0A7AtFrBNGlk4gB06RAb9cqg6fQMduGhbBOnZ2KEQV9nM6pPL9KzRfXNt6Yo7xVuBs2GC3YWkIhcJSJPiMgOEbmhyc9FRD5R/fmDIrLFhtzZYD6bxqwpSnehBrL1EmXGL6fhLsmI9tLkSW3MpgE/VJ+u07NF9emu7WxGajRSbNlZvbVtTPV5HH+xYCMAEckCnwKuBs4G3iQiZzd87Gpgc/W/64AbTeW2AxuzaUC/PNCIAtIcHmUaqpo5PQsRgIfGJNMOUVOqTzffAiZUn1ni29zRu6f6bHQC6xeUzM0cgI0jIS8GdiilngYQkduAa4FHI5+5Fvi8Cobq/FxE+kVkjVLqWQvyp+HoeBGAHzx+AIDBJd1af6fdkFEpxclCmbJSKAXHJ4o8NHyU89f3a8kNZLeXEC2WK4wXy4Tjin74hJnO7Tq9Rp3HC2W27xplaHmfllwInF5YbjcTSuUKJyM6f//x5wA3Oo8Xy9X5UMG9/8XOw9pyoX2n16jzfzwW6tyjLRdmN4bBOc8VipVK7RD5nz51yFznNtZ2uaIYK5RqOt/15AgAg4t1n3P7Tm+8UK7pjIK7doywcnGXUVVfO46+UtW5omBZb15LVqzrsvA31gF7Il8PA5e08Zl1QCIO4NL/8X3Gqx77dVuGOHP1Eq2/M5NhqFQUN/7oKb567zDDoyen1fjms8L7X32mltxQdivDsOPAcT72rce555nRmrOL4qoXrGbLhgEtuTM5PaUUn71rJ1/+5W72HB6n0FCznxH45Jv12b3A6ZWb/mzXoTE+eufj/HznIY6cnK7zSzav5KWbV2rKbd0hqpTii7/YzRd/toudh8YolKZ/5kvvalzu7WOm6pB9R8b56Lce56c7Rhg9WaBxJuGFGwe46oWr9eTOkvj+yrY93PLTZ3j64Ila0jeKm99yoZbcUHYrI3zg+AQfu/NxfvzkQQ6NTdf5+WuW8poL1mnJred6mut8xwP7+IcfP82TB47XIqwo/t83nKclN5Td6jkfOVngo3c+zg+eOMChE5NUVLCZueeDr9SW1y5sOIBmLrFR03Y+E3xQ5DoCmogNGzZoXdANV59FqaLo68rymvP1FgtEDcP0S/3gvz3El3+5h8tPX8mrX7Cagb587fMiwvnrl/H8NUuNZDczwk8fPMFrP3032YxwzTlrWL20h0Xd2Zrc7lyG11ywzqgSB5onRP/mm4/xmbt2csmpy3nl2acw0NdV+7yIcPaapdqOJ5TdTOd9R8Z53Y13UyhVAp2X9bC4O1eT25UVfus8A51nyHv8r/94kr///pNs2dDPOy7bRH9fV63MVUTYvGoxLz5dz/FA4PSayR05MclrP303xyeKXHPOGtb297Kkp65zLiP8xrlramsuvtzWa/szP3mav/7mY5w7tIy3XbaJgQadT13ZxxVnnaIlN5DdvCnq2ESR19/4Mw4cn+Cac9YwNNDHku4c4WPNZoRfP2cNXQlUuP3TL3bzF//6EM9fs5Tfu2Qjyxd30VXNcYgI6/p7efUL9HVutaEbL5T5nZt+xq5DJ7nmnNWsX97Hst48i7ptmOY2rsvC3xgG1ke+HgL2aXwGAKXUzcDNAFu3btUizd522SadX5uGViHjk88d58u/3MPvv/hUPvybjekOO2jVFfvJH+6gVFF8849fwnoDuqUVWo1F2HP4JP949zO88aL1fPS152gb29lkN3tJbvrRUxwdL/Kt976E01fpRXMzoZVhOHh8kpt+9BS/ce4aPvHGC7TD/9lkN3N6n71rJweOT/D191zOOUPL7Mtt4fSOTRT5+/94kivOWsU/vHWrtoOZUXYLOuQLP9vF7sMn+efrLuWS01ZYl5ttofNEsczHv/sEl562nC+88xLt5PaMsls4+n/ZtocnD5zglrdvNXKqurCh6T3AZhE5VUS6gDcCdzR85g7grdVqoEuBo0nx/zbRig75zE920pvPcv0Vpycqu9EgPXdsgjvu38ebLt6QiPGHeoNQo+xb736GjMB7X7k5EeMPzamBoyeL/PM9e3jtBUOJGH9o3Qn8hZ/volCu8KdXnpGI8YfmB8KMF8p88We7uPqcNYkYf2idA7jtl7s5PlniT688IxHjH8pulFssV/jHn+7kZWcMJmL8IThyFKbrfPv2vRwaK/CnV56ZiPGH5o5eKcU//ORptm4c8GL8wUIEoJQqicj1wHeALHCLUuoREXl39ec3AXcC1wA7gJPAO0zlukC+xY7hJ08e5IqzVrF8UVeCsqfvGH721CFKFcVrt+jTWrOhVSfwT548yGXPW8maZb2JyW7W/XzPM4eZLFUS1blVBPCTJw9y4YYBThtcnJzsJjmA+/cc4fhkidclqHO+Nhah8TmPcNbqJbxwXTKOB8L5R1N1fvzZ44ycKPC6C4cSk9squv3JkwcZGujlok369OVsyGWFSjWJHm4mnjl0kuHRcf7ry5PbSM56XTb+iFLqTgIjH/3eTZF/K+A9NmS5RLNd0v6jE+w7OsE7Nya3WELZjXTI9t2jLOrKctZq/dzCbGhmDI+OF3nywAl+49y1ickNZTcaw+27R8llhPMMKqpmlZud7vQmimUe2XuMd7x4U2JyoXnD3/bdowBG+ZRZ5TYZf1GpKO7ffYTfPD/Z59yswi3U+cIE36tm+S2lFNt3j3LpaSsSi2yjsstKkammRLfvSl7n2bCgO4FN0Wx4lIuFGsiebhju3TXKeev7EwvNofku6f49R1AqWYMUym6m8wvWLjWqtW9HLkw1ho/sO0qhXOGChHVudgbC9l2jnDa4iP6+5CLMZhVuTx44wfHJUuLPudXaPmVpN2uX6ZW1toPwrO2oo997ZJznjk06WNvTacZ7d4+ypDvH5lXJRZizIXUAM6CZYbhv9yjduQxnG1T4tCs7yhmOF8o8vv+4g5dz+jjo+3aPIgLnrU+OFghkT9W5XFE8OHzUiREO5YW4b/cRALZsTC7ygOlOTynFfXuOOHG2MH1tA2zZ4Ebn6Fnb9+0ZZcuGgUR34TA9yqw9ZwdODxrv9xHO39CfWH6pHaQOYAY0q5R4+uAYp65cpF2K1rbsBsOw+/BJyhXFGZo9De2iWaXEzpEx1vX3sqQn2caURmO4/9gE48Wydh9HHLkw1ek9PTLGQF+eVZqNVu2i0ekdGy9xeKzAmackq3Mzp7dzZIyuXIZNKxYlLHvqGpsslRkeHeeMhHWG6Wts58gYAJtPSXYXXousq2tMKcXOkRNOdJ4JqQOYAc2qgIZHxxOrwJkqeyo1MDx6EoD1A8klYaH5TmV4dJz1A8nr3Lg7Gz4c6pys7GZ0iLvnPNUg7Qmf8/Jkn3O46Wx8zkP9vYnvSBvzD88emUApnNzvRsptePQkq5Z0J0oxQnTkeGBLDo0VmChWEn+fZ0PqAGZAo2FQSjE8epJ1/ck/tMYIYHh0HIB1CS+YZlVAw6MnE5cbyM5Mybe41rnRMLh6zo1GGGBdfzlxtFUAAA79SURBVLLGMGwm8/GcG9+rus4u1tj098rN2m6u85CDjdVMSB3ADGikBo6OFxkrlBlysWCyMqVbcu+RcbpzGe05KO0ifDlD2ZOlMgeOTzrROZcVig3RFsDa/uRpGKiPCFBKsXd03M1zzmRQqm4Y9h4JDYMbo1RqcLguDFK2Ic+090gQ9ThZYw0NlnuPuNG59l7VHEBV54QjvdmQOoAZEDaFhEbJpdfON3DD4e4s8SRZwzGYYXju6iWZapBOcsrSbu1Tr9pFtuHlHDlRYLJUcaNzduocouHRkyzqytLfl/wgsHy2PpLhZKHEobGCEyMc9tdE36tsRliTYAVQiFy2vsbKFcW+I24cfb24YqotcRH1zITUAcyA8ByBcDBUzWs7WDA9+WxtBG0ge9zJYgnH3dZ1drdQe/JZShVVe0n2HnGjs4jQk8/UzhUIn7MrnaF+6HhISSTt6APZmdrI9H0OI4/6exXe73FWL+2pbT4SlZ3P1nQ+cHyCYlk5fc7he7V3dJxlvfnECytmQ+oAZkBPV2gM6wsVXDqASq1Ubq+j8DyfzZDPSk1nl+F5b/iSlOrG0BVH2htxuDUaxkF4Xte5KtuhztFNxh6Xa7trujF0wcNDw3N2qHPvNFty0onc2ZA6gBnQlc2QkfpD2390gp58xsmc7t7qSzJZqjBZKnNorOAkRIbAMITjtJ89OgHAageyQ8MwXiijlGL/0QlnOvdGdN5f1XnNUneGYbxQlX1swsm9hqnGcH/tOTt0euEaOzbueG1X6c3wOTvQOYwAou+VK51nQuoAZkBADWRrL+ehsQIrF3e7Cc9zdcNweKwAwMqEE8A12RHDcOhEgf6+fGJDsqbIzdV3SccnSxTKFac6h4Zh5ESBrmyGpb3Jj+QN6ZDxYplSucLoyYJbncO1fWISgBUJzreqy62u7cgac6dzhokGnVcudqHzVAcQ2hLfcDN0eh4jujMcOTHp7KGFEcB4scyhE6EDSH6hQlXngl+di8cDY7xyiRudexp0XrG4y42jj+h8uHroy6DL51xb2wWW9OQSr4cP5UKwuTlZKHGyUHa3xvJZRqrv08iJAhmBgQRHbkTlAkwUylQqisNzxAGkEcAs6Gl4SVwZ4eiOYWSsujtz+JJEd2cudoWhXAgMw6Fq1LNikTvnU496AgfgRG7EMISO3tVz7umKRj3uHH10bdd1dnS/uyJre2yS5Yu6nYxi6I3ofGS8SLminOk8E1IHMAt6u7K1Co1DJybdGaSoMXQcAUwxDGMOI4AphiF0eu53w4fGCu6fc9QYOnO4UTrEoaPvqucARhzSMNAY6bnb0E2N6N1u6GZC6gBmQWgYamGbQ0oCgkasOlfpyihlpuQAXDoeCA1DYAyTbnyryW7Ie7imvSaKFQ5VI72VBgeux5IdKYk85MHRT0yhN93JnizVIz3XUc9EsVJb267eq5mQOoBZEPLhR8eLlCrKKSUBMF6oMHJikp58hr6u5PlZqFeHFEoVjo4XnVJPMHVnOOBwVzpeDKqPDp6YdJpvgWBnePB41QE4XGPR3bBr2mu8UH/OTulNjzpPjXrmeQQgIstF5Hsi8mT1/9NmqorIehH5oYg8JiKPiMh7TWS6Rnc+E4RtY+4pCahTA66qj6AeJvuoPoK6zq6qjyCoQJoolDkxWaJQqjh7zt2RiphDYwXyWXFSfQTQnctOqT5ylnuoPedKJNfjkAKqOnqXEUA+K2QkpHTdVVzNBtO36wbg+0qpzcD3q183ogT8mVLq+cClwHtEJJmT1BNAuBsecRyqTk0Cu3s5oU57jXjg4SGIeg6NTTp9QcIIoM7DO456qoZhxSJ3jj5MfI+eLKKUO0qiO1LuO3JiksXdbqqPINC5ooKx22OFsrO1LSK19+rQWFB9lOSBP+3C1AFcC3yu+u/PAa9p/IBS6lml1Pbqv48DjwHJHXZqGeFL4jpsq3HDhTIjxydZ6dAY9kzT2X3UM3LcbZlco9NzxcNPcfQOKQkIdC6WFc8dCxqiXN3vTCYYvRFurFxy4eH9Dsduu6LboL7JGDkRVB8lebJfuzB1AKcopZ6FwNADq2b6sIhsAi4AfmEo1xlqXttxuVqtEaxKPzk3hgX3Cbro6A2X1UdQH70x4jg8D0dvhNUhrp8z1GcfOY24au/VpPPoFupjXVwVdUB1jRXcO72ZMCvZKCL/Aaxu8qMPxhEkIouBrwHvU0odm+Fz1wHXAWzYsCGOiETQUzOGk86aRmB6I5jrneFEqeI8QRcdveFc5+r93nvE7W4Y6hVIIycKPM/h+bBh1VVoDJ3TjNVNxsYV7mbih6M3wnlPrqg+qFdduewzmQ2zOgCl1Ctb/UxEnhORNUqpZ0VkDXCgxefyBMb/S0qp22eRdzNwM8DWrVvVTJ91gXBnePBEgeWLupyFbeGIgP1HJ4LqI6cGKUO5onj26ATduQyLHFUfhaM3jo0XOTpedGuEqxHXnuopZMtdUm5VY+iyGQvqOocOwFXJLdSTsSMnJrlwU7Ln8U6RW32vwufs0hDXn3OBCxI+d7ldmFJAdwBvq/77bcDXGz8gQUbrs8BjSqm/M5TnHL35LIVyhYPHJ5zuFjIZoTuXqYeqHnjS4dFxp9VHENzv2u7MQwQwXB3Tm/SZz1NkV8cTTJYqTp9zXeeT5DLuqo8gWGMnC8H4C9f5LYhQQB7yTC4bSmeD6Sr/GHCliDwJXFn9GhFZKyJ3Vj/zYuAtwBUicn/1v2sM5TpDGDIOj447D9t68tkaP+t0oUYMg2uuMtDZfXjeE+HDXT/n3shzdk1JQH1tO3X0XVn2HRlHKffUEwTP2WX1EQTOZ3Ss6LT6aDYYuXyl1CHg15p8fx9wTfXfdwH+092aiL4kZ5yyxLnsvaMedsNVnfeOjnPRqcudyYXAMNQoCYcJuqjOz1+71JlcCAzD0wdOAH6e8/DouFMePpT9xP7jgPtdOATP2b2jz9SiW5d020xIO4FnQbhDODFZcr9gurIcnywBfl6S45Ml5xFAbz7LiarOTnfDXT51znh5ziEdEqxttwapJ/qcPdBewXN2q3OvJ51nQuoAZkFvJAHqesGEzkccVh9B3TCA+4FVvfmobPe7YXDreBpl+3D0gFMeHhrfK1/P2Z/Oc2EQHKQOYFb05PwsVKgfnLG8z131EUzV2fVLEo5G6M5lWNztNikZwpejB/fVRyFcNb7VZEeS7C7vd7i+wL0R7vZoS1ohdQCzYIrX9rQzdB6qRnQedGwYojq7TEr2eIo8oK6zj+qjEL52w7mMsNThwehRnV0dvFOT7dGWtELqAGZB1DC4NoahbF9GGNwnq8KXxPWO1KfTCyk3r8/Zo6N3cSBLo1zwp3NfV3bKevOJ9EjIWfCCtUt564s2snHFIl64bplT2W950UaGBnr5nQvXO5X7vMFFvOPFmzhlaQ9bN7mtAnrjRRtY2pPnNResdSp3zdIe/stLT2Npb56Xbh50Kvt1W4bICFxzzhqncpf25vijK04nmxFe9YJmzf7J4TfPW8uJyZJzublshve/6gwmSxV+8zy3a+zqF65m/7EJXnHmjBNznEKU8t5s2xJbt25V27Zt830ZKVKkSDFvICL3KqW2tvPZlAJKkSJFig5F6gBSpEiRokOROoAUKVKk6FCkDiBFihQpOhSpA0iRIkWKDkXqAFKkSJGiQ5E6gBQpUqToUKQOIEWKFCk6FHO6EUxEDgK7NH99JTBi8XJcIL3m5DHfrhfSa3aFhXLNG5VSbbWzz2kHYAIR2dZuN9xcQXrNyWO+XS+k1+wKnXjNKQWUIkWKFB2K1AGkSJEiRYdiITuAm31fgAbSa04e8+16Ib1mV+i4a16wOYAUKVKkSDEzFnIEkCJFihQpZsCCcwAicpWIPCEiO0TkBt/X0woi8oyIPCQi94vItur3lovI90Tkyer/Bzxf4y0ickBEHo58r+U1isj/Wb3vT4jIq+fQNX9ERPZW7/X9InLNHLvm9SLyQxF5TEQeEZH3Vr8/J+/1DNc7Z++ziPSIyC9F5IHqNf+36vfn5D2e5Zrt3Wel1IL5D8gCTwGnAV3AA8DZvq+rxbU+A6xs+N7/DdxQ/fcNwP/0fI0vBbYAD892jcDZ1fvdDZxafQ7ZOXLNHwHe3+Szc+Wa1wBbqv9eAvyqem1z8l7PcL1z9j4DAiyu/jsP/AK4dK7e41mu2dp9XmgRwMXADqXU00qpAnAbcK3na4qDa4HPVf/9OeA1Hq8FpdSPgcMN3251jdcCtymlJpVSO4EdBM/DKVpccyvMlWt+Vim1vfrv48BjwDrm6L2e4Xpbwft9VgFOVL/MV/9TzNF7DDNecyvEvuaF5gDWAXsiXw8z88L0CQV8V0TuFZHrqt87RSn1LAQvGTB3Dg+to9U1zvV7f72IPFiliMIwf85ds4hsAi4g2O3N+XvdcL0wh++ziGRF5H7gAPA9pdScv8ctrhks3eeF5gCkyffmapnTi5VSW4CrgfeIyEt9X5Ah5vK9vxF4HnA+8Czw8er359Q1i8hi4GvA+5RSx2b6aJPvOb/uJtc7p++zUqqslDofGAIuFpEXzvDxuXzN1u7zQnMAw8D6yNdDwD5P1zIjlFL7qv8/APwrQaj2nIisAaj+/4C/K2yJVtc4Z++9Uuq56otUAf6Belg8Z65ZRPIExvRLSqnbq9+es/e62fXOh/sMoJQ6AvwncBVz+B5HEb1mm/d5oTmAe4DNInKqiHQBbwTu8HxN0yAii0RkSfhv4FXAwwTX+rbqx94GfN3PFc6IVtd4B/BGEekWkVOBzcAvPVzfNIQveBW/TXCvYY5cs4gI8FngMaXU30V+NCfvdavrncv3WUQGRaS/+u9e4JXA48zRezzTNVu9zy6z2i7+A64hqEp4Cvig7+tpcY2nEWTrHwAeCa8TWAF8H3iy+v/lnq/zywQhZpFgd/HOma4R+GD1vj8BXD2HrvkLwEPAg9WXZM0cu+bLCUL1B4H7q/9dM1fv9QzXO2fvM3AucF/12h4GPlz9/py8x7Ncs7X7nHYCp0iRIkWHYqFRQClSpEiRok2kDiBFihQpOhSpA0iRIkWKDkXqAFKkSJGiQ5E6gBQpUqToUKQOIEWKFCk6FKkDSJEiRYoOReoAUqRIkaJD8b8BY10uXWOCWXAAAAAASUVORK5CYII=\n", 97 | "text/plain": [ 98 | "
" 99 | ] 100 | }, 101 | "metadata": { 102 | "needs_background": "light" 103 | }, 104 | "output_type": "display_data" 105 | } 106 | ], 107 | "source": [ 108 | "t_r = 2\n", 109 | "n_scans = 340\n", 110 | "\n", 111 | "onsets_dir = '/home/finc/Dropbox/Projects/LearningBrain/github/LearningBrain_networks/support/onsets_dualnback.csv'\n", 112 | "events = pd.read_csv(onsets_dir)\n", 113 | "frame_times = np.arange(n_scans) * t_r\n", 114 | "\n", 115 | "# Step 1\n", 116 | "box = make_first_level_design_matrix(frame_times, events, hrf_model = None)\n", 117 | "box = box.reset_index()\n", 118 | "\n", 119 | "# Step 2\n", 120 | "box_hrf = make_first_level_design_matrix(frame_times, events, hrf_model = 'glover')\n", 121 | "box_hrf = box_hrf.reset_index()\n", 122 | "\n", 123 | "plt.plot(box_hrf['1-back'])" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "Step 2: Loading data\n", 131 | "----------------------------------------------------\n" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 4, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [ 140 | "top_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/01-extracted_timeseries/'\n", 141 | "out_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/02-correlation_matrices/'\n", 142 | "\n", 143 | "dual_power = np.load(f'{top_dir}dualnback/LB_dualnback_timeseries_power_denoised_acompcor_no_smooth.npy')\n", 144 | "dual_schaefer = np.load(f'{top_dir}dualnback/LB_dualnback_timeseries_schaefer_denoised_acompcor_no_smooth.npy')\n", 145 | "\n", 146 | "rest_power = np.load(f'{top_dir}rest/LB_rest_timeseries_power_denoised_acompcor_no_smooth.npy')\n", 147 | "rest_schaefer = np.load(f'{top_dir}rest/LB_rest_timeseries_schaefer_denoised_acompcor_no_smooth.npy')\n", 148 | "\n", 149 | "dual = np.asarray([\n", 150 | " [dual_power, 'dual_power'], \n", 151 | " [dual_schaefer, 'dual_schaefer']])\n", 152 | "rest = np.asarray([\n", 153 | " [rest_power, 'rest_power'], \n", 154 | " [rest_schaefer, 'rest_chaefer']])" 155 | ] 156 | }, 157 | { 158 | "cell_type": "markdown", 159 | "metadata": {}, 160 | "source": [ 161 | "Step 3: Calculating correlation matrices - resting-state\n", 162 | "-------------------------" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 7, 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "name": "stderr", 172 | "output_type": "stream", 173 | "text": [ 174 | "/home/finc/anaconda/lib/python3.6/site-packages/nilearn/connectome/connectivity_matrices.py:359: RuntimeWarning: divide by zero encountered in true_divide\n", 175 | " diagonal = np.atleast_2d(1. / np.sqrt(np.diag(covariance)))\n", 176 | "/home/finc/anaconda/lib/python3.6/site-packages/nilearn/connectome/connectivity_matrices.py:360: RuntimeWarning: invalid value encountered in multiply\n", 177 | " correlation = covariance * diagonal * diagonal.T\n", 178 | "/home/finc/anaconda/lib/python3.6/site-packages/nilearn/connectome/connectivity_matrices.py:359: RuntimeWarning: divide by zero encountered in true_divide\n", 179 | " diagonal = np.atleast_2d(1. / np.sqrt(np.diag(covariance)))\n", 180 | "/home/finc/anaconda/lib/python3.6/site-packages/nilearn/connectome/connectivity_matrices.py:360: RuntimeWarning: invalid value encountered in multiply\n", 181 | " correlation = covariance * diagonal * diagonal.T\n" 182 | ] 183 | }, 184 | { 185 | "name": "stdout", 186 | "output_type": "stream", 187 | "text": [ 188 | "(46, 4, 300, 300)\n" 189 | ] 190 | } 191 | ], 192 | "source": [ 193 | "from sklearn.covariance import EmpiricalCovariance\n", 194 | "\n", 195 | "for p in range(rest.shape[0]):\n", 196 | "\n", 197 | " data = rest[p,0]\n", 198 | " sub_n = len(data[:, 0, 0, 0])\n", 199 | " ses_n = len(data[0, :, 0, 0])\n", 200 | " rois_n = len(data[0, 0, 0, :])\n", 201 | "\n", 202 | " correlation_matrices = np.zeros((sub_n, \n", 203 | " ses_n, \n", 204 | " #len(cond), \n", 205 | " rois_n, rois_n))\n", 206 | "\n", 207 | " for sub in range(sub_n):\n", 208 | " for ses in range(ses_n): \n", 209 | " correlation_measure = ConnectivityMeasure(cov_estimator=EmpiricalCovariance(store_precision=True, assume_centered=False), kind = 'correlation', discard_diagonal=True)\n", 210 | "\n", 211 | " timeseries_dual = data[sub, ses, 0:180, : ] #rect_box_hrf > 0, :]\n", 212 | " #timeseries_dual = (timeseries_dual.T * rect_nnz).T\n", 213 | "\n", 214 | " fc = correlation_measure.fit_transform([timeseries_dual])[0]\n", 215 | " np.fill_diagonal(fc, 0)\n", 216 | "\n", 217 | " correlation_matrices[sub, ses, :, :] = np.arctanh(fc)\n", 218 | "\n", 219 | " print(correlation_matrices.shape)\n", 220 | " np.save(f'{out_dir}static/rest/LB_{rest[p,1]}_static_correlation_matrices.npy', correlation_matrices)\n" 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": {}, 226 | "source": [ 227 | "Step 4: Calculating correlation matrices - dual n-back\n", 228 | "-------------------------" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": 8, 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "name": "stdout", 238 | "output_type": "stream", 239 | "text": [ 240 | "Calculating correlations: sub 0\n", 241 | "Calculating correlations: sub 1\n", 242 | "Calculating correlations: sub 2\n", 243 | "Calculating correlations: sub 3\n", 244 | "Calculating correlations: sub 4\n", 245 | "Calculating correlations: sub 5\n", 246 | "Calculating correlations: sub 6\n", 247 | "Calculating correlations: sub 7\n", 248 | "Calculating correlations: sub 8\n", 249 | "Calculating correlations: sub 9\n", 250 | "Calculating correlations: sub 10\n", 251 | "Calculating correlations: sub 11\n", 252 | "Calculating correlations: sub 12\n", 253 | "Calculating correlations: sub 13\n", 254 | "Calculating correlations: sub 14\n", 255 | "Calculating correlations: sub 15\n", 256 | "Calculating correlations: sub 16\n", 257 | "Calculating correlations: sub 17\n", 258 | "Calculating correlations: sub 18\n", 259 | "Calculating correlations: sub 19\n", 260 | "Calculating correlations: sub 20\n", 261 | "Calculating correlations: sub 21\n", 262 | "Calculating correlations: sub 22\n", 263 | "Calculating correlations: sub 23\n", 264 | "Calculating correlations: sub 24\n", 265 | "Calculating correlations: sub 25\n", 266 | "Calculating correlations: sub 26\n", 267 | "Calculating correlations: sub 27\n", 268 | "Calculating correlations: sub 28\n", 269 | "Calculating correlations: sub 29\n", 270 | "Calculating correlations: sub 30\n", 271 | "Calculating correlations: sub 31\n", 272 | "Calculating correlations: sub 32\n", 273 | "Calculating correlations: sub 33\n", 274 | "Calculating correlations: sub 34\n", 275 | "Calculating correlations: sub 35\n", 276 | "Calculating correlations: sub 36\n", 277 | "Calculating correlations: sub 37\n", 278 | "Calculating correlations: sub 38\n", 279 | "Calculating correlations: sub 39\n", 280 | "Calculating correlations: sub 40\n", 281 | "Calculating correlations: sub 41\n", 282 | "Calculating correlations: sub 42\n", 283 | "Calculating correlations: sub 43\n", 284 | "Calculating correlations: sub 44\n", 285 | "Calculating correlations: sub 45\n", 286 | "(46, 4, 2, 300, 300)\n" 287 | ] 288 | } 289 | ], 290 | "source": [ 291 | "for p in range(rest.shape[0]):\n", 292 | " data = dual[p,0]\n", 293 | " \n", 294 | " sub_n = len(data[:, 0, 0, 0])\n", 295 | " ses_n = len(data[0, :, 0, 0])\n", 296 | " cond = ['1-back', '2-back']\n", 297 | " rois_n = len(data[0, 0, 0, :])\n", 298 | " A = np.zeros((rois_n, rois_n))\n", 299 | " correlation_matrices_wei = np.zeros((sub_n, ses_n, len(cond), rois_n, rois_n))\n", 300 | "\n", 301 | "\n", 302 | " for sub in range(sub_n):\n", 303 | " print(f'Calculating correlations: sub {sub}')\n", 304 | " for ses in range(ses_n): \n", 305 | " for con in range(len(cond)):\n", 306 | " #--- zeroing negative values\n", 307 | " rect_box_hrf = np.array([0 if elem < 0 else elem for elem in box_hrf[cond[con]]])\n", 308 | " #--- concatenating nonzeros blocs\n", 309 | " rect_nnz = rect_box_hrf[np.nonzero(rect_box_hrf)]\n", 310 | " #--- filtering \n", 311 | " timeseries_dual = data[sub, ses, rect_box_hrf > 0, :]\n", 312 | " #--- calculating weighted correlation coefficient\n", 313 | " for i in range(rois_n):\n", 314 | " for j in range(i):\n", 315 | " if i == j:\n", 316 | " continue\n", 317 | " else:\n", 318 | " A[i, j] = stats.corr_wei(timeseries_dual[:, i], timeseries_dual[:, j], rect_nnz)\n", 319 | "\n", 320 | " fc = A + A.T\n", 321 | " correlation_matrices_wei[sub, ses, con, :, :] = np.arctanh(fc)\n", 322 | " print(correlation_matrices_wei.shape)\n", 323 | " np.save(f'{out_dir}static/dualnback/LB_{dual[p,1]}_static_correlation_matrices.npy', correlation_matrices_wei)" 324 | ] 325 | } 326 | ], 327 | "metadata": { 328 | "kernelspec": { 329 | "display_name": "Python 3", 330 | "language": "python", 331 | "name": "python3" 332 | }, 333 | "language_info": { 334 | "codemirror_mode": { 335 | "name": "ipython", 336 | "version": 3 337 | }, 338 | "file_extension": ".py", 339 | "mimetype": "text/x-python", 340 | "name": "python", 341 | "nbconvert_exporter": "python", 342 | "pygments_lexer": "ipython3", 343 | "version": "3.7.3" 344 | } 345 | }, 346 | "nbformat": 4, 347 | "nbformat_minor": 2 348 | } 349 | -------------------------------------------------------------------------------- /02-fmri_data_preparation/04-dynamic_FC_estimation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# **Working memory training**: Dynamic connectivity estimation\n", 8 | "\n", 9 | "**Last edited:** 09-11-2018\n" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "Step 0: Loading libraries\n", 17 | "--------------------------------" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 4, 23 | "metadata": {}, 24 | "outputs": [ 25 | { 26 | "name": "stderr", 27 | "output_type": "stream", 28 | "text": [ 29 | "/home/finc/anaconda3/lib/python3.7/site-packages/matplotlib/__init__.py:855: MatplotlibDeprecationWarning: \n", 30 | "examples.directory is deprecated; in the future, examples will be found relative to the 'datapath' directory.\n", 31 | " \"found relative to the 'datapath' directory.\".format(key))\n", 32 | "/home/finc/anaconda3/lib/python3.7/site-packages/matplotlib/__init__.py:846: MatplotlibDeprecationWarning: \n", 33 | "The text.latex.unicode rcparam was deprecated in Matplotlib 2.2 and will be removed in 3.1.\n", 34 | " \"2.2\", name=key, obj_type=\"rcparam\", addendum=addendum)\n" 35 | ] 36 | } 37 | ], 38 | "source": [ 39 | "%matplotlib inline\n", 40 | "\n", 41 | "import sys\n", 42 | "sys.path.append(\"..\")\n", 43 | "import os\n", 44 | "\n", 45 | "import pandas as pd\n", 46 | "import numpy as np \n", 47 | "import matplotlib.pyplot as plt \n", 48 | "\n", 49 | "from nilearn import datasets, plotting, input_data, signal # for fetching atlas\n", 50 | "\n", 51 | "from nilearn.input_data import NiftiLabelsMasker\n", 52 | "from nilearn.connectome import ConnectivityMeasure\n", 53 | "from nistats.reporting import plot_design_matrix\n", 54 | "from nistats.design_matrix import make_first_level_design_matrix\n", 55 | "from sklearn.covariance import EmpiricalCovariance\n", 56 | "\n", 57 | "import seaborn as sns\n", 58 | "sns.reset_orig()\n", 59 | "\n", 60 | "from fctools import denoise, stats" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "Step 1: Loading data\n", 68 | "----------------------------------------------------\n" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 7, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "top_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/01-extracted_timeseries/'\n", 78 | "out_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/02-correlation_matrices/'\n", 79 | "\n", 80 | "dual_power = np.load(f'{top_dir}dualnback/LB_dualnback_timeseries_power_denoised_acompcor_no_smooth.npy')\n", 81 | "dual_schaefer = np.load(f'{top_dir}dualnback/LB_dualnback_timeseries_schaefer_denoised_acompcor_no_smooth.npy')\n", 82 | "\n", 83 | "dual = np.asarray([[dual_power, 'dual_power'], [dual_schaefer, 'dual_schaefer']])" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "Step 2: Design specification\n", 91 | "----------------------------------------------------\n" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 8, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "data": { 101 | "text/plain": [ 102 | "[]" 103 | ] 104 | }, 105 | "execution_count": 8, 106 | "metadata": {}, 107 | "output_type": "execute_result" 108 | }, 109 | { 110 | "data": { 111 | "image/png": "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\n", 112 | "text/plain": [ 113 | "
" 114 | ] 115 | }, 116 | "metadata": { 117 | "needs_background": "light" 118 | }, 119 | "output_type": "display_data" 120 | } 121 | ], 122 | "source": [ 123 | "t_r = 2\n", 124 | "n_scans = 340\n", 125 | "\n", 126 | "onsets_dir = '../support/onsets_dualnback.csv'\n", 127 | "events = pd.read_csv(onsets_dir)\n", 128 | "frame_times = np.arange(n_scans) * t_r\n", 129 | "\n", 130 | "events = events[(events.trial_type == '1-back') | (events.trial_type == '2-back')].reset_index()\n", 131 | "events['trial_type'] = np.arange(20)\n", 132 | "\n", 133 | "# Step 1\n", 134 | "box = make_first_level_design_matrix(frame_times, events, hrf_model = None)\n", 135 | "box = box.reset_index()\n", 136 | "\n", 137 | "# Step 2\n", 138 | "box_hrf = make_first_level_design_matrix(frame_times, events, hrf_model = 'glover')\n", 139 | "box_hrf = box_hrf.reset_index()\n", 140 | "plt.plot(box_hrf.iloc[:,6])\n", 141 | "plt.plot(box.iloc[:,6])" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "Step 3: Weighted correlation - dynamic connectivity\n", 149 | "---------------------------" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 9, 155 | "metadata": {}, 156 | "outputs": [ 157 | { 158 | "name": "stdout", 159 | "output_type": "stream", 160 | "text": [ 161 | "Calculating correlations: sub 0\n" 162 | ] 163 | }, 164 | { 165 | "ename": "KeyboardInterrupt", 166 | "evalue": "", 167 | "output_type": "error", 168 | "traceback": [ 169 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 170 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", 171 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 30\u001b[0;31m \u001b[0mA\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstats\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcorr_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeseries_dual\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeseries_dual\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrect_nnz\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 31\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[0mfc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mA\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mA\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mT\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 172 | "\u001b[0;32m~/Dropbox/Projects/LearningBrain/github/WM_training_modularity/fctools/stats.py\u001b[0m in \u001b[0;36mcorr_wei\u001b[0;34m(x, y, w)\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcorr_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;34m\"\"\"Weighted Correlation\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mcov_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msqrt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcov_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mcov_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mbootstrap_replicate_1d\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 173 | "\u001b[0;32m~/Dropbox/Projects/LearningBrain/github/WM_training_modularity/fctools/stats.py\u001b[0m in \u001b[0;36mcov_wei\u001b[0;34m(x, y, w)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcov_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\"\"\"Weighted Covariance\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mw\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mm_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mm_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 12\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcorr_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 174 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: " 175 | ] 176 | } 177 | ], 178 | "source": [ 179 | "for p in range(1,2): #range(rest.shape[0]):\n", 180 | " data = dual[p,0]\n", 181 | "\n", 182 | " n_sub = len(data[:, 0, 0, 0])\n", 183 | " n_ses = len(data[0, :, 0, 0])\n", 184 | " cond = np.arange(0,20)\n", 185 | " n_roi = len(data[0, 0, 0, :])\n", 186 | " A = np.zeros((n_roi, n_roi))\n", 187 | " correlation_matrices_dyn_wei = np.zeros((n_sub, n_ses, len(cond), n_roi, n_roi))\n", 188 | "\n", 189 | "\n", 190 | " for sub in range(n_sub):\n", 191 | " print(f'Calculating correlations: sub {sub}')\n", 192 | " for ses in range(n_ses): \n", 193 | " #correlation_measure = ConnectivityMeasure(cov_estimator=EmpiricalCovariance(store_precision=True, assume_centered=False), kind = 'correlation', discard_diagonal=True)\n", 194 | "\n", 195 | " for con in range(len(cond)):\n", 196 | " # Zeroing negative values\n", 197 | " rect_box_hrf = np.array([0 if elem < 0 else elem for elem in box_hrf[cond[con]]])\n", 198 | " # Concatenating nonzeros blocs\n", 199 | " rect_nnz = rect_box_hrf[np.nonzero(rect_box_hrf)]\n", 200 | " # Filtering \n", 201 | " timeseries_dual = data[sub, ses, rect_box_hrf > 0, :]\n", 202 | " # Calculating weighted correlation coefficient\n", 203 | " for i in range(n_roi):\n", 204 | " for j in range(i):\n", 205 | " if i == j:\n", 206 | " continue\n", 207 | " else:\n", 208 | " A[i, j] = stats.corr_wei(timeseries_dual[:, i], timeseries_dual[:, j], rect_nnz)\n", 209 | "\n", 210 | " fc = A + A.T\n", 211 | " correlation_matrices_dyn_wei[sub, ses, con, :, :] = np.arctanh(fc)\n", 212 | "\n", 213 | " print(correlation_matrices_dyn_wei.shape)\n", 214 | "\n", 215 | " np.save(f'{out_dir}dynamic/LB_{dual[p,1]}_dynamic_correlation_matrices.npy', correlation_matrices_dyn_wei)\n", 216 | " sio.savemat(f'{out_dir}dynamic/LB_{dual[p,1]}_dynamic_correlation_matrices.mat', {'correlation_matrices_dyn_wei': correlation_matrices_dyn_wei})\n", 217 | " " 218 | ] 219 | } 220 | ], 221 | "metadata": { 222 | "kernelspec": { 223 | "display_name": "Python 3", 224 | "language": "python", 225 | "name": "python3" 226 | }, 227 | "language_info": { 228 | "codemirror_mode": { 229 | "name": "ipython", 230 | "version": 3 231 | }, 232 | "file_extension": ".py", 233 | "mimetype": "text/x-python", 234 | "name": "python", 235 | "nbconvert_exporter": "python", 236 | "pygments_lexer": "ipython3", 237 | "version": "3.7.3" 238 | } 239 | }, 240 | "nbformat": 4, 241 | "nbformat_minor": 2 242 | } 243 | -------------------------------------------------------------------------------- /03-static_FC_analyses/01-static_modularity_calculation.m: -------------------------------------------------------------------------------- 1 | %---------------------------------------------------- 2 | % Working memory training: Static normalized modularity calculation 3 | 4 | % Karolina Finc | Centre for Modern Interdisciplinary Technologies, Nicolaus Copernicus University in Toruń, Poland 5 | % Last edited: 09-01-2019 6 | %---------------------------------------------------- 7 | 8 | % Mere the input is 5D matrix where: 9 | % 1st dim --> subject 10 | % 2nd dim --> session 11 | % 3rd dim --> condition 12 | % 4th and 5th dim --> correlation matrix 13 | 14 | %% Loading data 15 | 16 | M = load('WM_all_static_power_correlation_matrices.mat'); 17 | 18 | M = M.all_conditions_new_power; 19 | M = squeeze(M); 20 | 21 | %% Params 22 | n_sub = size(M,1); 23 | n_ses = size(M,2); 24 | n_con = size(M,3); 25 | n_rep = 100; 26 | n_null = 100; 27 | n_rew = 1; 28 | 29 | q = zeros(n_sub, n_ses, n_con); 30 | q_null_mean = zeros(n_sub, n_ses, n_con); 31 | 32 | %% Static modularity calculation 33 | for sub = 1: n_sub 34 | sub 35 | for ses = 1: n_ses 36 | for con = 1: n_con 37 | Qb = 0; 38 | for rep = 1: n_rep 39 | A = squeeze(M(sub,ses,con,:,:)).* squeeze(M(sub, ses, con, :, :) > 0); 40 | [~, Qt] = community_louvain(A, 1, []); 41 | if Qt > Qb 42 | Qb = Qt; 43 | end 44 | q(sub, ses, con) = Qb; 45 | end 46 | end 47 | end 48 | 49 | end 50 | save('mean_power_static_modularity.mat', 'q'); 51 | 52 | %% Randomized modularity calculation 53 | for sub = 1: n_sub 54 | q_null = zeros(1, n_null); 55 | 56 | sub 57 | for ses = 1: n_ses 58 | for con = 1: n_con 59 | A = squeeze(M(sub,ses,con,:,:)).* squeeze(M(sub, ses, con, :, :) > 0); 60 | if sum(isnan(A(:))) > 0 61 | q_null = 0; 62 | else 63 | for null = 1 : n_null 64 | B = randmio_und(A, n_rew); 65 | Qb = 0; 66 | for rep = 1: n_rep 67 | [~, Qt] = community_louvain(B, 1, []); 68 | if Qt > Qb 69 | Qb = Qt; 70 | end 71 | end 72 | q_null(1, null) = Qb; 73 | end 74 | end 75 | q_null_mean(sub, ses, con) = mean(q_null); 76 | 77 | end 78 | end 79 | end 80 | 81 | %% Normalized modularity calculation 82 | q_norm = q_mean ./ q_null_mean; 83 | save('mean_power_normalized_modularity.mat', 'q_norm'); -------------------------------------------------------------------------------- /03-static_FC_analyses/02-tidying_normalized_modularity.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# **Working memory training**: Preparation of normalized modularity\n", 8 | "\n", 9 | "Turning MATLAB array into tidy .csv table for further statistical analyses.\n", 10 | "\n", 11 | "**Last edited:** 06-01-2018" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "Step 0: Loading libraries\n", 19 | "-----------------------" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 4, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "import numpy as np\n", 29 | "import pandas as pd" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "Step 1: Preparing data\n", 37 | "-----------------------" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 6, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "# Selecting subjects which finished the study\n", 47 | "groups = pd.read_csv('../data/behavioral/group_assignment.csv')\n", 48 | "\n", 49 | "trained = (groups.group == 'Experimental') | (groups.group == 'Control')\n", 50 | "trained_subs = groups[trained].reset_index()\n", 51 | "subs = trained_subs['sub'].values\n", 52 | "\n", 53 | "# Creating vectors to filter by group\n", 54 | "experimental = (trained_subs == 'Experimental')\n", 55 | "control = (trained_subs == 'Control')\n", 56 | "exp_vector = experimental['group'].values\n", 57 | "con_vector = control['group'].values\n", 58 | "\n", 59 | "# Loading normalized modularity values\n", 60 | "mat = scipy.io.loadmat('mean_power_normalized_modularity.mat')\n", 61 | "Q = mat['q_norm']" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "Step 2: Creating tidy dataframe\n", 69 | "-----------------------" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 9, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "sess = ['Naive', 'Early', 'Middle', 'Late']\n", 79 | "cond = ['Rest', '1-back', '2-back']\n", 80 | "g = trained_subs['group'].values\n", 81 | "\n", 82 | "Q_results = pd.DataFrame()#pd.DataFrame(columns=['sub', 'group', 'ses', 'cond', 'Q'])\n", 83 | "for i, sub in enumerate(subs):\n", 84 | " for j, ses in enumerate(sess):\n", 85 | " for k, con in enumerate(cond):\n", 86 | " val = Q[i, j, k]\n", 87 | " result = pd.DataFrame({'Subject': sub, \n", 88 | " 'Group': trained_subs['group'].values[i], \n", 89 | " 'Session': ses, \n", 90 | " 'Condition': con, \n", 91 | " 'Q_norm': val},\n", 92 | " index=[0])\n", 93 | " Q_results = pd.concat([Q_results, result], axis = 0)\n", 94 | "\n", 95 | "Q_results.to_csv('../data/neuroimaging/03-modularity/static/Q_normalized_power_tidy.csv', index=False)\n", 96 | "Q_results" 97 | ] 98 | } 99 | ], 100 | "metadata": { 101 | "kernelspec": { 102 | "display_name": "Python 3", 103 | "language": "python", 104 | "name": "python3" 105 | }, 106 | "language_info": { 107 | "codemirror_mode": { 108 | "name": "ipython", 109 | "version": 3 110 | }, 111 | "file_extension": ".py", 112 | "mimetype": "text/x-python", 113 | "name": "python", 114 | "nbconvert_exporter": "python", 115 | "pygments_lexer": "ipython3", 116 | "version": "3.7.3" 117 | } 118 | }, 119 | "nbformat": 4, 120 | "nbformat_minor": 2 121 | } 122 | -------------------------------------------------------------------------------- /03-static_FC_analyses/load_data.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | ex_dual_mot = ['sub-13', 'sub-21', 'sub-23', 'sub-50'] # Higly motion subjects in one of four sessions 5 | ex_rest_mot = ['sub-21', 'sub-46', 'sub-47'] # Higly motion subjects in one of four sessions / missing data(20-44) 6 | ex_rest_mis = ['sub-20', 'sub-44'] # Missing data in resting (2nd session) 7 | ex_firs_mot = ['sub-21'] # Subject with highly motion on first session 8 | 9 | # path_fc_pow = 'data/matrices/LB_static_all_conditions_power.npy' 10 | path_fc_pow = 'data/matrices/LB_static_all_conditions_power.npy' 11 | path_fc_sch = 'data/matrices/LB_static_all_conditions_schaefer.npy' 12 | path_ma_pow = 'data/support/Power_modules.txt' 13 | path_ma_sch = 'data/support/Schaefer2018_300Parcels_7Networks_order.csv' 14 | path_bh_tra = 'data/behavioral/LB_training_mean_tidy.csv' 15 | path_bh_mri = 'data/behavioral/LB_fmri_behaviour_mean_tidy.csv' 16 | path_gr_ass = 'data/behavioral/LB_group_assignment.csv' 17 | 18 | # Functional connectivity 19 | print('=== Imaging data ===') 20 | mat_pow = np.load(path_fc_pow) 21 | mat_sch = np.load(path_fc_sch) 22 | print('mat_pow is {} having shape {}'.format(type(mat_pow), mat_pow.shape)) 23 | print('mat_sch is {} having shape {}'.format(type(mat_sch), mat_sch.shape)) 24 | print('\n') 25 | 26 | # A priori module assignment 27 | with open(path_ma_pow, 'r') as f: 28 | ma_pow = f.readlines() 29 | ma_pow = [ma.rstrip('\n') for ma in ma_pow] 30 | ma_sch = pd.read_csv(path_ma_sch, usecols=[6]) 31 | 32 | # Behavioral 33 | print('=== Behavioral data ===') 34 | beh_tra = pd.read_csv(path_bh_tra) 35 | beh_mri = pd.read_csv(path_bh_mri) 36 | grp_ass = pd.read_csv(path_gr_ass) 37 | print(beh_tra.head(3)) 38 | print('\nbeh_tra shape is {}\n'.format(beh_tra.shape)) 39 | print(beh_mri.head(3)) 40 | print('\nbeh_mri shape is {}\n'.format(beh_mri.shape)) 41 | print(grp_ass.head(3)) 42 | print('\ngrp_ass shape is {}\n'.format(grp_ass.shape)) 43 | 44 | # Exclusion 45 | print('=== Excluded subjects ===') 46 | print('Excluded due to motion in first session {}'.format(ex_firs_mot)) 47 | print('Excluded due to motion in dual {}'.format(ex_dual_mot)) 48 | print('Excluded due to motion in rest {}'.format(ex_rest_mot)) 49 | print('Excluded due to missing data in rest {}'.format(ex_rest_mis)) 50 | ex_rest = ex_rest_mis + ex_rest_mot 51 | -------------------------------------------------------------------------------- /04-dynamic_FC_analyses/01-multilayer_modularity_calculation.m: -------------------------------------------------------------------------------- 1 | %---------------------------------------------------- 2 | % Multilayer community detection algoritm 3 | 4 | % Karolina Finc | Centre for Modern Interdisciplinary Technologies, Nicolaus Copernicus University in Toruń, Poland 5 | % Last edited: 12-09-2018 6 | %---------------------------------------------------- 7 | 8 | % Mere the input is 5D matrix where: 9 | % 1st dim --> subject 10 | % 2nd dim --> session 11 | % 3rd dim --> time windows 12 | % 4th and 5th dim --> correlation matrix 13 | 14 | clc; clear; 15 | 16 | %% Loading data 17 | large = load('LB_dualnback_power_dynamic_correlation_matrices.mat'); 18 | M = squeeze(large.correlation_matrices_dyn_wei); 19 | 20 | n_sub = size(M,1); 21 | n_ses = size(M,2); 22 | n_win = size(M,3); 23 | n_roi = size(M,4); 24 | 25 | 26 | %% Parameters 27 | gamma = 1; 28 | omega = 1; 29 | n_rep = 100; 30 | 31 | %% Empty matrices to store data 32 | modularity_mean = zeros(n_sub, n_rep, n_ses); % Mean modularity 33 | modules = zeros(n_sub, n_ses, n_rep, n_roi, n_win); % Module assigment labels 34 | 35 | %% 36 | for sub = 1 : n_sub 37 | for ses = 1 : n_ses 38 | %--- define objects --------------------------------------------------- 39 | A = cell(1, n_win); 40 | B = spalloc(n_roi * n_win, n_roi * n_win,(n_roi + n_win) * n_roi* n_win); 41 | twomu = 0; 42 | 43 | %--- null model ------------------------------------------------------- 44 | for win = 1 : n_win 45 | %--- copy network with positive weights thresholding -------------- 46 | A{win} = squeeze(M(sub, ses, win, :, :) .* (M(sub, ses, win, :, :) > 0)); 47 | k = sum(A{win}); % node degree 48 | twom = sum(k); % mean network degree 49 | twomu = twomu + twom; % increment 50 | indx = [1:n_roi] + (win-1)*n_roi; % find indices 51 | B(indx,indx) = A{win} - gamma * [k'*k]/twom; % fill B matrix 52 | end 53 | twomu = twomu + 2*omega* n_roi*(n_win-1); 54 | 55 | B = B + omega/2*spdiags(ones(n_roi*n_win,2),[-n_roi, n_roi], n_roi*n_win, n_roi*n_win); 56 | B = B + omega*spdiags(ones(n_roi*n_win,2),[-2*n_roi, 2*n_roi], n_roi*n_win, n_roi*n_win); 57 | %B = B + omega * spdiags(ones(n_roi * n_win,2),[-n_roi, n_roi], n_roi*n_win, n_roi*n_win); 58 | 59 | %--- calculate multilayer modules ------------------------------------- 60 | %Qb = 0; 61 | for rep = 1 : n_rep 62 | clc; 63 | fprintf('Subject = %i\n',sub); 64 | [S,Q] = genlouvain(B); 65 | Q = Q / twomu; 66 | S = reshape(S, n_roi, n_win); 67 | 68 | modularity_mean(sub, rep, ses) = Q; 69 | modules(sub, ses, rep, :, :) = S; 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /04-dynamic_FC_analyses/02-module_allegiance_matrix_calculation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# **Working memory training**: Module allegiance matrix calculation\n", 8 | "\n", 9 | "**Last edited:** 04-10-2018\n" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "Step 0: Loading libraries\n", 17 | "--------------------------------" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 2, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import sys\n", 27 | "sys.path.append(\"..\")\n", 28 | "import os\n", 29 | "\n", 30 | "%matplotlib inline\n", 31 | "\n", 32 | "import scipy.io as sio\n", 33 | "import numpy as np\n", 34 | "from nilearn import plotting \n", 35 | "import pandas as pd\n", 36 | "import seaborn as sns\n", 37 | "import matplotlib.pyplot as plt\n", 38 | "\n", 39 | "from scipy import stats\n", 40 | "from fctools import networks, figures\n", 41 | "\n", 42 | "#---- matplotlib settings\n", 43 | "import matplotlib.pyplot as plt\n", 44 | "plt.style.use('seaborn-white')\n", 45 | "plt.rcParams['font.family'] = 'Helvetica'" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "Step 1: Getting modules names and color pallete\n", 53 | "----------------------------------------" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 3, 59 | "metadata": {}, 60 | "outputs": [ 61 | { 62 | "data": { 63 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAuMAAABECAYAAAAr+zvbAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAAyxJREFUeJzt2z2LXHUYxuFnMoPLGkPejGRSWGZIaWGjbik2gqDfQbCxlxRCilR+Agst/BpCik2XwsbC6YSAE8iLLrLKmt0Zi2hYlZ3umTueva7y/Ju7OvM7hzOj1WpVAADA5p1JDwAAgNNKjAMAQIgYBwCAEDEOAAAhk5MOZrPZVlW9WVWLqjra2CIAABiWcVVNq+refD4/OH5wYozXsxDf7VwFAACnyE5V3T1+YV2ML6qqbr37WV0+e6lzVMz3b7+entDq/kd30hPaHOx+k57Q6pP399MTWm19ez49odV3P3yantDq81u30xNavfXFV+kJra5/sJOe0ObDm+kFvW5c/Dg9odV7X7+RntDm6XKvfjz4suqvvj5uXYwfVVVdPnupXnvlStO0rAuvTtMTWj05HG7wjK8O++8O02V6Qa/t6Tg9odX9h8N8gfG30WiUntBq+8rV9IRW5w8P0xPaXDuXXtDr8MLL6QmtXjpzMT1hE/7z6fewiwYAAF5gYhwAAELEOAAAhIhxAAAIEeMAABAixgEAIESMAwBAiBgHAIAQMQ4AACFiHAAAQsQ4AACEiHEAAAgR4wAAECLGAQAgRIwDAECIGAcAgBAxDgAAIWIcAABCxDgAAISIcQAACBHjAAAQIsYBACBEjAMAQIgYBwCAEDEOAAAhYhwAAELEOAAAhIhxAAAIEeMAABAixgEAIESMAwBAiBgHAIAQMQ4AACFiHAAAQsQ4AACEiHEAAAgR4wAAECLGAQAgRIwDAECIGAcAgBAxDgAAIWIcAABCxDgAAISIcQAACBHjAAAQIsYBACBEjAMAQIgYBwCAEDEOAAAhYhwAAELEOAAAhEzWnI2rqh7vP9nQlM375dF2ekKr/cleekKbgwfL9IRWi4E/Jm8tjtITWj16PNz7ZlXVarVKT2j1+8MH6Qmt9ibrfvr/3376Nb2g12TyW3pCqz+WP6cntHm6fN5k43+fjU66qc5ms3eqardvFgAAnCo78/n87vEL6x6P71XVTlUtqmrYr7EAAKDPuKqm9ayv/+HEN+MAAECvgX+ZCgAALy4xDgAAIWIcAABCxDgAAIT8CWitXhDKYeylAAAAAElFTkSuQmCC\n", 64 | "text/plain": [ 65 | "
" 66 | ] 67 | }, 68 | "metadata": { 69 | "needs_background": "light" 70 | }, 71 | "output_type": "display_data" 72 | } 73 | ], 74 | "source": [ 75 | "labels = pd.read_csv(f'../support/modules.txt', sep = \" \", header = None)\n", 76 | "\n", 77 | "power_colors_new = {'AU':'#d182c6', \n", 78 | " 'CER':'#9fc5e8', \n", 79 | " 'CO':'#7d009d', \n", 80 | " 'DA':'#75df33', \n", 81 | " 'DM':'#ed1126', \n", 82 | " 'FP':'#f6e838', \n", 83 | " 'MEM':'#bebab5', \n", 84 | " 'SAL':'#2a2a2a', \n", 85 | " 'SOM':'#6ccadf', \n", 86 | " 'SUB':'#980000', \n", 87 | " 'UNC':'#f58c00', \n", 88 | " 'VA':'#00a074', \n", 89 | " 'VIS':'#5131ac',}\n", 90 | "\n", 91 | "modules = sorted(labels[0].values)\n", 92 | "network_pal = (sns.color_palette(power_colors_new.values()))\n", 93 | "sns.palplot(sns.color_palette(power_colors_new.values()))\n", 94 | "\n", 95 | "network_lut = dict(zip(map(str, np.unique(modules)), network_pal))\n", 96 | "\n", 97 | "network_colors = pd.Series(modules).map(network_lut)\n", 98 | "network_colors = np.asarray(network_colors)\n", 99 | "\n", 100 | "n_roi = len(labels)\n", 101 | "n_net = len(np.unique(modules))" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "Step 2: Loading module assignment matrices\n", 109 | "-------------------------------------------------------------------------------" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 5, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "top_dir = '/home/finc/Dropbox/Projects/LearningBrain/'\n", 119 | "mat = sio.loadmat(f'{top_dir}data/neuroimaging/03-modularity/dynamic/02-module_assignment/power_modules.mat')\n", 120 | "\n", 121 | "idx = np.argsort(labels[0])\n", 122 | "\n", 123 | "module_assignment = mat['modules']\n", 124 | "module_assignment = module_assignment[:, :, :, idx, :]" 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "Step 3: calculating allegiance matrices\n", 132 | "-------------------------------------------" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 8, 138 | "metadata": {}, 139 | "outputs": [ 140 | { 141 | "name": "stdout", 142 | "output_type": "stream", 143 | "text": [ 144 | "Subject 1\n" 145 | ] 146 | }, 147 | { 148 | "ename": "KeyboardInterrupt", 149 | "evalue": "", 150 | "output_type": "error", 151 | "traceback": [ 152 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 153 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", 154 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'Subject {i+1}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn_ses\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0mP\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnetworks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mallegiance_matrix_opti\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodule_assignment\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msave\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'{top_dir}data/neuroimaging/03-modularity/dynamic/03-allegiance_matrices/allegiance_matrix_power_opt_mean.npy'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mP\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 155 | "\u001b[0;32m~/Dropbox/Projects/LearningBrain/github/WM_training_modularity/04-dynamic_FC_analyses/fctools/networks.py\u001b[0m in \u001b[0;36mallegiance_matrix_opti\u001b[0;34m(M)\u001b[0m\n", 156 | "\u001b[0;32m~/Dropbox/Projects/LearningBrain/github/WM_training_modularity/04-dynamic_FC_analyses/fctools/networks.py\u001b[0m in \u001b[0;36mallegiance_matrix\u001b[0;34m(M)\u001b[0m\n", 157 | "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/numpy/core/fromnumeric.py\u001b[0m in \u001b[0;36msum\u001b[0;34m(a, axis, dtype, out, keepdims, initial)\u001b[0m\n\u001b[1;32m 2074\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2075\u001b[0m return _wrapreduction(a, np.add, 'sum', axis, dtype, out, keepdims=keepdims,\n\u001b[0;32m-> 2076\u001b[0;31m initial=initial)\n\u001b[0m\u001b[1;32m 2077\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2078\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 158 | "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/numpy/core/fromnumeric.py\u001b[0m in \u001b[0;36m_wrapreduction\u001b[0;34m(obj, ufunc, method, axis, dtype, out, **kwargs)\u001b[0m\n\u001b[1;32m 84\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mreduction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0maxis\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mpasskwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 86\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mufunc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreduce\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mpasskwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 87\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 88\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 159 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: " 160 | ] 161 | } 162 | ], 163 | "source": [ 164 | "# Calculating allegiance matrices (mean over optimizations)\n", 165 | "n_sub = module_assignment.shape[0]\n", 166 | "n_ses = module_assignment.shape[1]\n", 167 | "n_opt = module_assignment.shape[2]\n", 168 | "n_nod = module_assignment.shape[3]\n", 169 | "\n", 170 | "P = np.zeros((n_sub, n_ses, n_nod, n_nod))\n", 171 | "\n", 172 | "for i in range(n_sub):\n", 173 | " print(f'Subject {i+1}')\n", 174 | " for j in range(n_ses):\n", 175 | " P[i,j,:,:] = networks.allegiance_matrix_opti(module_assignment[i,j,:,:,:])\n", 176 | "\n", 177 | "np.save(f'{top_dir}data/neuroimaging/03-modularity/dynamic/03-allegiance_matrices/allegiance_matrix_power_opt_mean.npy', P)" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 14, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "name": "stdout", 187 | "output_type": "stream", 188 | "text": [ 189 | "Subject 1\n", 190 | "Subject 2\n", 191 | "Subject 3\n", 192 | "Subject 4\n", 193 | "Subject 5\n", 194 | "Subject 6\n", 195 | "Subject 7\n", 196 | "Subject 8\n", 197 | "Subject 9\n", 198 | "Subject 10\n", 199 | "Subject 11\n", 200 | "Subject 12\n", 201 | "Subject 13\n", 202 | "Subject 14\n", 203 | "Subject 15\n", 204 | "Subject 16\n", 205 | "Subject 17\n", 206 | "Subject 18\n", 207 | "Subject 19\n", 208 | "Subject 20\n", 209 | "Subject 21\n", 210 | "Subject 22\n", 211 | "Subject 23\n", 212 | "Subject 24\n", 213 | "Subject 25\n", 214 | "Subject 26\n", 215 | "Subject 27\n", 216 | "Subject 28\n", 217 | "Subject 29\n", 218 | "Subject 30\n", 219 | "Subject 31\n", 220 | "Subject 32\n", 221 | "Subject 33\n", 222 | "Subject 34\n", 223 | "Subject 35\n", 224 | "Subject 36\n", 225 | "Subject 37\n", 226 | "Subject 38\n", 227 | "Subject 39\n", 228 | "Subject 40\n", 229 | "Subject 41\n", 230 | "Subject 42\n", 231 | "Subject 43\n", 232 | "Subject 44\n", 233 | "Subject 45\n", 234 | "Subject 46\n" 235 | ] 236 | } 237 | ], 238 | "source": [ 239 | "# Calculating allegiance matrices for each window (mean over optimizations)\n", 240 | "\n", 241 | "n_sub = len(module_assignment.shape[0])\n", 242 | "n_ses = len(module_assignment.shape[1])\n", 243 | "n_nod = len(module_assignment.shape[3])\n", 244 | "n_win = len(module_assignment.shape[4])\n", 245 | "\n", 246 | "W = np.zeros((n_sub, n_ses, n_win, n_nod, n_nod))\n", 247 | "\n", 248 | "for i in range(n_sub):\n", 249 | " print(f'Subject {i+1}')\n", 250 | " W[i,j,:,:,:] = networks.all_window_allegiance_mean(module_assignment[i, j, :, :, :])\n", 251 | "\n", 252 | "np.save(f'{top_dir}data/neuroimaging/03-modularity/dynamic/03-allegiance_matrices/window_allegiance_matrix_power_dualnback.npy', W)" 253 | ] 254 | } 255 | ], 256 | "metadata": { 257 | "kernelspec": { 258 | "display_name": "Python 3", 259 | "language": "python", 260 | "name": "python3" 261 | }, 262 | "language_info": { 263 | "codemirror_mode": { 264 | "name": "ipython", 265 | "version": 3 266 | }, 267 | "file_extension": ".py", 268 | "mimetype": "text/x-python", 269 | "name": "python", 270 | "nbconvert_exporter": "python", 271 | "pygments_lexer": "ipython3", 272 | "version": "3.7.3" 273 | } 274 | }, 275 | "nbformat": 4, 276 | "nbformat_minor": 2 277 | } 278 | -------------------------------------------------------------------------------- /04-dynamic_FC_analyses/08-multilayer_modularity_calculation_signed.m: -------------------------------------------------------------------------------- 1 | clc; clear; 2 | 3 | %% Loading data 4 | large = load('LB_dualnback_power_dynamic_correlation_matrices.mat'); 5 | M = squeeze(large.correlation_matrices_dyn_wei); 6 | 7 | n_sub = size(M,1); 8 | n_ses = size(M,2); 9 | T = size(M,3); 10 | N = size(M,4); 11 | 12 | %% Parameters 13 | gplus = 1; 14 | gminus = 1; 15 | omega = 1; 16 | n_rep = 100; 17 | 18 | %% Empty matrices to store results 19 | modularity_mean = zeros(n_sub, n_rep, n_ses); % Mean modularity 20 | modules = zeros(n_sub, n_ses, n_rep, N, T); % Module assigment labels 21 | 22 | for sub = 1 : 1:n_sub 23 | for ses = 1 :1: n_ses 24 | 25 | %--- define objects --------------------------------------------------- 26 | A = cell(1, T); 27 | B=spalloc(N*T,N*T,N*N*T+2*N*T); 28 | twom=0; 29 | 30 | % Signed version by Xiaosong He, 5/23/2019 31 | for s=1:T 32 | A{s} = squeeze(M(sub, ses, s, :, :)); 33 | Aplus=A{s}; Aplus(A{s}<0)=0; 34 | Aminus=-A{s}; Aminus(A{s}>0)=0; 35 | kplus=sum(Aplus)'; 36 | kminus=sum(Aminus)'; 37 | mm=sum(kplus)+sum(kminus); 38 | twom=twom+mm; 39 | indx=[1:N]+(s-1)*N; 40 | if sum(kminus) == 0 % necessary for case no negative edges in matrix 41 | Gm=0; 42 | else 43 | Gm=gminus*kminus*kminus'/sum(kminus); 44 | end 45 | B(indx,indx)=A{s}-(gplus*kplus*kplus'/sum(kplus)-Gm); 46 | end 47 | 48 | 49 | B = B + omega/2*spdiags(ones(N*T,2),[-N, N], N*T, N*T); 50 | B = B + omega*spdiags(ones(N*T,2),[-2*N, 2*N], N*T, N*T); 51 | 52 | twom=twom+(N*T*(T-1)*omega); 53 | 54 | for rep = 1 : n_rep 55 | clc; 56 | fprintf('Subject = %i\n',sub); 57 | [S,Q] = genlouvain(B); 58 | Q = Q / twom; 59 | S = reshape(S, N, T); 60 | 61 | modularity_mean(sub, rep, ses) = Q; 62 | modules(sub, ses, rep, :, :) = S; 63 | end 64 | 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Karolina Finc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dynamic reconfiguration of functional brain networks during working memory training 2 | 3 | Repository containing a code for network analyses of longitudinal working memory training data with multi-session fMRI scanning. 4 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: LearningBrain_networks 2 | dependencies: 3 | - numpy = 1.13.3 4 | - pandas = 0.20.3 5 | - nilearn = 0.4.2 6 | - scipy = 0.19.1 7 | - matplotlib = 2.1.0 8 | - sklearn = 0.19.1 9 | 10 | -------------------------------------------------------------------------------- /fctools/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.1" 2 | -------------------------------------------------------------------------------- /fctools/denoise.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | """ 5 | Created on Wed Jul 19 2018 6 | Last edit: Sat Sep 01 2018 7 | @author: kfinc 8 | 9 | """ 10 | 11 | import pandas as pd 12 | import numpy as np 13 | from sklearn import preprocessing 14 | from nistats.design_matrix import make_first_level_design_matrix 15 | 16 | 17 | def motion_24_friston(dataframe): 18 | 19 | """Simple function that calculates 24 motion parameters from pandas dataframe. 20 | 21 | Parameters 22 | ---------- 23 | dataframe: pandas dataframe including 6 movement parameters with headers 24 | 25 | Returns 26 | ------- 27 | motion_24_friston: pandas dataframe including 24 motion parameters 28 | 29 | - the first 6 are the motion parameters 30 | - the next 6 are the temporal difference of motion parameters ('_td' suffix) 31 | - the next 12 are the square of the motion parameters and the differenced values ('_sqrt' suffix) 32 | 33 | """ 34 | 35 | motion_24_friston = dataframe 36 | 37 | for col in dataframe.columns: 38 | temp_diff = np.roll(dataframe[col], 1, axis = 0) 39 | temp_diff[0] = 0 40 | temp_diff = pd.DataFrame(temp_diff) 41 | motion_24_friston[col + '_td'] = temp_diff 42 | 43 | for col in motion_24_friston.columns: 44 | quad = motion_24_friston[col] ** 2 45 | motion_24_friston[col + '_quad'] = quad 46 | 47 | return motion_24_friston 48 | 49 | 50 | def scrubbing(fd, thr = 0.5, before = True, after = True): 51 | 52 | """Function that calculates motion outliers (frames with motion above threshold_. 53 | 54 | Parameters 55 | ---------- 56 | fd: pandas dataframe including frame-wise displacement (FD) 57 | thr: threshold (default: 0.5) 58 | before: marks frames before outlier datapoint (default: True) 59 | after: marks frames after outlier datapoint (default: True) 60 | 61 | Returns 62 | ------- 63 | scrubbing: pandas dataframe including all ourliers datapoints 64 | 65 | """ 66 | 67 | scrubbing = pd.DataFrame() 68 | fd.loc[0] = 0 69 | fd = fd.astype(float) 70 | 71 | scrub1 = fd > thr 72 | scrub1 = scrub1.astype(int) 73 | scrubbing['scrubbing'] = scrub1 74 | 75 | if before == True: 76 | scrub2 = np.roll(scrubbing['scrubbing'], -1, axis = 0) 77 | scrub2[0] = 0 78 | scrubbing['scrubbing_bef'] = scrub2 79 | 80 | if after == True: 81 | scrub3 = np.roll(scrubbing['scrubbing'], 1, axis = 0) 82 | scrub3[0] = 0 83 | scrubbing['scrubbing_aft'] = scrub3 84 | 85 | return scrubbing 86 | 87 | 88 | 89 | def standardize(dataframe): 90 | """ 91 | Normalizes each column and returns values set to unit variance. 92 | 93 | Parameters 94 | ---------- 95 | dataframe: pandas dataframe including columns of interest 96 | 97 | Returns 98 | ------- 99 | dataframe_stand: pandas dataframe with standarized values 100 | 101 | 102 | """ 103 | 104 | dataframe_stand = pd.DataFrame() 105 | val = dataframe.values 106 | standardize = preprocessing.StandardScaler() 107 | val_scaled = standardize.fit_transform(val) 108 | dataframe_stand = pd.DataFrame(val_scaled, columns = dataframe.columns) 109 | 110 | return dataframe_stand 111 | 112 | 113 | def motion_temp_diff(dataframe): 114 | 115 | """Simple function that calculates 12 motion parameters from pandas dataframe. 116 | 117 | Parameters 118 | ---------- 119 | dataframe: pandas dataframe including 6 movement parameters with headers 120 | 121 | Returns 122 | ------- 123 | motion_temp_diff: pandas dataframe including 24 motion parameters 124 | 125 | - the first 6 are the motion parameters 126 | - the next 6 are the temporal difference of motion parameters ('_td' suffix) 127 | 128 | """ 129 | 130 | motion_temp_diff = dataframe 131 | 132 | for col in dataframe.columns: 133 | temp_diff = np.roll(dataframe[col], 1, axis = 0) 134 | temp_diff[0] = 0 135 | temp_diff = pd.DataFrame(temp_diff) 136 | motion_temp_diff[col + '_td'] = temp_diff 137 | 138 | return motion_temp_diff 139 | 140 | 141 | def temp_deriv(dataframe, quadratic = False): 142 | """Simple function that calculates temporal derivatives for each column of pandas dataframe. 143 | 144 | Parameters 145 | ---------- 146 | dataframe: pandas dataframe with variable to calculate temporal derivarives 147 | 148 | Returns 149 | ------- 150 | temp_deriv: pandas dataframe including original columns and their temporal derivatives ('_td') and (optional) 151 | their quadratic terms 152 | 153 | """ 154 | 155 | temp_deriv = dataframe.copy() 156 | 157 | for col in dataframe.columns: 158 | #--- backward difference algorithm 159 | temp = np.diff(dataframe[col], 1, axis = 0) 160 | temp = np.insert(temp, 0, 0) 161 | temp = pd.DataFrame(temp ) 162 | temp_deriv[col + '_td'] = temp 163 | 164 | if quadratic == True: 165 | for col in temp_deriv.columns: 166 | quad = temp_deriv[col] ** 2 167 | temp_deriv[col + '_quad'] = quad 168 | 169 | return temp_deriv 170 | 171 | def scrubbing(fd, thr = 0.5, before = True, after = True): 172 | 173 | """Function that calculates motion outliers (frames with motion above threshold_. 174 | 175 | Parameters 176 | ---------- 177 | fd: pandas dataframe including frame-wise displacement (FD) 178 | thr: threshold (default: 0.5) 179 | before: marks frames before outlier datapoint (default: True) 180 | after: marks frames after outlier datapoint (default: True) 181 | 182 | Returns 183 | ------- 184 | scrubbing: pandas dataframe including all outliers datapoints 185 | 186 | """ 187 | 188 | scrubbing = pd.DataFrame() 189 | fd.loc[0] = 0 190 | fd = fd.astype(float) 191 | 192 | scrub1 = fd > thr 193 | scrub1 = scrub1.astype(int) 194 | scrubbing['scrubbing'] = scrub1 195 | 196 | if before == True: 197 | scrub2 = np.roll(scrubbing['scrubbing'], -1, axis = 0) 198 | scrub2[0] = 0 199 | scrubbing['scrubbing_bef'] = scrub2 200 | 201 | if after == True: 202 | scrub3 = np.roll(scrubbing['scrubbing'], 1, axis = 0) 203 | scrub3[0] = 0 204 | scrubbing['scrubbing_aft'] = scrub3 205 | 206 | return scrubbing 207 | 208 | def outliers_fd_dvars(dataframe, fd=0.5, dvars=3): 209 | """Function that calculates motion outliers (frames with frame-wise displacement (FD) 210 | and DVARS above predefined threshold). 211 | 212 | Parameters 213 | ---------- 214 | dataframe: pandas dataframe including columns with DVARS and FD 215 | fd: threshold for FD (default: 0.5) 216 | dvars: threshold for DVARS (+/-SD, default: 3) 217 | 218 | Returns 219 | ------- 220 | outliers: pandas dataframe including all outliers datapoints 221 | 222 | """ 223 | 224 | df = dataframe.copy() 225 | df.fillna(value=0, inplace=True) 226 | 227 | dvars_out = np.absolute(df[df.columns[0]].astype(float)) > dvars 228 | fd_out = df[df.columns[1]].astype(float) > fd 229 | 230 | outliers = (dvars_out == True) | (fd_out == True) 231 | outliers = pd.DataFrame(outliers.astype('int')) 232 | outliers.columns = ['scrubbing'] 233 | 234 | return outliers 235 | 236 | def get_condition_column(events, tr = 2, n_scans = 340): 237 | """converts events file to pd dataframe with column representing each condition""" 238 | frame_times = np.arange(n_scans) * tr 239 | box = make_first_level_design_matrix(frame_times, events, hrf_model = None) 240 | box = box.reset_index() 241 | 242 | x = box.iloc[:,1:4] > 0.8 243 | y = x.astype('int') 244 | col = pd.DataFrame(y.idxmax(axis=1), columns = ['condition']) 245 | return col 246 | 247 | -------------------------------------------------------------------------------- /fctools/figures.py: -------------------------------------------------------------------------------- 1 | import seaborn as sns 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | 5 | def matrix_networks_plot(M, network_colors, dpi = 300, colorbar = False, group = None, ses = None, suffix = None, out_dir = None): 6 | """Creates and saves matrixplot with networks color labels. """ 7 | 8 | small = 15 9 | medium = 15 10 | bigger = 15 11 | 12 | plt.rc('font', size=small) # controls default text sizes 13 | plt.rc('axes', titlesize=small) # fontsize of the axes title 14 | plt.rc('axes', linewidth=2.2) 15 | plt.rc('axes', labelsize=medium) # fontsize of the x and y labels 16 | plt.rc('xtick', labelsize=small) # fontsize of the tick labels 17 | plt.rc('ytick', labelsize=small) # fontsize of the tick labels 18 | plt.rc('legend', fontsize=small) # legend fontsize 19 | plt.rc('figure', titlesize=bigger) # fontsize of the figure title 20 | plt.rc('lines', linewidth=2.2, color='gray') 21 | 22 | g = sns.clustermap(M, 23 | cmap="RdBu_r", 24 | row_cluster=False, 25 | col_cluster=False, 26 | row_colors=network_colors, 27 | col_colors=network_colors, 28 | linewidths=0, 29 | yticklabels=False, 30 | xticklabels=False, 31 | vmax = 0.8) 32 | 33 | # Adjust the postion of the main colorbar for the heatmap 34 | g.cax.set_position([.97, .2, .03, .45]) 35 | g.fig.suptitle(f'{group}: {ses}', size = 20) 36 | #g.ax_heatmap.set_title(f'{group}: {ses}', size = 15) 37 | g.cax.set_visible(colorbar) 38 | 39 | if out_dir == None: 40 | "Figure not saved" 41 | else: 42 | 43 | if suffix != None: 44 | g.savefig(f'{out_dir}{group}_{ses}_{suffux}.pdf', dpi=dpi) 45 | else: 46 | g.savefig(f'{out_dir}{group}_{ses}.pdf', dpi=dpi) 47 | 48 | 49 | def swarm_box_plot(x, y, hue, data): 50 | plt.style.use('seaborn-white') 51 | plt.rcParams['font.family'] = 'Helvetica' 52 | 53 | plt.figure(figsize = (8, 6)) 54 | 55 | ax = sns.swarmplot(x = x, y = y, hue = hue, data = data, dodge = True, alpha = 0.8, size = 8) 56 | ax = sns.boxplot(x = x, y = y, hue = hue, data = data, dodge = True, 57 | showcaps = False, boxprops = {'facecolor':'None'}, 58 | showfliers = False) 59 | plt.xticks(np.arange(4), ('1', '2', '3', '4')) 60 | ax.set(xlabel='Scan') 61 | ax.tick_params(axis='both', color = 'black', length = 5, width = 2) 62 | 63 | return ax 64 | 65 | 66 | def swarm_box_plot_integ(x, hue, data, net1, net2): 67 | 68 | plt.style.use('seaborn-white') 69 | plt.rcParams['font.family'] = 'Helvetica' 70 | 71 | small = 25 72 | medium = 25 73 | bigger = 25 74 | 75 | plt.rc('font', size=small) # controls default text sizes 76 | plt.rc('axes', titlesize=small) # fontsize of the axes title 77 | plt.rc('axes', linewidth=2.2) 78 | plt.rc('axes', labelsize=medium) # fontsize of the x and y labels 79 | plt.rc('xtick', labelsize=small) # fontsize of the tick labels 80 | plt.rc('ytick', labelsize=small) # fontsize of the tick labels 81 | plt.rc('legend', fontsize=small) # legend fontsize 82 | plt.rc('figure', titlesize=bigger) # fontsize of the figure title 83 | plt.rc('lines', linewidth=2.2, color='gray') 84 | 85 | plt.figure(figsize = (8, 6)) 86 | 87 | ax = sns.swarmplot(x = x, y = f'{net1}_integration', hue = hue, data = data[data['Network'] == net2], dodge = True, alpha = 0.8, size = 8) 88 | ax = sns.boxplot(x = x, y = f'{net1}_integration', hue = hue, data = data[data['Network'] == net2], dodge = True, 89 | showcaps = False, boxprops = {'facecolor':'None'}, 90 | showfliers = False) 91 | plt.xticks(np.arange(4), ('Naive', 'Early', 'Middle', 'Late')) 92 | ax.set(xlabel='Scan') 93 | plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) 94 | ax.tick_params(axis='both', color = 'black', length = 5, width = 2) 95 | 96 | 97 | return ax 98 | 99 | 100 | def matrix_networks_slope_plot(M, network_colors, dpi=300, colorbar=False, group=None, suffix=None, out_dir=None, vmin = -0.08, vmax = 0.08): 101 | """Creates and saves matrixplot with networks color labels. """ 102 | 103 | small = 15 104 | medium = 15 105 | bigger = 15 106 | 107 | plt.rc('font', size=small) # controls default text sizes 108 | plt.rc('axes', titlesize=small) # fontsize of the axes title 109 | plt.rc('axes', linewidth=2.2) 110 | plt.rc('axes', labelsize=medium) # fontsize of the x and y labels 111 | plt.rc('xtick', labelsize=small) # fontsize of the tick labels 112 | plt.rc('ytick', labelsize=small) # fontsize of the tick labels 113 | plt.rc('legend', fontsize=small) # legend fontsize 114 | plt.rc('figure', titlesize=bigger) # fontsize of the figure title 115 | plt.rc('lines', linewidth=2.2, color='gray') 116 | g = sns.clustermap(M, 117 | cmap="RdBu_r", 118 | row_cluster=False, 119 | col_cluster=False, 120 | row_colors=network_colors, 121 | col_colors=network_colors, 122 | linewidths=0, 123 | yticklabels=False, 124 | xticklabels=False, vmin = vmin, vmax = vmax) 125 | 126 | # Adjust the postion of the main colorbar for the heatmap 127 | g.cax.set_position([.97, .2, .03, .45]) 128 | g.fig.suptitle(f'{group}', size=20) 129 | #g.ax_heatmap.set_title(f'{group}: {ses}', size = 15) 130 | g.cax.set_visible(colorbar) 131 | 132 | if out_dir == None: 133 | "Figure not saved" 134 | else: 135 | 136 | if suffix != None: 137 | g.savefig(f'{out_dir}{group}_{ses}_{suffux}.pdf', dpi=dpi) 138 | else: 139 | g.savefig(f'{out_dir}{group}_{ses}.pdf', dpi=dpi) -------------------------------------------------------------------------------- /fctools/networks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | """ 5 | Created on Tue Jun 12 2018 6 | Last edit: Tue Jun 12 2018 7 | @author: kfinc 8 | 9 | """ 10 | 11 | import numpy as np 12 | import pandas as pd 13 | 14 | def calculate_lsn_edges (A, labels): 15 | """Function calculates number of edges between and within predefined large-scale networks (LSNs). 16 | The function takes binary symetrical adjacency matrix, module assignment of each ROI and calculate number of edges between and within each 17 | large-scale network. 18 | 19 | Parameters 20 | ------------ 21 | array: N x N binary ajdacency matrix 22 | array: N-length vector with module assignment for each node 23 | 24 | Returns 25 | ------------ 26 | array: M x M matrix with number of edges between each module 27 | 28 | """ 29 | columns = np.unique(labels) 30 | lsn_matrix = np.zeros((len(labels), len(columns))) 31 | lsn_edges = np.zeros((len(columns), len(columns))) 32 | 33 | for col in range(len(columns)): 34 | module = columns[col, ] 35 | for row in range(len(labels)): 36 | if (labels[row, ] == module): 37 | lsn_matrix[row, col] = 1 38 | else: 39 | lsn_matrix[row, col] = 0 40 | 41 | lsn_edges = lsn_matrix.T @ A @ lsn_matrix 42 | return lsn_edges 43 | 44 | 45 | def allegiance_matrix(M): 46 | """Calculates n x n allegiance matrix P from n x t matrix M, where n represents nodes, and t represents time windows. 47 | Each value on allegiance matrix P represents the probability that node i and node j have been assigned to the same 48 | community (Bassett et al., 2014; Mattar et al., 2015). 49 | 50 | Parameters 51 | ------------ 52 | array: n x t module assignment matrix t 53 | 54 | Returns 55 | ------------ 56 | array: n x n allegiance matrix P """ 57 | 58 | n_nodes = M.shape[0] 59 | n_slices = M.shape[1] 60 | T = np.zeros((n_nodes, n_nodes)) 61 | 62 | for i in range(n_nodes): 63 | for j in range(i): 64 | if i == j: 65 | continue 66 | else: 67 | t = np.sum(M[i, :] == M[j, :]) 68 | T[i, j] = t 69 | 70 | P = (T + T.T)/n_slices 71 | np.fill_diagonal(P, 1) 72 | 73 | return P 74 | 75 | 76 | def allegiance_matrices_4d(M): 77 | """Calculates 4D array composed of allegiance matrices for each subject and each condition/session. 78 | 79 | Parameters 80 | ------------ 81 | array: 4D array S(subjects) x C(condition/session) x N(node) x M(window) 82 | 83 | Returns 84 | ------------ 85 | array: 4D array S(subjects) x C(condition/session) x N(node) x N(node), where N x N is allegiance matrix 86 | 87 | """ 88 | n_roi = len(M[0,0,:,0]) 89 | n_sub = len(M[:,0,0,0]) 90 | n_ses = len(M[0,:,0,0]) 91 | AM = np.zeros((n_sub, n_ses, n_roi, n_roi)) 92 | 93 | for sub in range(n_sub): 94 | for ses in range(n_ses): 95 | AM[sub, ses, :, :] = allegiance_matrix(M[sub, ses, :, :]) 96 | return AM 97 | 98 | def allegiance_matrix_opti(M): 99 | """Calculates n x n allegiance matrix P from o x n x t matrix M, where o represents module community detection 100 | optimizations, n represents nodes, and t represents time windows. Each value on allegiance matrix PO represents the 101 | probability that node i and node j have been assigned to the same 102 | community (Bassett et al., 2014; Mattar et al., 2015). 103 | 104 | Parameters 105 | ------------ 106 | array: o x n x t module assignment matrix t 107 | 108 | Returns 109 | ------------ 110 | array: n x n allegiance matrix P (mean across all optimizations)""" 111 | 112 | n_optimizations = M.shape[0] 113 | n_nodes = M.shape[1] 114 | P = np.zeros((n_optimizations, n_nodes, n_nodes)) 115 | PO = np.zeros((n_nodes, n_nodes)) 116 | 117 | for i in range(n_optimizations): 118 | P[i, :, :] = allegiance_matrix(M[i, :, :]) 119 | PO = P.mean(axis = 0) 120 | return PO 121 | 122 | def allegiance_matrix_opti_5d(M): 123 | 124 | n_subs = M.shape[0] 125 | n_sess = M.shape[1] 126 | n_optimizations = M.shape[2] 127 | n_nodes = M.shape[3] 128 | 129 | P = np.zeros((n_subs, n_sess, n_optimizations, n_nodes, n_nodes)) 130 | 131 | for i in range(n_subs): 132 | for j in range(n_sess): 133 | P[i, j, :, :, :] = allegiance_matrix_opti_3d(M[i, j, :, :, :]) 134 | return P 135 | 136 | def sort_matrices_4d(M, idx): 137 | """Sorts matrices according to predefinded index. 138 | 139 | Parameters 140 | ------------ 141 | array: 4D array S(subjects) x C(condition/session) x N(node) x N(node) (unsorted) 142 | array: N-length vector with index to sort matrix 143 | 144 | Returns 145 | ------------ 146 | array: 4D array S(subjects) x C(condition/session) x N(node) x N(node) (sorted)""" 147 | M1 = M[:,:,:,idx] 148 | M2 = M1[:,:,idx,:] 149 | return M2 150 | 151 | 152 | def dumming(labels): 153 | """Gennerate vectors with dummy variables from single vector with categorical variable 154 | 155 | Parameters 156 | ------------ 157 | array: np.array, N-length vector with categorical variable 158 | 159 | Returns 160 | ------------ 161 | array: 3D array with M rows and N columns with binary variables""" 162 | 163 | columns = np.unique(labels) 164 | dummies = np.zeros((len(labels), len(columns))) 165 | 166 | for col in range(len(columns)): 167 | module = columns[col] 168 | for row in range(len(labels)): 169 | if (labels[row] == module): 170 | dummies[row, col] = 1 171 | else: 172 | dummies[row, col] = 0 173 | return dummies 174 | 175 | 176 | def dumming_pd(labels): 177 | """Gennerate vectors with dummy variables from single vector with categorical variable 178 | 179 | Parameters 180 | ------------ 181 | array: np.array, N-length vector with categorical variable 182 | 183 | Returns 184 | ------------ 185 | array: pd.DataFrame with M rows and N columns with binary variables 186 | 187 | """ 188 | columns = np.unique(labels) 189 | return pd.DataFrame(dumming(labels), columns=columns) 190 | 191 | def upper_tri_masking(A): 192 | """Getting values of upper triangle of matrix without diagonal""" 193 | m = A.shape[0] 194 | r = np.arange(m) 195 | mask = r[:,None] < r 196 | return A[mask] 197 | 198 | 199 | def fc_cartography(M, modules): 200 | """Function which calculates mean integration and recruitment values from sorted allegiance matrices""" 201 | dummy_networks = dumming(sorted(modules)) 202 | roi_n = len(dummy_networks) 203 | net = np.size(dummy_networks,1) 204 | diagnostics = np.zeros((net, net)) 205 | 206 | for i in range(net): 207 | for j in range(net): 208 | vec1 = dummy_networks[:,i].astype('bool') 209 | vec2 = dummy_networks[:,j].astype('bool') 210 | 211 | L = M[vec1,:] 212 | P = L[:,vec2] 213 | 214 | #if i == j: 215 | # m = upper_tri_masking(P).mean() 216 | #else: 217 | m = P.mean() 218 | 219 | diagnostics[i, j] = m 220 | return diagnostics 221 | 222 | 223 | '''def fc_cartography(M, modules): 224 | """Function which calculates mean integration and recruitment values from sorted allegiance matrices""" 225 | dummy_networks = dumming(sorted(modules)) 226 | n_nod = len(dummy_networks) 227 | n_net = np.size(dummy_networks,1) 228 | diagnostics = np.zeros((n_net, n_net)) 229 | 230 | for i in range(n_net): 231 | for j in range(n_net): 232 | vec1 = dummy_networks[:,i].astype('bool') 233 | vec2 = dummy_networks[:,j].astype('bool') 234 | 235 | L = M[vec1,:] 236 | P = L[:,vec2] 237 | 238 | #if i == j: 239 | # m = upper_tri_masking(P).mean() 240 | #else: 241 | m = P.mean() 242 | 243 | diagnostics[i, j] = m 244 | return diagnostics 245 | ''' 246 | 247 | 248 | 249 | def fc_cartography_4d(M, modules): 250 | """Function which calculates mean integration and recruitment values from sorted allegiance matrices. 4D version""" 251 | sub_n = len(M[:,0,0,0]) 252 | ses_n = len(M[0,:,0,0]) 253 | mod_n = len(np.unique(modules)) 254 | 255 | fc_cart = np.zeros((sub_n, ses_n, mod_n, mod_n)) 256 | 257 | for i in range(sub_n): 258 | for j in range(ses_n): 259 | X = M[i,j,:,:] 260 | fc_cart[i, j, :, :] = fc_cartography(X, modules) 261 | return fc_cart 262 | 263 | 264 | def net_filter(M, modules, net_list): 265 | modules = np.sort(np.asarray(modules)) 266 | net_filt = [True if elem in net_list else False for elem in modules] 267 | M1 = M[net_filt, :] 268 | M2 = M1[:, net_filt] 269 | return M2 270 | 271 | def net_filter_4d(M, modules, net_list): 272 | modules = np.sort(np.asarray(modules)) 273 | net_filt = [True if elem in net_list else False for elem in modules] 274 | M1 = M[:, :, net_filt, :] 275 | M2 = M1[:, :, :, net_filt] 276 | return M2 277 | 278 | def single_window_allegiance(t): 279 | n_nod = len(t) 280 | T = np.zeros((n_nod, n_nod)) 281 | 282 | for i, row in enumerate(t): 283 | for j, col in enumerate(t): 284 | if row == col: 285 | T[i,j] = 1 286 | else: 287 | continue 288 | return T 289 | 290 | def single_window_allegiance_mean(M): 291 | n_opt = M.shape[0] 292 | n_nod = M.shape[1] 293 | T = np.zeros((n_opt, n_nod, n_nod)) 294 | 295 | for i in range(n_opt): 296 | T[i, :, :] = single_window_allegiance(M[i, :]) 297 | 298 | return T.mean(axis=0) 299 | 300 | def all_window_allegiance_mean(M): 301 | 302 | n_win = M.shape[2] 303 | n_nod = M.shape[1] 304 | 305 | T = np.zeros((n_win, n_nod, n_nod)) 306 | 307 | for i in range(n_win): 308 | T[i, :, :] = single_window_allegiance_mean(M[:,:,i]) 309 | 310 | return T 311 | 312 | def node_flexibility(node_vector): 313 | n_win = len(node_vector) 314 | count = 0 315 | for i in range(n_win-1): 316 | if node_vector[i] != node_vector[i+1]: 317 | count += 1 318 | return count/n_win 319 | 320 | 321 | def flexibility(matrix): 322 | n_nod = matrix.shape[0] 323 | n_win = matrix.shape[1] 324 | 325 | node_flex = [node_flexibility(elem) for elem in matrix] 326 | return node_flex 327 | 328 | 329 | 330 | def randmio_und(R, itr): 331 | ''' 332 | Edited from aestrivex/bctpy with corrected matrix symetry check 333 | 334 | This function randomizes an undirected network, while preserving the 335 | degree distribution. The function does not preserve the strength 336 | distribution in weighted networks. 337 | Parameters 338 | ---------- 339 | W : NxN np.ndarray 340 | undirected binary/weighted connection matrix 341 | itr : int 342 | rewiring parameter. Each edge is rewired approximately itr times. 343 | Returns 344 | ------- 345 | R : NxN np.ndarray 346 | randomized network 347 | eff : int 348 | number of actual rewirings carried out 349 | ''' 350 | if not np.allclose(R, R.T): 351 | raise BCTParamError("Input must be undirected") 352 | R = R.copy() 353 | n = len(R) 354 | i, j = np.where(np.tril(R)) 355 | k = len(i) 356 | itr *= k 357 | 358 | # maximum number of rewiring attempts per iteration 359 | max_attempts = np.round(n * k / (n * (n - 1))) 360 | # actual number of successful rewirings 361 | eff = 0 362 | 363 | for it in range(int(itr)): 364 | att = 0 365 | while att <= max_attempts: # while not rewired 366 | while True: 367 | e1, e2 = np.random.randint(k, size=(2,)) 368 | while e1 == e2: 369 | e2 = np.random.randint(k) 370 | a = i[e1] 371 | b = j[e1] 372 | c = i[e2] 373 | d = j[e2] 374 | 375 | if a != c and a != d and b != c and b != d: 376 | break # all 4 vertices must be different 377 | 378 | if np.random.random() > .5: 379 | i.setflags(write=True) 380 | j.setflags(write=True) 381 | i[e2] = d 382 | j[e2] = c # flip edge c-d with 50% probability 383 | c = i[e2] 384 | d = j[e2] # to explore all potential rewirings 385 | 386 | # rewiring condition 387 | if not (R[a, d] or R[c, b]): 388 | R[a, d] = R[a, b] 389 | R[a, b] = 0 390 | R[d, a] = R[b, a] 391 | R[b, a] = 0 392 | R[c, b] = R[c, d] 393 | R[c, d] = 0 394 | R[b, c] = R[d, c] 395 | R[d, c] = 0 396 | 397 | j.setflags(write=True) 398 | j[e1] = d 399 | j[e2] = b # reassign edge indices 400 | eff += 1 401 | break 402 | att += 1 403 | 404 | return R, eff -------------------------------------------------------------------------------- /fctools/stats.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy import stats 3 | import pandas as pd 4 | 5 | def m_wei(x, w): 6 | """Weighted Mean""" 7 | return np.sum(x * w) / np.sum(w) 8 | 9 | def cov_wei(x, y, w): 10 | """Weighted Covariance""" 11 | return np.sum(w * (x - m_wei(x, w)) * (y - m_wei(y, w))) / np.sum(w) 12 | 13 | def corr_wei(x, y, w): 14 | """Weighted Correlation""" 15 | return cov_wei(x, y, w) / np.sqrt(cov_wei(x, x, w) * cov_wei(y, y, w)) 16 | 17 | def bootstrap_replicate_1d(data, func): 18 | """Calculate bootstrap replicate""" 19 | return func(np.random.choice(data, size=len(data))) 20 | 21 | def ttest_rel_cond(group, variable, data): 22 | """ Function which calculates paired t-test comparing variable between two task conditions""" 23 | sess = ['ses-1', 'ses-2', 'ses-3', 'ses-4'] 24 | conds = ['1-back', '2-back'] 25 | table = np.zeros((4,2)) 26 | 27 | for i, ses in enumerate(sess): 28 | group_1 = data[(data.Session == ses) & (data.Condition == '1-back') & (data.Group == group)] 29 | group_2 = data[(data.Session == ses) & (data.Condition == '2-back') & (data.Group == group)] 30 | 31 | t, pval = stats.ttest_rel(group_1[variable].values, group_2[variable].values,) 32 | table[i, 0] = t 33 | table[i, 1] = pval 34 | 35 | return pd.DataFrame(table.tolist(), columns = ['statistic', 'pval']) 36 | 37 | 38 | def ttest_rel_sess(group, variable, data): 39 | """ Function which calculates paired t-test comparing variable between each session""" 40 | sess = ['ses-1', 'ses-2', 'ses-3', 'ses-4'] 41 | table = np.zeros((4,4,2)) 42 | 43 | for i, ses1 in enumerate(sess): 44 | for j, ses2 in enumerate(sess): 45 | ses_1 = data[(data.Session == ses1) & (data.Group == group)] 46 | ses_2 = data[(data.Session == ses2) & (data.Group == group)] 47 | 48 | t, pval = stats.ttest_rel(ses_1[variable].values, ses_2[variable].values,) 49 | table[i, j, 0] = t 50 | table[i, j, 1] = pval 51 | 52 | return table 53 | 54 | def ttest_ind_groups(variable, data): 55 | """ Function which calculates two sample t-test comparing variables between groups""" 56 | sess = ['ses-1', 'ses-2', 'ses-3', 'ses-4'] 57 | 58 | table = np.zeros((4,2)) 59 | 60 | for i, ses in enumerate(sess): 61 | group_1 = data[(data.Session == ses) & (data.Group == 'Experimental')] 62 | group_2 = data[(data.Session == ses) & (data.Group == 'Control')] 63 | 64 | t, pval = stats.ttest_ind(group_1[variable].values, group_2[variable].values,) 65 | table[i, 0] = t 66 | table[i, 1] = pval 67 | 68 | return pd.DataFrame(table.tolist(), columns = ['statistic', 'pval']) 69 | 70 | -------------------------------------------------------------------------------- /support/modules.txt: -------------------------------------------------------------------------------- 1 | UNC 2 | UNC 3 | UNC 4 | UNC 5 | UNC 6 | UNC 7 | UNC 8 | UNC 9 | UNC 10 | UNC 11 | UNC 12 | UNC 13 | SOM 14 | SOM 15 | SOM 16 | SOM 17 | SOM 18 | SOM 19 | SOM 20 | SOM 21 | SOM 22 | SOM 23 | SOM 24 | SOM 25 | SOM 26 | SOM 27 | SOM 28 | SOM 29 | SOM 30 | SOM 31 | SOM 32 | SOM 33 | SOM 34 | SOM 35 | SOM 36 | SOM 37 | SOM 38 | SOM 39 | SOM 40 | SOM 41 | SOM 42 | SOM 43 | SOM 44 | SOM 45 | SOM 46 | SOM 47 | CO 48 | CO 49 | CO 50 | CO 51 | CO 52 | CO 53 | CO 54 | CO 55 | CO 56 | CO 57 | CO 58 | CO 59 | CO 60 | CO 61 | AU 62 | AU 63 | AU 64 | AU 65 | AU 66 | AU 67 | AU 68 | AU 69 | AU 70 | AU 71 | AU 72 | AU 73 | AU 74 | DM 75 | DM 76 | DM 77 | DM 78 | DM 79 | DM 80 | DM 81 | DM 82 | DM 83 | DM 84 | UNC 85 | UNC 86 | DM 87 | DM 88 | DM 89 | DM 90 | DM 91 | DM 92 | DM 93 | DM 94 | DM 95 | DM 96 | DM 97 | DM 98 | DM 99 | DM 100 | DM 101 | DM 102 | DM 103 | DM 104 | DM 105 | DM 106 | DM 107 | DM 108 | DM 109 | DM 110 | DM 111 | DM 112 | DM 113 | DM 114 | DM 115 | DM 116 | DM 117 | DM 118 | DM 119 | DM 120 | DM 121 | DM 122 | DM 123 | DM 124 | DM 125 | DM 126 | DM 127 | DM 128 | DM 129 | DM 130 | DM 131 | DM 132 | UNC 133 | MEM 134 | MEM 135 | MEM 136 | MEM 137 | DM 138 | VA 139 | DM 140 | UNC 141 | UNC 142 | UNC 143 | VIS 144 | VIS 145 | VIS 146 | VIS 147 | VIS 148 | VIS 149 | VIS 150 | VIS 151 | VIS 152 | VIS 153 | VIS 154 | VIS 155 | VIS 156 | VIS 157 | VIS 158 | VIS 159 | VIS 160 | VIS 161 | VIS 162 | VIS 163 | VIS 164 | VIS 165 | VIS 166 | VIS 167 | VIS 168 | VIS 169 | VIS 170 | VIS 171 | VIS 172 | VIS 173 | VIS 174 | FP 175 | FP 176 | FP 177 | FP 178 | FP 179 | FP 180 | FP 181 | FP 182 | UNC 183 | UNC 184 | UNC 185 | UNC 186 | FP 187 | FP 188 | FP 189 | FP 190 | FP 191 | FP 192 | FP 193 | FP 194 | FP 195 | FP 196 | FP 197 | FP 198 | FP 199 | FP 200 | FP 201 | FP 202 | FP 203 | SAL 204 | SAL 205 | SAL 206 | SAL 207 | SAL 208 | SAL 209 | SAL 210 | SAL 211 | SAL 212 | SAL 213 | SAL 214 | SAL 215 | SAL 216 | SAL 217 | SAL 218 | SAL 219 | SAL 220 | SAL 221 | MEM 222 | SUB 223 | SUB 224 | SUB 225 | SUB 226 | SUB 227 | SUB 228 | SUB 229 | SUB 230 | SUB 231 | SUB 232 | SUB 233 | SUB 234 | SUB 235 | VA 236 | VA 237 | VA 238 | VA 239 | VA 240 | VA 241 | VA 242 | VA 243 | CER 244 | CER 245 | CER 246 | CER 247 | UNC 248 | UNC 249 | UNC 250 | UNC 251 | DA 252 | DA 253 | UNC 254 | UNC 255 | SOM 256 | DA 257 | DA 258 | DA 259 | DA 260 | DA 261 | DA 262 | DA 263 | DA 264 | DA 265 | -------------------------------------------------------------------------------- /support/onsets_dualnback.csv: -------------------------------------------------------------------------------- 1 | duration,onset,trial_type 2 | 4.00,0.00,intro 3 | 30.00,4.00,1-back 4 | 4.00,34.00,intro 5 | 30.00,38.00,2-back 6 | 4.00,68.00,intro 7 | 30.00,72.00,1-back 8 | 4.00,102.00,intro 9 | 30.00,106.00,2-back 10 | 4.00,136.00,intro 11 | 30.00,140.00,1-back 12 | 4.00,170.00,intro 13 | 30.00,174.00,2-back 14 | 4.00,204.00,intro 15 | 30.00,208.00,1-back 16 | 4.00,238.00,intro 17 | 30.00,242.00,2-back 18 | 4.00,272.00,intro 19 | 30.00,276.00,1-back 20 | 4.00,306.00,intro 21 | 30.00,310.00,2-back 22 | 4.00,340.00,intro 23 | 30.00,344.00,1-back 24 | 4.00,374.00,intro 25 | 30.00,378.00,2-back 26 | 4.00,408.00,intro 27 | 30.00,412.00,1-back 28 | 4.00,442.00,intro 29 | 30.00,446.00,2-back 30 | 4.00,476.00,intro 31 | 30.00,480.00,1-back 32 | 4.00,510.00,intro 33 | 30.00,514.00,2-back 34 | 4.00,544.00,intro 35 | 30.00,548.00,1-back 36 | 4.00,578.00,intro 37 | 30.00,582.00,2-back 38 | 4.00,612.00,intro 39 | 30.00,616.00,1-back 40 | 4.00,646.00,intro 41 | 30.00,650.00,2-back --------------------------------------------------------------------------------