[med-svn] [mne-python] 01/04: Imported Upstream version 0.7~rc1
Andreas Tille
tille at debian.org
Thu Nov 21 21:14:55 UTC 2013
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository mne-python.
commit 3ceaf1717a48e3f6c51a4eb76db845cc0bbac185
Author: Andreas Tille <tille at debian.org>
Date: Thu Nov 21 21:52:07 2013 +0100
Imported Upstream version 0.7~rc1
---
.travis.yml | 35 +
MANIFEST.in | 8 +-
Makefile | 22 +
README.rst | 8 +
bin/mne | 36 +
doc/Makefile | 5 +
doc/source/_static/logo.png | Bin 74269 -> 175727 bytes
doc/source/_templates/layout.html | 1 +
doc/source/cite.rst | 10 +
doc/source/contributing.rst | 127 +-
doc/source/getting_started.rst | 69 +-
doc/source/git_links.inc | 28 +-
doc/source/index.rst | 1 +
doc/source/mne-python.rst | 9 +-
doc/source/python_reference.rst | 59 +-
doc/source/python_tutorial.rst | 30 +-
doc/source/whats_new.rst | 89 +
doc/sphinxext/gen_rst.py | 8 +-
doc/upload_html.sh | 1 +
.../connectivity/plot_cwt_sensor_connectivity.py | 4 +-
.../plot_mne_inverse_coherence_epochs.py | 8 +-
.../plot_mne_inverse_connectivity_spectrum.py | 10 +-
.../plot_mne_inverse_label_connectivity.py | 8 +-
.../connectivity/plot_mne_inverse_psi_visual.py | 2 +-
examples/datasets/README.txt | 5 +
examples/datasets/plot_spm_faces_dataset.py | 118 +
examples/decoding/plot_decoding_csp_space.py | 106 +
examples/decoding/plot_decoding_sensors.py | 24 +-
.../plot_decoding_spatio_temporal_source.py | 2 +-
examples/export/plot_epochs_as_data_frame.py | 8 +-
examples/export/plot_epochs_to_nitime.py | 4 +-
examples/export/plot_evoked_to_nitime.py | 4 +-
examples/export/plot_raw_to_nitime.py | 14 +-
examples/inverse/plot_compute_mne_inverse.py | 12 +-
.../plot_compute_mne_inverse_epochs_in_label.py | 22 +-
.../plot_compute_mne_inverse_raw_in_label.py | 12 +-
.../inverse/plot_compute_mne_inverse_volume.py | 32 +-
examples/inverse/plot_dics_beamformer.py | 89 +
examples/inverse/plot_dics_source_power.py | 79 +
examples/inverse/plot_gamma_map_inverse.py | 9 +-
examples/inverse/plot_label_activation_from_stc.py | 24 +-
examples/inverse/plot_label_from_stc.py | 105 +
examples/inverse/plot_label_source_activations.py | 26 +-
examples/inverse/plot_lcmv_beamformer.py | 29 +-
examples/inverse/plot_lcmv_beamformer_volume.py | 31 +-
examples/inverse/plot_make_inverse_operator.py | 30 +-
examples/inverse/plot_mixed_norm_L21_inverse.py | 12 +-
examples/inverse/plot_morph_data.py | 16 +-
examples/inverse/plot_read_stc.py | 10 +-
examples/inverse/plot_tf_dics.py | 116 +
examples/inverse/plot_tf_lcmv.py | 130 +
.../plot_time_frequency_mixed_norm_inverse.py | 13 +-
examples/plot_channel_epochs_image.py | 10 +-
examples/plot_decimate_head_surface.py | 39 +
examples/plot_define_target_events.py | 20 +-
examples/plot_evoked_delayed_ssp.py | 12 +-
examples/plot_evoked_whitening.py | 3 +-
examples/plot_from_raw_to_epochs_to_evoked.py | 21 +-
.../plot_from_raw_to_multiple_epochs_to_evoked.py | 18 +-
examples/plot_make_forward.py | 54 +
examples/plot_megsim_data.py | 6 +-
examples/plot_megsim_data_single_trial.py | 1 -
examples/plot_read_forward.py | 26 +-
examples/plot_read_noise_covariance_matrix.py | 8 +-
examples/plot_shift_evoked.py | 4 +-
examples/plot_simulate_evoked_data.py | 10 +-
examples/plot_ssp_projs_sensitivity_map.py | 10 +-
examples/plot_ssp_projs_topomaps.py | 4 +-
examples/plot_topo_channel_epochs_image.py | 4 +-
examples/plot_topo_compare_conditions.py | 6 +-
examples/plot_topography.py | 4 +-
examples/preprocessing/plot_find_ecg_artifacts.py | 12 +-
examples/preprocessing/plot_find_eog_artifacts.py | 10 +-
examples/preprocessing/plot_ica_from_epochs.py | 78 +-
examples/preprocessing/plot_ica_from_raw.py | 111 +-
examples/realtime/README.txt | 5 +
examples/realtime/plot_compute_rt_average.py | 64 +
examples/realtime/plot_compute_rt_decoder.py | 111 +
examples/realtime/rt_feedback_client.py | 116 +
examples/realtime/rt_feedback_server.py | 144 +
.../plot_cluster_1samp_test_time_frequency.py | 50 +-
examples/stats/plot_cluster_methods_tutorial.py | 18 +-
examples/stats/plot_cluster_stats_evoked.py | 35 +-
.../stats/plot_cluster_stats_spatio_temporal.py | 28 +-
.../plot_cluster_stats_spatio_temporal_2samp.py | 20 +-
...tats_spatio_temporal_repeated_measures_anova.py | 63 +-
.../stats/plot_cluster_stats_time_frequency.py | 44 +-
...stats_time_frequency_repeated_measures_anova.py | 80 +-
examples/stats/plot_fdr_stats_evoked.py | 28 +-
examples/stats/plot_sensor_permutation_test.py | 22 +-
.../plot_compute_raw_data_spectrum.py | 61 +-
.../plot_compute_source_psd_epochs.py | 12 +-
.../time_frequency/plot_single_trial_spectra.py | 84 +
.../plot_source_label_time_frequency.py | 96 +-
.../time_frequency/plot_source_power_spectrum.py | 14 +-
.../plot_source_space_time_frequency.py | 16 +-
examples/time_frequency/plot_temporal_whitening.py | 26 +-
examples/time_frequency/plot_tfr_topography.py | 6 +-
examples/time_frequency/plot_time_frequency.py | 58 +-
mne/__init__.py | 75 +-
mne/baseline.py | 10 +-
mne/beamformer/__init__.py | 3 +-
mne/beamformer/_dics.py | 587 ++
mne/beamformer/_lcmv.py | 444 +-
mne/beamformer/tests/test_dics.py | 296 +
mne/beamformer/tests/test_lcmv.py | 357 +-
mne/{transforms/tests => commands}/__init__.py | 0
{bin => mne/commands}/mne_browse_raw.py | 23 +-
{bin => mne/commands}/mne_bti2fiff.py | 33 +-
{bin => mne/commands}/mne_clean_eog_ecg.py | 13 +-
{bin => mne/commands}/mne_compute_proj_ecg.py | 141 +-
{bin => mne/commands}/mne_compute_proj_eog.py | 15 +-
{bin => mne/commands}/mne_flash_bem_model.py | 7 +-
{bin => mne/commands}/mne_kit2fiff.py | 32 +-
mne/commands/mne_make_scalp_surfaces.py | 129 +
{bin => mne/commands}/mne_maxfilter.py | 9 +-
{bin => mne/commands}/mne_surf2bem.py | 21 +-
mne/commands/utils.py | 39 +
mne/connectivity/effective.py | 4 +-
mne/connectivity/spectral.py | 21 +-
mne/connectivity/tests/test_effective.py | 25 +-
mne/connectivity/tests/test_spectral.py | 39 +-
mne/coreg.py | 1041 +++
mne/cov.py | 57 +-
mne/cuda.py | 10 +-
mne/data/coil_def.dat | 416 +
mne/datasets/__init__.py | 1 +
mne/datasets/megsim/megsim.py | 7 +-
mne/datasets/sample/__init__.py | 2 +-
mne/datasets/sample/sample.py | 156 +-
mne/datasets/spm_face/__init__.py | 4 +
mne/datasets/spm_face/spm_data.py | 30 +
mne/datasets/{sample/sample.py => utils.py} | 134 +-
mne/decoding/__init__.py | 4 +
mne/decoding/classifier.py | 425 +
mne/decoding/csp.py | 205 +
mne/decoding/mixin.py | 30 +
mne/{ => decoding}/tests/__init__.py | 0
mne/decoding/tests/test_classifier.py | 127 +
mne/decoding/tests/test_csp.py | 97 +
mne/dipole.py | 4 +-
mne/epochs.py | 718 +-
mne/event.py | 218 +-
mne/fiff/__init__.py | 15 +-
mne/fiff/brainvision/__init__.py | 7 +
mne/fiff/brainvision/brainvision.py | 518 ++
mne/fiff/brainvision/tests/__init__.py | 1 +
mne/fiff/brainvision/tests/data/test.eeg | Bin 0 -> 505600 bytes
mne/fiff/brainvision/tests/data/test.vhdr | 142 +
mne/fiff/brainvision/tests/data/test.vmrk | 22 +
mne/fiff/brainvision/tests/data/test_bin_raw.fif | Bin 0 -> 526560 bytes
mne/fiff/brainvision/tests/data/test_elp.txt | 45 +
mne/fiff/brainvision/tests/test_brainvision.py | 75 +
mne/fiff/bti/raw.py | 50 +-
mne/fiff/bti/read.py | 3 -
mne/fiff/bti/tests/test_bti.py | 13 +-
mne/fiff/compensator.py | 15 +-
mne/fiff/constants.py | 88 +-
mne/fiff/cov.py | 14 +-
mne/fiff/ctf.py | 5 +-
mne/fiff/diff.py | 5 +-
mne/fiff/edf/__init__.py | 7 +
mne/fiff/edf/edf.py | 594 ++
mne/{ => fiff/edf}/tests/__init__.py | 0
mne/fiff/edf/tests/data/biosemi.hpts | 82 +
mne/fiff/edf/tests/data/test.bdf | 3222 +++++++
mne/fiff/edf/tests/data/test.edf | 9591 ++++++++++++++++++++
mne/fiff/edf/tests/data/test_bdf_eeglab.mat | Bin 0 -> 447053 bytes
mne/fiff/edf/tests/data/test_edf_eeglab.mat | Bin 0 -> 799941 bytes
mne/fiff/edf/tests/data/test_eeglab.mat | Bin 0 -> 447053 bytes
mne/fiff/edf/tests/test_edf.py | 87 +
mne/fiff/evoked.py | 57 +-
mne/fiff/kit/__init__.py | 1 +
mne/fiff/kit/constants.py | 22 +-
mne/fiff/kit/coreg.py | 306 +-
mne/fiff/kit/kit.py | 390 +-
mne/fiff/kit/tests/data/trans-sample.fif | Bin 0 -> 420 bytes
mne/fiff/kit/tests/test_coreg.py | 75 +
mne/fiff/kit/tests/test_kit.py | 91 +-
mne/fiff/matrix.py | 9 +-
mne/fiff/meas_info.py | 162 +-
mne/fiff/open.py | 4 +-
mne/fiff/pick.py | 88 +-
mne/fiff/proj.py | 56 +-
mne/fiff/raw.py | 328 +-
mne/fiff/tag.py | 21 +-
mne/fiff/tests/data/fsaverage-fiducials.fif | Bin 0 -> 260 bytes
mne/fiff/tests/data/sample-audvis-raw-trans.txt | 4 +
mne/fiff/tests/data/test-lh.label | 101 +
mne/fiff/tests/data/test-rh.label | 102 +
mne/fiff/tests/data/test_chpi_raw_hp.txt | 5 +
mne/fiff/tests/data/test_chpi_raw_sss.fif | Bin 0 -> 13071083 bytes
mne/fiff/tests/test_compensator.py | 2 +
mne/fiff/tests/test_evoked.py | 4 +-
mne/fiff/tests/test_meas_info.py | 66 +
mne/fiff/tests/test_raw.py | 180 +-
mne/fiff/tree.py | 5 +-
mne/fiff/write.py | 42 +-
mne/filter.py | 28 +-
mne/fixes.py | 26 +
mne/forward/__init__.py | 12 +
mne/forward/_compute_forward.py | 346 +
mne/forward/_make_forward.py | 494 +
mne/{ => forward}/forward.py | 327 +-
mne/{ => forward}/tests/__init__.py | 0
mne/{ => forward}/tests/test_forward.py | 153 +-
mne/forward/tests/test_make_forward.py | 227 +
mne/inverse_sparse/_gamma_map.py | 5 +-
mne/inverse_sparse/mxne_debiasing.py | 6 +-
mne/inverse_sparse/mxne_inverse.py | 5 +-
mne/inverse_sparse/mxne_optim.py | 14 +-
mne/inverse_sparse/tests/test_gamma_map.py | 18 +-
mne/inverse_sparse/tests/test_mxne_debiasing.py | 2 +-
mne/inverse_sparse/tests/test_mxne_inverse.py | 71 +-
mne/inverse_sparse/tests/test_mxne_optim.py | 10 +-
mne/label.py | 410 +-
mne/layouts/layout.py | 10 +-
mne/minimum_norm/__init__.py | 12 +-
mne/minimum_norm/inverse.py | 257 +-
mne/minimum_norm/tests/test_inverse.py | 97 +-
mne/minimum_norm/tests/test_time_frequency.py | 28 +-
mne/minimum_norm/time_frequency.py | 97 +-
mne/parallel.py | 72 +-
mne/preprocessing/__init__.py | 4 +-
mne/preprocessing/ecg.py | 122 +-
mne/preprocessing/eog.py | 25 +-
mne/preprocessing/ica.py | 660 +-
mne/preprocessing/maxfilter.py | 27 +-
mne/preprocessing/peak_finder.py | 10 +-
mne/preprocessing/ssp.py | 104 +-
mne/preprocessing/stim.py | 15 +-
mne/preprocessing/tests/test_ica.py | 261 +-
mne/preprocessing/tests/test_ssp.py | 51 +-
mne/preprocessing/tests/test_stim.py | 54 +-
mne/proj.py | 59 +-
mne/realtime/__init__.py | 13 +
mne/realtime/client.py | 370 +
mne/realtime/epochs.py | 398 +
mne/realtime/mockclient.py | 175 +
mne/realtime/stim_server_client.py | 289 +
mne/{ => realtime}/tests/__init__.py | 0
mne/realtime/tests/test_mockclient.py | 58 +
mne/realtime/tests/test_stim_client_server.py | 63 +
mne/selection.py | 5 +-
mne/simulation/__init__.py | 4 +-
mne/simulation/tests/test_evoked.py | 5 +-
mne/simulation/tests/test_source.py | 42 +-
mne/source_estimate.py | 1152 +--
mne/source_space.py | 968 +-
mne/stats/__init__.py | 14 +-
mne/stats/cluster_level.py | 172 +-
mne/stats/parametric.py | 19 +-
mne/stats/tests/test_cluster_level.py | 223 +-
mne/stats/tests/test_parametric.py | 4 +-
mne/surface.py | 961 +-
mne/tests/__init__.py | 3 +
mne/tests/test_coreg.py | 154 +
mne/tests/test_cov.py | 20 +-
mne/tests/test_dipole.py | 4 +-
mne/tests/test_epochs.py | 84 +-
mne/tests/test_event.py | 44 +-
mne/tests/test_filter.py | 17 +-
mne/tests/test_label.py | 126 +-
mne/tests/test_misc.py | 2 +-
mne/tests/test_proj.py | 11 +-
mne/tests/test_source_estimate.py | 207 +-
mne/tests/test_source_space.py | 368 +-
mne/tests/test_surface.py | 84 +-
mne/tests/test_transforms.py | 62 +
mne/tests/test_utils.py | 53 +-
mne/tests/test_viz.py | 187 +-
mne/time_frequency/__init__.py | 3 +-
mne/time_frequency/csd.py | 258 +
mne/time_frequency/multitaper.py | 28 +-
mne/time_frequency/psd.py | 101 +-
mne/time_frequency/stft.py | 5 +-
mne/time_frequency/tests/test_csd.py | 163 +
mne/time_frequency/tests/test_psd.py | 54 +-
mne/time_frequency/tfr.py | 11 +-
mne/{transforms => }/transforms.py | 176 +-
mne/transforms/__init__.py | 2 -
mne/transforms/coreg.py | 67 -
mne/transforms/tests/test_coreg.py | 20 -
mne/transforms/tests/test_transforms.py | 31 -
mne/utils.py | 225 +-
mne/viz.py | 1436 ++-
setup.py | 50 +-
287 files changed, 34137 insertions(+), 5036 deletions(-)
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..c61d0f0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,35 @@
+language: python
+env:
+ - COVERAGE=--with-coverage MNE_FORCE_SERIAL=1 MNE_SKIP_SAMPLE_DATASET_TESTS=1
+python:
+ - "2.7"
+virtualenv:
+ system_site_packages: true
+before_install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq python-scipy python-nose
+ - sudo apt-get install python-pip
+ - sudo apt-get install python-nibabel python-nitime python-pandas
+ - sudo pip install scikit-learn
+install:
+ - if [ "${COVERAGE}" == "--with-coverage" ]; then sudo pip install coverage; fi
+ - if [ "${COVERAGE}" == "--with-coverage" ]; then sudo pip install coveralls; fi
+ - python setup.py build
+ - python setup.py install
+ - SRC_DIR=$(pwd)
+ - cd ~
+ - MNE_DIR=$(python -c 'import mne;print mne.__path__[0]')
+ - ln -s ${SRC_DIR}/mne/fiff/tests/data ${MNE_DIR}/fiff/tests/data
+ - ln -s ${SRC_DIR}/mne/fiff/bti/tests/data ${MNE_DIR}/fiff/bti/tests/data
+ - ln -s ${SRC_DIR}/mne/fiff/edf/tests/data ${MNE_DIR}/fiff/edf/tests/data
+ - ln -s ${SRC_DIR}/mne/fiff/kit/tests/data ${MNE_DIR}/fiff/kit/tests/data
+ - ln -s ${SRC_DIR}/mne/fiff/brainvision/tests/data ${MNE_DIR}/fiff/brainvision/tests/data
+script:
+ - cd ${MNE_DIR}/../
+ - TEST="nosetests -v --exe mne"
+ - TEST_COVER="nosetests -v --exe --with-coverage --cover-package=mne
+ --cover-html --cover-html-dir=coverage mne"
+ - if [ "${COVERAGE}" == "--with-coverage" ]; then ${TEST};
+ else ${TEST_COVER}; fi
+after_success:
+ - if [ "${COVERAGE}" == "--with-coverage" ]; then coveralls; fi
diff --git a/MANIFEST.in b/MANIFEST.in
index 9593ea5..f8733c9 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,12 +4,14 @@ include mne/__init__.py
recursive-include examples *.py
recursive-include examples *.txt
recursive-include mne *.py
-# recursive-include mne/fiff/tests/data *
-recursive-exclude mne/fiff/tests/data *
-recursive-exclude mne/fiff/bti/tests/data *
recursive-include mne/data *.sel
recursive-include mne/data *.fif.gz
recursive-include mne/layouts *.lout
recursive-include mne/layouts *.lay
recursive-exclude examples/MNE-sample-data *
+# recursive-include mne/fiff/tests/data *
+recursive-exclude mne/fiff/tests/data *
+recursive-exclude mne/fiff/bti/tests/data *
recursive-exclude mne/fiff/kit/tests/data *
+recursive-exclude mne/fiff/edf/tests/data *
+recursive-exclude mne/fiff/brainvision/tests/data *
diff --git a/Makefile b/Makefile
index 48be1ec..a90fe4a 100755
--- a/Makefile
+++ b/Makefile
@@ -39,6 +39,16 @@ $(CURDIR)/examples/MNE-sample-data/MEG/sample/sample_audvis_raw.fif:
test: in sample_data
$(NOSETESTS) mne
+test-no-sample: in
+ @MNE_SKIP_SAMPLE_DATASET_TESTS=true \
+ $(NOSETESTS) mne
+
+
+test-no-sample-with-coverage: in
+ rm -rf coverage .coverage
+ @MNE_SKIP_SAMPLE_DATASET_TESTS=true \
+ $(NOSETESTS) --with-coverage --cover-package=mne --cover-html --cover-html-dir=coverage
+
test-doc: sample_data
$(NOSETESTS) --with-doctest --doctest-tests --doctest-extension=rst doc/ doc/source/
@@ -50,6 +60,9 @@ test-profile: sample_data
$(NOSETESTS) --with-profile --profile-stats-file stats.pf mne
hotshot2dot stats.pf | dot -Tpng -o profile.png
+test-mem: in sample_data
+ ulimit -v 1097152 && $(NOSETESTS)
+
trailing-spaces:
find . -name "*.py" | xargs perl -pi -e 's/[ \t]*$$//'
@@ -65,3 +78,12 @@ codespell:
# The *.fif had to be there twice to be properly ignored (!)
codespell.py -w -i 3 -S="*.fif,*.fif,*.eve,*.gz,*.tgz,*.zip,*.mat,*.stc,*.label,*.w,*.bz2,*.coverage,*.annot,*.sulc,*.log,*.local-copy,*.orig_avg,*.inflated_avg,*.gii" ./dictionary.txt -r .
+manpages:
+ @echo "I: generating manpages"
+ set -e; mkdir -p build/manpages && \
+ cd bin && for f in mne*; do \
+ descr=$$(grep -h -e "^ *'''" -e 'DESCRIP =' $$f -h | sed -e "s,.*' *\([^'][^']*\)'.*,\1,g" | head -n 1); \
+ PYTHONPATH=../ \
+ help2man -n "$$descr" --no-discard-stderr --no-info --version-string "$(uver)" ./$$f \
+ >| ../build/manpages/$$f.1; \
+ done
diff --git a/README.rst b/README.rst
index 9dad435..cd7b1db 100644
--- a/README.rst
+++ b/README.rst
@@ -1,5 +1,13 @@
+
.. -*- mode: rst -*-
+
+|Travis|_
+
+.. |Travis| image:: https://api.travis-ci.org/mne-tools/mne-python.png?branch=master
+.. _Travis: https://travis-ci.org/mne-tools/mne-python
+
+
`mne-python <http://martinos.org/mne/mne-python.html>`_
=======================================================
diff --git a/bin/mne b/bin/mne
new file mode 100755
index 0000000..d322ada
--- /dev/null
+++ b/bin/mne
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+import sys
+import glob
+import subprocess
+import os.path as op
+
+import mne
+
+mne_bin_dir = op.dirname(mne.__file__)
+valid_commands = sorted(glob.glob(op.join(mne_bin_dir, 'commands', 'mne_*.py')))
+valid_commands = [c.split(op.sep)[-1][4:-3] for c in valid_commands]
+
+def print_help():
+ print "Usage : mne command options\n"
+ print "Accepted commands :\n"
+ for c in valid_commands:
+ print "\t- %s" % c
+ print "\nExample : mne browse_raw --raw sample_audvis_raw.fif"
+ print "\nGetting help example : mne compute_proj_eog -h"
+ sys.exit(0)
+
+if len(sys.argv) == 1:
+ print_help()
+elif ("help" in sys.argv[1] or "-h" in sys.argv[1]):
+ print_help()
+elif sys.argv[1] == "--version":
+ print "MNE %s" % mne.__version__
+elif sys.argv[1] not in valid_commands:
+ print 'Invalid command: "%s"\n' % sys.argv[1]
+ print_help()
+ sys.exit(0)
+else:
+ cmd = sys.argv[1]
+ cmd_path = op.join(mne_bin_dir, 'commands', 'mne_%s.py' % cmd)
+ sys.exit(subprocess.call([cmd_path] + sys.argv[2:]))
diff --git a/doc/Makefile b/doc/Makefile
index c3d4404..96a8dbc 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -39,6 +39,11 @@ html:
@echo
@echo "Build finished. The HTML pages are in build/html."
+html-noplot:
+ $(SPHINXBUILD) -D plot_gallery=False -b html $(ALLSPHINXOPTS) build/html
+ @echo
+ @echo "Build finished. The HTML pages are in build/html/stable."
+
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) build/dirhtml
@echo
diff --git a/doc/source/_static/logo.png b/doc/source/_static/logo.png
index 4b86571..d90ddc0 100644
Binary files a/doc/source/_static/logo.png and b/doc/source/_static/logo.png differ
diff --git a/doc/source/_templates/layout.html b/doc/source/_templates/layout.html
index 8bbdd51..85b0125 100755
--- a/doc/source/_templates/layout.html
+++ b/doc/source/_templates/layout.html
@@ -41,6 +41,7 @@
<li><a href="{{ pathto('index') }}">Home</a> | </li>
<li><a href="{{ pathto('manual') }}">Manual</a> | </li>
<li><a href="{{ pathto('mne-python') }}">Python</a> | </li>
+ <li><a href="{{ pathto('cite') }}">Cite MNE</a> | </li>
<!-- <li><a href="{{ pathto('search') }}">Search</a></li> -->
{% endblock %}
diff --git a/doc/source/cite.rst b/doc/source/cite.rst
new file mode 100644
index 0000000..7ca0308
--- /dev/null
+++ b/doc/source/cite.rst
@@ -0,0 +1,10 @@
+.. _cite:
+
+Cite MNE and MNE-Python
+-----------------------
+
+If you use in your research the implementations provided by the MNE software you should cite:
+
+ - [1] A. Gramfort, M. Luessi, E. Larson, D. Engemann, D. Strohmeier, C. Brodbeck, L. Parkkonen, M. Hämäläinen, `MNE software for processing MEG and EEG data <http://www.ncbi.nlm.nih.gov/pubmed/24161808>`_, NeuroImage, 2013, ISSN 1053-8119, `[DOI] <http://dx.doi.org/10.1016/j.neuroimage.2013.10.027>`_
+
+You should as well cite the related method papers, some of which are listed in :ref:`ch_reading`.
diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst
index 8e9b86c..b420a6e 100644
--- a/doc/source/contributing.rst
+++ b/doc/source/contributing.rst
@@ -14,6 +14,27 @@ of the users who use the package.
page as the maintainers about changes or enhancements before too much
coding is done saves everyone time and effort!
+What you will need
+------------------
+
+#. A Unix (Linux or Mac OS) box: `MNE command line utilities`_ and Freesurfer_
+ that are required to make the best out of this toolbox require a Unix platform.
+
+#. A good python editor: Spyder_ IDE is suitable for those migrating from
+ Matlab. EPD_ and Anaconda_ both ship Spyder and all its dependencies. For
+ Mac users, TextMate_ and `Sublime Text`_ are good choices. `Sublime Text`_
+ is available on all three major platforms.
+
+#. Basic scientific tools in python: numpy_, scipy_, matplotlib_
+
+#. Development related tools: nosetests_, coverage_, mayavi_, sphinx_,
+ pep8_, and pyflakes_
+
+#. Other useful packages: pysurfer_, nitime_, pandas_, PIL_, PyDICOM_,
+ joblib_, nibabel_, and scikit-learn_
+
+#. External tools: `MNE command line utilities`_, Freesurfer_, and `mne-scripts`_
+
General code guidelines
-----------------------
@@ -131,8 +152,8 @@ in principle also fork a different one, such as ``mne-matlab```):
Now, after a short pause and some 'Hardcore forking action', you should
find yourself at the home page for your own forked copy of mne-python_.
-Setting up the fork to work on
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Setting up the fork and the working directory
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Briefly, this is done using::
@@ -146,6 +167,47 @@ These steps can be broken out to be more explicit as:
git clone git at github.com:your-user-name/mne-python.git
+#. Create a symbolic link to your mne directory::
+
+ To find the directory in which python packages are installed, go to python
+ and type::
+
+ import site; site.getsitepackages()
+
+ This gives two directories::
+
+ ['/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
+
+ When you write examples and import the MNE modules, this is where python
+ searches and imports them from. If you want to avoid installing the
+ package again when you make changes in your source code, it is better to
+ create a symbolic link from the installation directory to the ``mne/``
+ folder containing your source code.
+
+ First, check if there are any ``mne`` or ``mne-*.egg-info`` files in
+ these directories and delete them. Then, find the user directory for
+ installing python packages::
+
+ import site; site.getusersitepackages()
+
+ This might give for instance::
+
+ '~/.local/lib/python2.7/site-packages'
+
+ Then, make a symbolic link to your working directory::
+
+ ln -s <path to mne-python>/mne ~/.local/lib/python2.7/site-packages/mne
+
+ Since you make a symbolic link to the local directory, you won't require
+ root access while editing the files and the changes in your working
+ directory are automatically reflected in the installation directory. To
+ verify that it works, go to a directory other than the installation
+ directory, run ipython, and then type ``import mne; print mne.__path__``.
+ This will show you from where it imported MNE-Python.
+
+ Now, whenever you make any changes to the code, just restart the
+ ipython kernel for the changes to take effect.
+
#. Change directory to your new repo::
cd mne-python
@@ -186,7 +248,18 @@ These steps can be broken out to be more explicit as:
origin git at github.com:your-user-name/mne-python.git (fetch)
origin git at github.com:your-user-name/mne-python.git (push)
- Your fork is now set up correctly, and you are ready to hack away.
+ Your fork is now set up correctly.
+
+#. Ensure unit tests pass and html files can be compiled
+
+ Make sure before starting to code that all unit tests pass and the
+ html files in the ``doc/`` directory can be built without errors. To build
+ the html files, first go the ``doc/`` directory and then type::
+
+ make html
+
+ Once it is compiled for the first time, subsequent compiles will only
+ recompile what has changed. That's it! You are now ready to hack away.
Workflow summary
----------------
@@ -646,4 +719,52 @@ and the history looks now like this::
If it went wrong, recovery is again possible as explained :ref:`above
<recovering-from-mess-up>`.
+Fetching a pull request
+^^^^^^^^^^^^^^^^^^^^^^^
+
+To fetch a pull request on the main repository to your local working
+directory as a new branch, just do::
+
+ git fetch upstream pull/<pull request number>/head:<local-branch>
+
+As an example, to pull the realtime pull request which has a url
+``https://github.com/mne-tools/mne-python/pull/615/``, do::
+
+ git fetch upstream pull/615/head:realtime
+
+If you want to fetch a pull request to your own fork, replace
+``upstream`` with ``origin``. That's it!
+
+Adding example to example gallery
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Add the example to the correct subfolder in the ``examples/`` directory and
+prefix the file with ``plot_``. To make sure that the example renders correctly,
+run ``make html`` in the ``doc/`` folder
+
+Editing \*.rst files
+^^^^^^^^^^^^^^^^^^^^
+
+These are reStructuredText files. Consult the Sphinx documentation to learn
+more about editing them.
+
+Troubleshooting
+---------------
+
+Listed below are miscellaneous issues that you might face:
+
+Missing files in examples or unit tests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the unit tests fail due to missing files, you may need to run
+`mne-scripts`_ on the sample dataset. Go to ``bash`` if you are using some
+other shell. Then, execute all three shell scripts in the
+``sample-data/`` directory within ``mne-scripts/``.
+
+Cannot import class from a new \*.py file
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You need to update the corresponding ``__init__.py`` file and then
+restart the ipython kernel.
+
.. include:: links.inc
diff --git a/doc/source/getting_started.rst b/doc/source/getting_started.rst
index 5ef305c..79c4149 100644
--- a/doc/source/getting_started.rst
+++ b/doc/source/getting_started.rst
@@ -30,30 +30,79 @@ Outside the Martinos Center
---------------------------
MNE is written in pure Python making it easy to setup of
-any machine with Python >=2.6, Numpy >= 1.4, Scipy >= 0.7.2
+any machine with Python >=2.6, NumPy >= 1.4, SciPy >= 0.7.2
and matplotlib >= 1.1.0.
-Some isolated functions (e.g. filtering with firwin2 require Scipy >= 0.9).
+Some isolated functions (e.g. filtering with firwin2) require SciPy >= 0.9.
-For a fast and up to date scientific Python environment you
-can install EPD available at:
+To run all documentation examples the following additional packages are required:
-http://www.enthought.com/products/epd.php
+ * PySurfer (for visualization of source estimates on cortical surfaces)
-EPD is free for academic purposes. If you cannot benefit from the
+ * scikit-learn (for supervised and unsupervised machine learning functionality)
+
+ * pandas >= 0.8 (for export to tabular data structures like excel files)
+
+Note. For optimal performance we recommend installing recent versions of
+NumPy (> 1.7), SciPy (> 0.10) and scikit-learn (>= 0.14).
+
+For a fast and up to date scientific Python environment that resolves all
+dependencies you can install Enthought Canopy available at:
+
+https://www.enthought.com/products/canopy/
+
+Canopy is free for academic purposes. If you cannot benefit from the
an academic license and you don't want to pay for it, you can
-use EPD free which is a lightweight version (no 3D visualization
+use Canopy express which is a lightweight version (no 3D visualization
support for example):
-http://www.enthought.com/products/epd_free.php
+https://www.enthought.com/store/
+
+Note that we explicitly support the following Python setups since they reflect our
+development environments and functionality is best tested for them:
+
+ * EPD 7.3 (Mac, Linux)
+
+ * Canopy >= 1.0 (Mac, Linux)
+
+ * Anaconda (Mac)
+
+ * Debian / Ubuntu standard system Python + Scipy stack
+
+
+Note. To make Anaconda working with all examples and our test-suite a few
+manual adjustments might be necessary. This may require compiling the recent
+matplotlib development verion (http://goo.gl/bFZHhX, http://goo.gl/S81KHv)
+and manually adjusting the python interpreter invoked by the nosetests and
+the sphinx-build 'binaries' (http://goo.gl/Atqh26).
+Tested on a recent MacBook Pro running Mac OS X 10.8
+
+If you use another Python setup and you encounter some difficulties please
+report them on the MNE mailing list or on github to get assistance.
To test that everything works properly, open up IPython::
ipython
+
Although all of the examples in this documentation are in the style
-of the standard Python interpreter, the use of IPython is highly
-recommended.
+of the standard Python interpreter, the use of IPython with the pylab option
+is highly recommended. In addition, for the setups listed above we would
+strongly recommend to use the QT matplotlib backend for fast and correct rendering::
+
+ ipython --pylab qt
+
+
+On Linux, for example, QT is the only matplotlib backend for which 3D rendering
+will work correctly. On Mac OS X for other backends certain matplotlib functions
+might not work as expected.
+
+To take full advantage of MNE-Python's visualization capacities in combination
+with IPython notebooks and inline displaying, please explicitly add the
+following magic method invocation to your notebook or configure your notebook
+runtime accordingly.
+
+ %pylab inline
Now that you have a working Python environment you can install MNE.
diff --git a/doc/source/git_links.inc b/doc/source/git_links.inc
index 478f7cf..15a0c02 100644
--- a/doc/source/git_links.inc
+++ b/doc/source/git_links.inc
@@ -55,9 +55,35 @@
.. other stuff
.. _python: http://www.python.org
-.. _spyder: http://spyder-ide.blogspot.com/
+
+.. python packages
.. _pep8: http://pypi.python.org/pypi/pep8
.. _pyflakes: http://pypi.python.org/pypi/pyflakes
+.. _coverage: https://pypi.python.org/pypi/coverage
+.. _nosetests: https://nose.readthedocs.org/en/latest/
+.. _mayavi: http://mayavi.sourceforge.net/
+.. _nitime: http://nipy.org/nitime/
+.. _joblib: https://pypi.python.org/pypi/joblib
+.. _scikit-learn: http://scikit-learn.org/stable/
+.. _pysurfer: http://pysurfer.github.io/
+.. _pyDICOM: https://pypi.python.org/pypi/pydicom/
+.. _matplotlib: http://matplotlib.org/
+.. _sphinx: http://sphinx-doc.org/
+.. _pandas: http://pandas.pydata.org/
+.. _PIL: https://pypi.python.org/pypi/PIL
+
+.. python editors
+.. _spyder: http://spyder-ide.blogspot.com/
+.. _anaconda: http://www.continuum.io/downloads
+.. _EPD: https://www.enthought.com/products/epd/
+.. _textmate: http://macromates.com/
+.. _sublime text: http://www.sublimetext.com/
+
+.. mne stuff
+.. _mne command line utilities: http://www.nmr.mgh.harvard.edu/martinos/userInfo/data/MNE_register/
+.. _mne-scripts: https://github.com/mne-tools/mne-scripts/
+
+.. _Freesurfer: http://surfer.nmr.mgh.harvard.edu/fswiki/DownloadAndInstall/
.. |emdash| unicode:: U+02014
diff --git a/doc/source/index.rst b/doc/source/index.rst
index bb2dff5..ed89936 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -45,4 +45,5 @@ simplified BSD license.
manual
mne-python
+ cite
diff --git a/doc/source/mne-python.rst b/doc/source/mne-python.rst
index b26b91e..94fe4fd 100644
--- a/doc/source/mne-python.rst
+++ b/doc/source/mne-python.rst
@@ -16,4 +16,11 @@ MNE with Python
.. raw:: html
- <a class="twitter-timeline" href="https://twitter.com/mne_python" data-widget-id="317730454184804352">Tweets by @mne_python</a>
+ <div>
+ <div style="width: 40%; float: left; padding: 20px;">
+ <a class="twitter-timeline" href="https://twitter.com/mne_python" data-widget-id="317730454184804352">Tweets by @mne_python</a>
+ </div>
+ <div style="width: 40%; float: left; padding: 20px;">
+ <script type="text/javascript" src="http://www.ohloh.net/p/586838/widgets/project_basic_stats.js"></script>
+ </div>
+ </div>
diff --git a/doc/source/python_reference.rst b/doc/source/python_reference.rst
index c85e9c4..ba12951 100644
--- a/doc/source/python_reference.rst
+++ b/doc/source/python_reference.rst
@@ -29,7 +29,17 @@ Classes
Label
BiHemiLabel
preprocessing.ICA
-
+ decoding.TransformerMixin
+ decoding.CSP
+ decoding.Scaler
+ decoding.ConcatenateChannels
+ decoding.FilterEstimator
+ decoding.PSDEstimator
+ realtime.RtEpochs
+ realtime.RtClient
+ realtime.MockRtClient
+ realtime.StimServer
+ realtime.StimClient
Logging and Configuration
=========================
@@ -81,6 +91,8 @@ Functions:
:template: function.rst
parse_config
+ decimate_surfaces
+ read_bem_solution
read_bem_surfaces
read_cov
read_dip
@@ -88,6 +100,7 @@ Functions:
read_events
read_forward_solution
read_label
+ read_morph_map
read_proj
read_reject_parameters
read_selection
@@ -173,6 +186,7 @@ Visualization
plot_ica_panel
plot_image_epochs
plot_raw
+ plot_raw_psds
plot_source_estimates
plot_sparse_source_estimates
plot_topo
@@ -293,6 +307,8 @@ Sensor Space Data
:toctree: generated/
:template: function.rst
+ fiff.concatenate_raws
+ fiff.get_chpi_positions
fiff.pick_channels
fiff.pick_channels_cov
fiff.pick_channels_forward
@@ -321,6 +337,21 @@ Covariance
write_cov
+MRI Processing
+==============
+
+.. currentmodule:: mne
+
+.. autosummary::
+ :toctree: generated/
+ :template: function.rst
+
+ create_default_subject
+ scale_mri
+ scale_labels
+ scale_source_space
+
+
Forward Modeling
================
@@ -330,16 +361,21 @@ Forward Modeling
:toctree: generated/
:template: function.rst
+ add_source_space_distances
apply_forward
apply_forward_raw
average_forward_solutions
+ convert_forward_solution
do_forward_solution
+ make_forward_solution
read_bem_surfaces
read_forward_solution
read_trans
read_source_spaces
read_surface
sensitivity_map
+ setup_source_space
+ setup_volume_source_space
write_bem_surface
write_trans
@@ -409,6 +445,9 @@ Inverse Solutions
lcmv
lcmv_epochs
lcmv_raw
+ dics
+ dics_epochs
+ dics_source_power
Source Space Data
@@ -456,6 +495,7 @@ Time-Frequency
ar_raw
compute_raw_psd
+ compute_epochs_psd
iir_filter_raw
induced_power
morlet
@@ -545,3 +585,20 @@ Simulation
generate_evoked
generate_sparse_stc
select_source_in_label
+
+Decoding
+========
+
+:py:mod:`mne.decoding`:
+
+.. automodule:: mne.decoding
+ :no-members:
+
+
+Realtime
+========
+
+:py:mod:`mne.realtime`:
+
+.. automodule:: mne.realtime
+ :no-members:
diff --git a/doc/source/python_tutorial.rst b/doc/source/python_tutorial.rst
index d9cae03..039c098 100644
--- a/doc/source/python_tutorial.rst
+++ b/doc/source/python_tutorial.rst
@@ -11,11 +11,6 @@ contrasts, statistics, time-frequency analysis etc.)
It uses the same files as standard MNE unix commands:
no need to convert your files to a new system or database.
-What you're not supposed to do with MNE Python
-----------------------------------------------
-
- - **Forward modeling**: BEM computation and mesh creation (see :ref:`ch_forward`)
-
What you can do with MNE Python
-------------------------------
@@ -24,15 +19,24 @@ What you can do with MNE Python
- **Averaging** to get Evoked data
- **Compute SSP pojectors** to remove ECG and EOG artifacts
- **Compute ICA** to remove artifacts or select latent sources.
- - **Linear inverse solvers** (dSPM, MNE)
+ - **Forward modeling**: BEM computation and mesh creation (see :ref:`ch_forward`)
+ - **Linear inverse solvers** (dSPM, sLORETA, MNE, LCMV, DICS)
+ - **Sparse inverse solvers** (L1/L2 mixed norm MxNE, Gamma Map, Time-Frequency MxNE)
- **Connectivity estimation** in sensor and source space
- - **MNE source estimates visualization**
+ - **Visualization of sensor and source space data**
- **Time-frequency** analysis with Morlet wavelets (induced power, phase lock value) also in the source space
- **Spectrum estimation** using multi-taper method
- **Compute contrasts** between conditions, between sensors, across subjects etc.
- **Non-parametric statistics** in time, space and frequency (including cluster-level)
- **Scripting** (batch and parallel computing)
+What you're not supposed to do with MNE Python
+----------------------------------------------
+
+ - **Dipole fitting** use MNE or other designated software instead.
+ - **Boundary Element Modeling** use MNE and Freesurfer.
+
+
.. note:: Package based on the FIF file format from Neuromag but can work with CTF and 4D after conversion to FIF.
@@ -69,8 +73,8 @@ Make life easier
~~~~~~~~~~~~~~~~
For optimal performance we recommend using numpy / scipy with the multi-threaded
- ATLAS, gotoblas2, or intel MKL. The EPD python distribution for example ships with
- tested MKL-compiled numpy / scipy versions. Depending on the use case and your system
+ ATLAS, gotoblas2, or intel MKL. For example, the Enthought Canopy and the Anaconda distributions
+ ship with tested MKL-compiled numpy / scipy versions. Depending on the use case and your system
this may speed up operations by a factor greater than 10.
The expected location for the MNE-sample data is my-path-to/mne-python/examples.
@@ -89,9 +93,9 @@ From raw data to evoked data
.. _ipython: http://ipython.scipy.org/
-Now, launch `ipython`_ (Advanced Python shell)::
+Now, launch `ipython`_ (Advanced Python shell) using the QT backend which best supported across systems::
- $ ipython -pylab -wthread
+ $ ipython -pylab -qt
First, load the mne package:
@@ -136,6 +140,8 @@ Read data from file:
Ready.
>>> print raw
<Raw | n_channels x n_times : 376 x 41700>
+ >>> print raw.info # doctest:+ELLIPSIS
+ <Info | 19 non-empty ...
Look at the channels in raw:
@@ -404,9 +410,11 @@ What else can you do?
- compute Independent Component Analysis (ICA) to remove artifacts or select latent sources
- estimate noise covariance matrix from Raw and Epochs
- visualize cross-trial response dynamics using epochs images
+ - compute forward solutions
- estimate power in the source space
- estimate connectivity in sensor and source space
- morph stc from one brain to another for group studies
+ - compute mass univariate statistics base on custom contrasts
- visualize source estimates
- export raw, epochs, and evoked data to other python data analysis libraries i.e. pandas and nitime
diff --git a/doc/source/whats_new.rst b/doc/source/whats_new.rst
index d2f5687..45c535c 100644
--- a/doc/source/whats_new.rst
+++ b/doc/source/whats_new.rst
@@ -1,6 +1,93 @@
What's new
==========
+.. _changes_0_7:
+
+Current
+-------
+
+Changelog
+~~~~~~~~~
+
+ - Add capability for real-time feedback via trigger codes using StimServer and StimClient classes by `Mainak Jas`_
+
+ - New decoding module for MEG analysis containing sklearn compatible transformers by `Mainak Jas`_ and `Alex Gramfort`_
+
+ - New realtime module containing RtEpochs, RtClient and MockRtClient class by `Martin Luessi`_, Christopher Dinh, `Alex Gramfort`_, `Denis Engemann`_ and `Mainak Jas`_
+
+ - Allow picking normal orientation in LCMV beamformers by `Roman Goj`_, `Alex Gramfort`_, `Denis Engemann`_ and `Martin Luessi`_
+
+ - Add printing summary to terminal for measurement info by `Denis Engemann`_
+
+ - Add read and write info attribute ICA objects by `Denis Engemann`_
+
+ - Decoding with Common Spatial Patterns (CSP) by `Romain Trachel`_ and `Alex Gramfort`_
+
+ - Add ICA plot_topomap function and method for displaying the spatial sensitivity of ICA sources by `Denis Engemann`_
+
+ - Plotting multiple brain views at once by `Eric Larson`_
+
+ - Reading head positions from raw FIFF files by `Eric Larson`_
+
+ - Add decimation parameter to ICA.decompose* methods by `Denis Engemann`_ and `Alex Gramfort`_
+
+ - Add rejection buffer to ICA.decompose* methods by `Denis Engemann`_ and `Alex Gramfort`_
+
+ - Add polygonal surface decimation function by `Denis Engemann`_ and `Alex Gramfort`_
+
+ - DICS time-frequency beamforming for epochs, evoked and for estimating source power by `Roman Goj`_, `Alex Gramfort`_ and `Denis Engemann`_
+
+ - Add method for computing cross-spectral density (CSD) from epochs and class for storing CSD data by `Roman Goj`_, `Alex Gramfort`_ and `Denis Engemann`_
+
+ - Add trellis plot function and method for visualizing single epochs by `Denis Engemann`_
+
+ - Add fiducials read/write support by `Christian Brodbeck`_ and `Alex Gramfort`_
+
+ - Add select / drop bad channels in `plot_raw` on click by `Denis Engemann`_
+
+ - Add `ico` and `oct` source space creation in native Python by `Eric Larson`_
+
+ - Add interactive rejection of bad trials in `plot_epochs` by `Denis Engemann`_
+
+ - Add morph map calculation by `Eric Larson`_ and `Martin Luessi`_
+
+ - Add volume and discrete source space creation and I/O support by `Eric Larson`_
+
+ - Time-frequency beamforming to obtain spectrograms in source space using LCMV and DICS by `Roman Goj`_, `Alex Gramfort`_ and `Denis Engemann`_
+
+ - Compute epochs power spectral density function by `Denis Engemann`_
+
+ - Plot raw power spectral density by `Eric Larson`_
+
+ - Computing of distances along the cortical surface by `Eric Larson`_
+
+ - Add reading BEM solutions by `Eric Larson`_
+
+ - Add forward solution calculation in native Python by `Eric Larson`_
+
+ - Add (Neuro)debian license compatibility by `Eric Larson`_
+
+ - Automatic QRS threshold selection for ECG events by `Eric Larson`_
+
+ - Add Travis continuous integration service by `Denis Engemann`_
+
+ - Add SPM face data set by `Denis Engemann`_ `Martin Luessi`_ and `Alex Gramfort`_
+
+ - Support reading of EDF+,BDF data by `Teon Brooks`_
+
+ - Support reading of EEG BrainVision data by `Teon Brooks`_
+
+API
+~~~
+
+ - The pick_normal parameter for minimum norm solvers has been renamed as pick_ori and normal orientation picking is now achieved by passing the value "normal" for the pick_ori parameter.
+
+ - ICA objects now expose the measurment info of the object fitted.
+
+ - Average EEG reference is now added by default to Raw instances.
+
+ - Removed deprecated read/write_stc/w, use SourceEstimate methods instead
+
.. _changes_0_6:
Version 0.6
@@ -442,3 +529,5 @@ of commits):
.. _Roman Goj: http://romanmne.blogspot.co.uk
.. _Andrew Dykstra: https://github.com/adykstra
+
+.. _Romain Trachel: http://www-sop.inria.fr/athena/Site/RomainTrachel
diff --git a/doc/sphinxext/gen_rst.py b/doc/sphinxext/gen_rst.py
index 6eedc90..7d27f84 100644
--- a/doc/sphinxext/gen_rst.py
+++ b/doc/sphinxext/gen_rst.py
@@ -1,3 +1,6 @@
+#!/usr/bin/env python
+# -*- coding: utf-8
+
"""
Example generation modified from the scikit learn
@@ -503,6 +506,8 @@ def generate_dir_rst(dir, fhindex, example_dir, root_dir, plot_gallery):
return 'zz' + a
return a
for fname in sorted(os.listdir(src_dir), key=sort_key):
+ if not os.path.split(fname)[-1].startswith('plot_'):
+ continue
if fname.endswith('py'):
generate_file_rst(fname, target_dir, src_dir, plot_gallery)
thumb = os.path.join(dir, 'images', 'thumb', fname[:-3] + '.png')
@@ -871,7 +876,8 @@ def embed_code_links(app, exception):
with open(full_fname, 'wt') as fid:
for line in lines_in:
for name, link in str_repl.iteritems():
- line = line.replace(name, link)
+ line = line.replace(name.encode('utf-8'),
+ link.encode('utf-8'))
fid.write(line)
fid.close()
diff --git a/doc/upload_html.sh b/doc/upload_html.sh
index 2196279..21d1c58 100755
--- a/doc/upload_html.sh
+++ b/doc/upload_html.sh
@@ -2,3 +2,4 @@
#scp -r build/html/* martinos-data:/web/html/mne/
rsync -rltvz --delete --perms --chmod=g+w build/html/ martinos-data:/web/html/mne/ -essh
+ssh martinos-data "chgrp -R megweb /web/html/mne"
diff --git a/examples/connectivity/plot_cwt_sensor_connectivity.py b/examples/connectivity/plot_cwt_sensor_connectivity.py
index 001afde..715bded 100644
--- a/examples/connectivity/plot_cwt_sensor_connectivity.py
+++ b/examples/connectivity/plot_cwt_sensor_connectivity.py
@@ -72,8 +72,8 @@ con, freqs, times, _, _ = spectral_connectivity(epochs, indices=indices,
con[np.where(indices[1] == seed)] = 1.0
# Show topography of connectivity from seed
-import pylab as pl
+import matplotlib.pyplot as plt
layout = read_layout('Vectorview-all')
title = 'WPLI2 - Visual - Seed %s' % seed_ch
plot_topo_tfr(epochs, con, freqs, layout, title=title)
-pl.show()
+plt.show()
diff --git a/examples/connectivity/plot_mne_inverse_coherence_epochs.py b/examples/connectivity/plot_mne_inverse_coherence_epochs.py
index 0232a15..1355a06 100644
--- a/examples/connectivity/plot_mne_inverse_coherence_epochs.py
+++ b/examples/connectivity/plot_mne_inverse_coherence_epochs.py
@@ -19,8 +19,8 @@ import numpy as np
import mne
from mne.datasets import sample
from mne.fiff import Raw, pick_types
-from mne.minimum_norm import apply_inverse, apply_inverse_epochs,\
- read_inverse_operator
+from mne.minimum_norm import (apply_inverse, apply_inverse_epochs,
+ read_inverse_operator)
from mne.connectivity import seed_target_indices, spectral_connectivity
@@ -59,7 +59,7 @@ snr = 3.0
lambda2 = 1.0 / snr ** 2
evoked = epochs.average()
stc = apply_inverse(evoked, inverse_operator, lambda2, method,
- pick_normal=True)
+ pick_ori="normal")
# Restrict the source estimate to the label in the left auditory cortex
stc_label = stc.in_label(label_lh)
@@ -80,7 +80,7 @@ indices = seed_target_indices([seed_idx], np.arange(n_sources))
snr = 1.0 # use lower SNR for single epochs
lambda2 = 1.0 / snr ** 2
stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2, method,
- pick_normal=True, return_generator=True)
+ pick_ori="normal", return_generator=True)
# Now we are ready to compute the coherence in the alpha and beta band.
# fmin and fmax specify the lower and upper freq. for each band, resp.
diff --git a/examples/connectivity/plot_mne_inverse_connectivity_spectrum.py b/examples/connectivity/plot_mne_inverse_connectivity_spectrum.py
index 95aefd7..f6808a7 100644
--- a/examples/connectivity/plot_mne_inverse_connectivity_spectrum.py
+++ b/examples/connectivity/plot_mne_inverse_connectivity_spectrum.py
@@ -50,7 +50,7 @@ snr = 1.0 # use lower SNR for single epochs
lambda2 = 1.0 / snr ** 2
method = "dSPM" # use dSPM method (could also be MNE or sLORETA)
stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2, method,
- pick_normal=True, return_generator=True)
+ pick_ori="normal", return_generator=True)
# Read some labels
names = ['Aud-lh', 'Aud-rh', 'Vis-lh', 'Vis-rh']
@@ -70,10 +70,10 @@ con, freqs, times, n_epochs, n_tapers = spectral_connectivity(label_ts,
method='wpli2_debiased', mode='multitaper', sfreq=sfreq, fmin=fmin,
fmax=fmax, mt_adaptive=True, n_jobs=2)
-import pylab as pl
+import matplotlib.pyplot as plt
n_rows, n_cols = con.shape[:2]
-fig, axes = pl.subplots(n_rows, n_cols, sharex=True, sharey=True)
-pl.suptitle('Between labels connectivity')
+fig, axes = plt.subplots(n_rows, n_cols, sharex=True, sharey=True)
+plt.suptitle('Between labels connectivity')
for i in range(n_rows):
for j in range(i + 1):
if i == j:
@@ -95,4 +95,4 @@ for i in range(n_rows):
for f in [8, 12, 18, 35]:
axes[i, j].axvline(f, color='k')
axes[j, i].axvline(f, color='k')
-pl.show()
+plt.show()
diff --git a/examples/connectivity/plot_mne_inverse_label_connectivity.py b/examples/connectivity/plot_mne_inverse_label_connectivity.py
index 0728874..015822b 100644
--- a/examples/connectivity/plot_mne_inverse_label_connectivity.py
+++ b/examples/connectivity/plot_mne_inverse_label_connectivity.py
@@ -55,7 +55,7 @@ snr = 1.0 # use lower SNR for single epochs
lambda2 = 1.0 / snr ** 2
method = "dSPM" # use dSPM method (could also be MNE or sLORETA)
stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2, method,
- pick_normal=True, return_generator=True)
+ pick_ori="normal", return_generator=True)
# Get labels for FreeSurfer 'aparc' cortical parcellation with 34 labels/hemi
labels, label_colors = mne.labels_from_parc('sample', parc='aparc',
@@ -120,6 +120,6 @@ plot_connectivity_circle(con, label_names, n_lines=300, node_angles=node_angles,
node_colors=label_colors,
title='All-to-All Connectivity left-Auditory '
'Condition')
-import pylab as pl
-pl.savefig('circle.png', facecolor='black')
-pl.show()
+import matplotlib.pyplot as plt
+plt.savefig('circle.png', facecolor='black')
+plt.show()
diff --git a/examples/connectivity/plot_mne_inverse_psi_visual.py b/examples/connectivity/plot_mne_inverse_psi_visual.py
index 4828a68..f0bbe38 100644
--- a/examples/connectivity/plot_mne_inverse_psi_visual.py
+++ b/examples/connectivity/plot_mne_inverse_psi_visual.py
@@ -66,7 +66,7 @@ epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks,
snr = 1.0 # use lower SNR for single epochs
lambda2 = 1.0 / snr ** 2
stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2, method,
- pick_normal=True, return_generator=False)
+ pick_ori="normal", return_generator=False)
# Now, we generate seed time series by averaging the activity in the left
# visual corex
diff --git a/examples/datasets/README.txt b/examples/datasets/README.txt
new file mode 100644
index 0000000..983b7ef
--- /dev/null
+++ b/examples/datasets/README.txt
@@ -0,0 +1,5 @@
+
+Examples on open datasets
+-------------------------
+
+Some demos on common/public datasets using MNE.
diff --git a/examples/datasets/plot_spm_faces_dataset.py b/examples/datasets/plot_spm_faces_dataset.py
new file mode 100644
index 0000000..a854034
--- /dev/null
+++ b/examples/datasets/plot_spm_faces_dataset.py
@@ -0,0 +1,118 @@
+"""
+==========================================
+From raw data to dSPM on SPM Faces dataset
+==========================================
+
+Runs a full pipeline using MNE-Python:
+- artifact removal
+- averaging Epochs
+- forward model computation
+- source reconstruction using dSPM on the contrast : "faces - scrambled"
+
+"""
+print __doc__
+
+# Authors: Alexandre Gramfort <alexandre.gramfort at telecom-paristech.fr>
+# Denis Engemann <d.engemann at fz-juelich.de>
+#
+# License: BSD (3-clause)
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+import mne
+from mne.datasets import spm_face
+from mne.preprocessing import ICA
+from mne import fiff
+from mne.minimum_norm import make_inverse_operator, apply_inverse
+
+
+data_path = spm_face.data_path()
+subjects_dir = data_path + '/subjects'
+
+###############################################################################
+# Load and filter data, set up epochs
+
+raw_fname = data_path + '/MEG/spm/SPM_CTF_MEG_example_faces%d_3D_raw.fif'
+
+raw = fiff.Raw(raw_fname % 1, preload=True) # Take first run
+
+
+picks = mne.fiff.pick_types(raw.info, meg=True, exclude='bads')
+raw.filter(1, 45, method='iir')
+
+events = mne.find_events(raw, stim_channel='UPPT001')
+event_ids = {"faces":1, "scrambled":2}
+
+tmin, tmax = -0.2, 0.6
+baseline = None # no baseline as high-pass is applied
+reject = dict(mag=1.5e-12)
+
+epochs = mne.Epochs(raw, events, event_ids, tmin, tmax, picks=picks,
+ baseline=baseline, preload=True, reject=reject)
+
+# Fit ICA, find and remove major artifacts
+
+ica = ICA(None, 50).decompose_epochs(epochs, decim=2)
+
+for ch_name in ['MRT51-2908', 'MLF14-2908']: # ECG, EOG contaminated chs
+ scores = ica.find_sources_epochs(epochs, ch_name, 'pearsonr')
+ ica.exclude += list(np.argsort(np.abs(scores))[-2:])
+
+ica.plot_topomap(np.unique(ica.exclude)) # plot components found
+
+
+# select ICA sources and reconstruct MEG signals, compute clean ERFs
+
+epochs = ica.pick_sources_epochs(epochs)
+
+evoked = [epochs[k].average() for k in event_ids]
+
+contrast = evoked[1] - evoked[0]
+
+evoked.append(contrast)
+
+for e in evoked:
+ plt.figure()
+ e.plot(ylim=dict(mag=[-400, 400]))
+
+plt.show()
+
+# estimate noise covarariance
+noise_cov = mne.compute_covariance(epochs.crop(None, 0, copy=True))
+
+###############################################################################
+# Compute forward model
+
+# Make source space
+src = mne.setup_source_space('spm', spacing='oct6', subjects_dir=subjects_dir,
+ overwrite=True)
+
+mri = data_path + '/MEG/spm/SPM_CTF_MEG_example_faces1_3D_raw-trans.fif'
+bem = data_path + '/subjects/spm/bem/spm-5120-5120-5120-bem-sol.fif'
+forward = mne.make_forward_solution(contrast.info, mri=mri, src=src, bem=bem)
+forward = mne.convert_forward_solution(forward, surf_ori=True)
+
+###############################################################################
+# Compute inverse solution
+
+snr = 5.0
+lambda2 = 1.0 / snr ** 2
+method = 'dSPM'
+
+inverse_operator = make_inverse_operator(contrast.info, forward, noise_cov,
+ loose=0.2, depth=0.8)
+
+# Compute inverse solution on contrast
+stc = apply_inverse(contrast, inverse_operator, lambda2, method,
+ pick_normal=False)
+# stc.save('spm_%s_dSPM_inverse' % constrast.comment)
+
+# plot constrast
+# Plot brain in 3D with PySurfer if available. Note that the subject name
+# is already known by the SourceEstimate stc object.
+brain = stc.plot(surface='inflated', hemi='both', subjects_dir=subjects_dir)
+brain.set_data_time_index(173)
+brain.scale_data_colormap(fmin=4, fmid=6, fmax=8, transparent=True)
+brain.show_view('ventral')
+# brain.save_image('dSPM_map.png')
diff --git a/examples/decoding/plot_decoding_csp_space.py b/examples/decoding/plot_decoding_csp_space.py
new file mode 100644
index 0000000..a946f25
--- /dev/null
+++ b/examples/decoding/plot_decoding_csp_space.py
@@ -0,0 +1,106 @@
+"""
+====================================================================
+Decoding in sensor space data using the Common Spatial Pattern (CSP)
+====================================================================
+
+Decoding applied to MEG data in sensor space decomposed using CSP.
+Here the classifier is applied to features extracted on CSP filtered signals.
+
+See http://en.wikipedia.org/wiki/Common_spatial_pattern and [1]
+
+[1] Zoltan J. Koles. The quantitative extraction and topographic mapping
+ of the abnormal components in the clinical EEG. Electroencephalography
+ and Clinical Neurophysiology, 79(6):440--447, December 1991.
+
+"""
+# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Romain Trachel <romain.trachel at inria.fr>
+#
+# License: BSD (3-clause)
+
+print __doc__
+import numpy as np
+
+import mne
+from mne import fiff
+from mne.datasets import sample
+
+data_path = sample.data_path()
+
+###############################################################################
+# Set parameters and read data
+raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
+event_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw-eve.fif'
+tmin, tmax = -0.2, 0.5
+event_id = dict(aud_l=1, vis_l=3)
+
+# Setup for reading the raw data
+raw = fiff.Raw(raw_fname, preload=True)
+raw.filter(2, None, method='iir') # replace baselining with high-pass
+events = mne.read_events(event_fname)
+
+raw.info['bads'] = ['MEG 2443'] # set bad channels
+picks = fiff.pick_types(raw.info, meg='grad', eeg=False, stim=False, eog=False,
+ exclude='bads')
+
+# Read epochs
+epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ picks=picks, baseline=None, preload=True)
+
+labels = epochs.events[:, -1]
+evoked = epochs.average()
+
+###############################################################################
+# Decoding in sensor space using a linear SVM
+
+from sklearn.svm import SVC
+from sklearn.cross_validation import ShuffleSplit
+from mne.decoding import CSP
+
+n_components = 3 # pick some components
+svc = SVC(C=1, kernel='linear')
+csp = CSP(n_components=n_components)
+
+# Define a monte-carlo cross-validation generator (reduce variance):
+cv = ShuffleSplit(len(labels), 10, test_size=0.2, random_state=42)
+scores = []
+epochs_data = epochs.get_data()
+
+for train_idx, test_idx in cv:
+ y_train, y_test = labels[train_idx], labels[test_idx]
+
+ X_train = csp.fit_transform(epochs_data[train_idx], y_train)
+ X_test = csp.transform(epochs_data[test_idx])
+
+ # fit classifier
+ svc.fit(X_train, y_train)
+
+ scores.append(svc.score(X_test, y_test))
+
+# Printing the results
+class_balance = np.mean(labels == labels[0])
+class_balance = max(class_balance, 1. - class_balance)
+print "Classification accuracy: %f / Chance level: %f" % (np.mean(scores),
+ class_balance)
+
+# Or use much more convenient scikit-learn cross_val_score function using
+# a Pipeline
+from sklearn.pipeline import Pipeline
+from sklearn.cross_validation import cross_val_score
+cv = ShuffleSplit(len(labels), 10, test_size=0.2, random_state=42)
+clf = Pipeline([('CSP', csp), ('SVC', svc)])
+scores = cross_val_score(clf, epochs_data, labels, cv=cv, n_jobs=1)
+print scores.mean() # should match results above
+
+# And using reuglarized csp with Ledoit-Wolf estimator
+csp = CSP(n_components=n_components, reg='lws')
+clf = Pipeline([('CSP', csp), ('SVC', svc)])
+scores = cross_val_score(clf, epochs_data, labels, cv=cv, n_jobs=1)
+print scores.mean() # should get better results than above
+
+# plot CSP patterns estimated on full data for visualization
+csp.fit_transform(epochs_data, labels)
+evoked.data = csp.patterns_.T
+evoked.times = np.arange(evoked.data.shape[0])
+evoked.plot_topomap(times=[0, 1, 201, 202], ch_type='grad',
+ colorbar=False, size=1.5)
diff --git a/examples/decoding/plot_decoding_sensors.py b/examples/decoding/plot_decoding_sensors.py
index 3e8b12e..1b4fc73 100644
--- a/examples/decoding/plot_decoding_sensors.py
+++ b/examples/decoding/plot_decoding_sensors.py
@@ -12,7 +12,7 @@ point.
# License: BSD (3-clause)
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
import numpy as np
import mne
@@ -21,7 +21,7 @@ from mne.datasets import sample
data_path = sample.data_path()
-pl.close('all')
+plt.close('all')
###############################################################################
# Set parameters
@@ -86,14 +86,14 @@ for t in xrange(n_times):
times = 1e3 * epochs.times
scores *= 100 # make it percentage
std_scores *= 100
-pl.plot(times, scores, label="Classif. score")
-pl.axhline(50, color='k', linestyle='--', label="Chance level")
-pl.axvline(0, color='r', label='stim onset')
-pl.legend()
+plt.plot(times, scores, label="Classif. score")
+plt.axhline(50, color='k', linestyle='--', label="Chance level")
+plt.axvline(0, color='r', label='stim onset')
+plt.legend()
hyp_limits = (scores - std_scores, scores + std_scores)
-pl.fill_between(times, hyp_limits[0], y2=hyp_limits[1], color='b', alpha=0.5)
-pl.xlabel('Times (ms)')
-pl.ylabel('CV classification score (% correct)')
-pl.ylim([30, 100])
-pl.title('Sensor space decoding')
-pl.show()
+plt.fill_between(times, hyp_limits[0], y2=hyp_limits[1], color='b', alpha=0.5)
+plt.xlabel('Times (ms)')
+plt.ylabel('CV classification score (% correct)')
+plt.ylim([30, 100])
+plt.title('Sensor space decoding')
+plt.show()
diff --git a/examples/decoding/plot_decoding_spatio_temporal_source.py b/examples/decoding/plot_decoding_spatio_temporal_source.py
index dbaac14..4c7c0f4 100644
--- a/examples/decoding/plot_decoding_spatio_temporal_source.py
+++ b/examples/decoding/plot_decoding_spatio_temporal_source.py
@@ -78,7 +78,7 @@ X = np.zeros([n_epochs, n_vertices, n_times])
# to save memory, we'll load and transform our epochs step by step.
for condition_count, ep in zip([0, n_epochs / 2], epochs_list):
stcs = apply_inverse_epochs(ep, inverse_operator, lambda2,
- method, pick_normal=True, # this saves us memory
+ method, pick_ori="normal", # this saves us memory
return_generator=True)
for jj, stc in enumerate(stcs):
X[condition_count + jj] = stc.lh_data
diff --git a/examples/export/plot_epochs_as_data_frame.py b/examples/export/plot_epochs_as_data_frame.py
index dde36fb..f994726 100644
--- a/examples/export/plot_epochs_as_data_frame.py
+++ b/examples/export/plot_epochs_as_data_frame.py
@@ -92,14 +92,14 @@ pandas doc sites: http://pandas.pydata.org/pandas-docs/stable/
print __doc__
import mne
-import pylab as pl
+import matplotlib.pyplot as plt
import numpy as np
from mne.fiff import Raw
from mne.datasets import sample
# turn on interactive mode
-pl.ion()
+plt.ion()
data_path = sample.data_path()
raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
@@ -205,9 +205,9 @@ print max_latency
# Then make the plot labels more readable let's edit the values of 'condition'.
df.condition = df.condition.apply(lambda name: name + ' ')
-pl.figure()
+plt.figure()
max_latency.plot(kind='barh', title='Latency of Maximum Reponse',
- color='steelblue')
+ color=['steelblue'])
mne.viz.tight_layout()
# Finally, we will again remove the index to create a proper data table that
diff --git a/examples/export/plot_epochs_to_nitime.py b/examples/export/plot_epochs_to_nitime.py
index 37ceaf9..200d9ac 100644
--- a/examples/export/plot_epochs_to_nitime.py
+++ b/examples/export/plot_epochs_to_nitime.py
@@ -49,7 +49,7 @@ epochs_ts = epochs.to_nitime(picks=np.arange(20), collapse=True)
from nitime.analysis import MTCoherenceAnalyzer
from nitime.viz import drawmatrix_channels
-import matplotlib.pylab as pl
+import matplotlib.pyplot as plt
# setup coherency analyzer
C = MTCoherenceAnalyzer(epochs_ts)
@@ -62,4 +62,4 @@ coh = np.mean(C.coherence[:, :, freq_idx], -1) # Averaging on last dimension
drawmatrix_channels(coh, epochs.ch_names, color_anchor=0,
title='MEG gradiometer coherence')
-pl.show()
+plt.show()
diff --git a/examples/export/plot_evoked_to_nitime.py b/examples/export/plot_evoked_to_nitime.py
index d0a2dfd..8b4b771 100644
--- a/examples/export/plot_evoked_to_nitime.py
+++ b/examples/export/plot_evoked_to_nitime.py
@@ -14,7 +14,7 @@ print __doc__
from mne import fiff
from mne.datasets import sample
from nitime.viz import plot_tseries
-import pylab as pl
+import matplotlib.pyplot as plt
data_path = sample.data_path()
@@ -31,4 +31,4 @@ evoked_ts = evoked.to_nitime(picks=picks)
plot_tseries(evoked_ts)
-pl.show()
+plt.show()
diff --git a/examples/export/plot_raw_to_nitime.py b/examples/export/plot_raw_to_nitime.py
index 5b8a81d..0965f96 100644
--- a/examples/export/plot_raw_to_nitime.py
+++ b/examples/export/plot_raw_to_nitime.py
@@ -61,7 +61,7 @@ print raw_ts.ch_names[:3]
###############################################################################
# investigate spectral density
-import matplotlib.pylab as pl
+import matplotlib.pyplot as plt
import nitime.algorithms as tsa
@@ -75,9 +75,9 @@ f, psd_mt, nu = tsa.multi_taper_psd(data_ch, Fs=raw_ts.sampling_rate,
# Convert PSD to dB
psd_mt = 10 * np.log10(psd_mt)
-pl.close('all')
-pl.plot(f, psd_mt)
-pl.xlabel('Frequency (Hz)')
-pl.ylabel('Power Spectrald Density (db/Hz)')
-pl.title('Multitaper Power Spectrum \n %s' % raw_ts.ch_names[ch_sel])
-pl.show()
+plt.close('all')
+plt.plot(f, psd_mt)
+plt.xlabel('Frequency (Hz)')
+plt.ylabel('Power Spectrald Density (db/Hz)')
+plt.title('Multitaper Power Spectrum \n %s' % raw_ts.ch_names[ch_sel])
+plt.show()
diff --git a/examples/inverse/plot_compute_mne_inverse.py b/examples/inverse/plot_compute_mne_inverse.py
index 36e358b..4a635a5 100644
--- a/examples/inverse/plot_compute_mne_inverse.py
+++ b/examples/inverse/plot_compute_mne_inverse.py
@@ -14,7 +14,7 @@ and stores the solution in stc files for visualisation.
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
from mne.datasets import sample
from mne.fiff import Evoked
from mne.minimum_norm import apply_inverse, read_inverse_operator
@@ -35,17 +35,17 @@ inverse_operator = read_inverse_operator(fname_inv)
# Compute inverse solution
stc = apply_inverse(evoked, inverse_operator, lambda2, method,
- pick_normal=False)
+ pick_ori=None)
# Save result in stc files
stc.save('mne_%s_inverse' % method)
###############################################################################
# View activation time-series
-pl.plot(1e3 * stc.times, stc.data[::100, :].T)
-pl.xlabel('time (ms)')
-pl.ylabel('%s value' % method)
-pl.show()
+plt.plot(1e3 * stc.times, stc.data[::100, :].T)
+plt.xlabel('time (ms)')
+plt.ylabel('%s value' % method)
+plt.show()
# Plot brain in 3D with PySurfer if available. Note that the subject name
# is already known by the SourceEstimate stc object.
diff --git a/examples/inverse/plot_compute_mne_inverse_epochs_in_label.py b/examples/inverse/plot_compute_mne_inverse_epochs_in_label.py
index a7f057c..225ae0b 100644
--- a/examples/inverse/plot_compute_mne_inverse_epochs_in_label.py
+++ b/examples/inverse/plot_compute_mne_inverse_epochs_in_label.py
@@ -15,7 +15,7 @@ to a brain label.
print __doc__
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.datasets import sample
from mne.fiff import Raw, pick_types
@@ -56,7 +56,7 @@ epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks,
# Compute inverse solution and stcs for each epoch
stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2, method, label,
- pick_normal=True)
+ pick_ori="normal")
mean_stc = sum(stcs) / len(stcs)
@@ -68,12 +68,12 @@ label_mean_flip = np.mean(flip[:, np.newaxis] * mean_stc.data, axis=0)
###############################################################################
# View activation time-series
-pl.figure()
-h0 = pl.plot(1e3 * stcs[0].times, mean_stc.data.T, 'k')
-h1, = pl.plot(1e3 * stcs[0].times, label_mean, 'r', linewidth=3)
-h2, = pl.plot(1e3 * stcs[0].times, label_mean_flip, 'g', linewidth=3)
-pl.legend((h0[0], h1, h2), ('all dipoles in label', 'mean',
- 'mean with sign flip'))
-pl.xlabel('time (ms)')
-pl.ylabel('dSPM value')
-pl.show()
+plt.figure()
+h0 = plt.plot(1e3 * stcs[0].times, mean_stc.data.T, 'k')
+h1, = plt.plot(1e3 * stcs[0].times, label_mean, 'r', linewidth=3)
+h2, = plt.plot(1e3 * stcs[0].times, label_mean_flip, 'g', linewidth=3)
+plt.legend((h0[0], h1, h2), ('all dipoles in label', 'mean',
+ 'mean with sign flip'))
+plt.xlabel('time (ms)')
+plt.ylabel('dSPM value')
+plt.show()
diff --git a/examples/inverse/plot_compute_mne_inverse_raw_in_label.py b/examples/inverse/plot_compute_mne_inverse_raw_in_label.py
index 92d0d08..73230b6 100644
--- a/examples/inverse/plot_compute_mne_inverse_raw_in_label.py
+++ b/examples/inverse/plot_compute_mne_inverse_raw_in_label.py
@@ -15,7 +15,7 @@ visualisation.
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.datasets import sample
from mne.fiff import Raw
@@ -41,14 +41,14 @@ start, stop = raw.time_as_index([0, 15]) # read the first 15s of data
# Compute inverse solution
stc = apply_inverse_raw(raw, inverse_operator, lambda2, method, label,
- start, stop, pick_normal=False)
+ start, stop, pick_ori=None)
# Save result in stc files
stc.save('mne_%s_raw_inverse_%s' % (method, label_name))
###############################################################################
# View activation time-series
-pl.plot(1e3 * stc.times, stc.data[::100, :].T)
-pl.xlabel('time (ms)')
-pl.ylabel('%s value' % method)
-pl.show()
+plt.plot(1e3 * stc.times, stc.data[::100, :].T)
+plt.xlabel('time (ms)')
+plt.ylabel('%s value' % method)
+plt.show()
diff --git a/examples/inverse/plot_compute_mne_inverse_volume.py b/examples/inverse/plot_compute_mne_inverse_volume.py
index 2451c6d..d0cd1fd 100644
--- a/examples/inverse/plot_compute_mne_inverse_volume.py
+++ b/examples/inverse/plot_compute_mne_inverse_volume.py
@@ -15,8 +15,7 @@ space and stores the solution in a nifti file for visualisation.
print __doc__
import numpy as np
-import pylab as pl
-import mne
+import matplotlib.pyplot as plt
from mne.datasets import sample
from mne.fiff import Evoked
from mne.minimum_norm import apply_inverse, read_inverse_operator
@@ -38,18 +37,23 @@ src = inverse_operator['src']
stc = apply_inverse(evoked, inverse_operator, lambda2, method)
stc.crop(0.0, 0.2)
-# Save result in a 4D nifti file
-img = mne.save_stc_as_volume('mne_%s_inverse.nii.gz' % method, stc,
- src, mri_resolution=False) # set to True for full MRI resolution
+# Export result as a 4D nifti object
+img = stc.as_volume(src,
+ mri_resolution=False) # set True for full MRI resolution
+
+# Save it as a nifti file
+import nibabel as nib
+nib.save(img, 'mne_%s_inverse.nii.gz' % method)
+
data = img.get_data()
-# plot result (one slice)
+# Plot result (one slice)
coronal_slice = data[:, 10, :, 60]
-pl.close('all')
-pl.imshow(np.ma.masked_less(coronal_slice, 8), cmap=pl.cm.Reds,
- interpolation='nearest')
-pl.colorbar()
-pl.contour(coronal_slice != 0, 1, colors=['black'])
-pl.xticks([])
-pl.yticks([])
-pl.show()
+plt.close('all')
+plt.imshow(np.ma.masked_less(coronal_slice, 8), cmap=plt.cm.Reds,
+ interpolation='nearest')
+plt.colorbar()
+plt.contour(coronal_slice != 0, 1, colors=['black'])
+plt.xticks([])
+plt.yticks([])
+plt.show()
diff --git a/examples/inverse/plot_dics_beamformer.py b/examples/inverse/plot_dics_beamformer.py
new file mode 100644
index 0000000..a1138be
--- /dev/null
+++ b/examples/inverse/plot_dics_beamformer.py
@@ -0,0 +1,89 @@
+"""
+=====================================
+Compute DICS beamfomer on evoked data
+=====================================
+
+Compute a Dynamic Imaging of Coherent Sources (DICS) beamformer from single
+trial activity in a time-frequency window to estimate source time courses based
+on evoked data.
+
+The original reference for DICS is:
+Gross et al. Dynamic imaging of coherent sources: Studying neural interactions
+in the human brain. PNAS (2001) vol. 98 (2) pp. 694-699
+"""
+
+# Author: Roman Goj <roman.goj at gmail.com>
+#
+# License: BSD (3-clause)
+
+print __doc__
+
+import mne
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+from mne.fiff import Raw
+from mne.datasets import sample
+from mne.time_frequency import compute_epochs_csd
+from mne.beamformer import dics
+
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
+event_fname = data_path + '/MEG/sample/sample_audvis_raw-eve.fif'
+fname_fwd = data_path + '/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif'
+label_name = 'Aud-lh'
+fname_label = data_path + '/MEG/sample/labels/%s.label' % label_name
+subjects_dir = data_path + '/subjects'
+
+###############################################################################
+# Read raw data
+raw = Raw(raw_fname)
+raw.info['bads'] = ['MEG 2443', 'EEG 053'] # 2 bads channels
+
+# Set picks
+picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False, eog=False,
+ stim=False, exclude='bads')
+
+# Read epochs
+event_id, tmin, tmax = 1, -0.2, 0.5
+events = mne.read_events(event_fname)
+epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ picks=picks, baseline=(None, 0), preload=True,
+ reject=dict(grad=4000e-13, mag=4e-12))
+evoked = epochs.average()
+
+# Read forward operator
+forward = mne.read_forward_solution(fname_fwd, surf_ori=True)
+
+# Computing the data and noise cross-spectral density matrices
+# The time-frequency window was chosen on the basis of spectrograms from
+# example time_frequency/plot_time_frequency.py
+data_csd = compute_epochs_csd(epochs, mode='multitaper', tmin=0.04, tmax=0.15,
+ fmin=6, fmax=10)
+noise_csd = compute_epochs_csd(epochs, mode='multitaper', tmin=-0.11, tmax=0.0,
+ fmin=6, fmax=10)
+
+evoked = epochs.average()
+
+# Compute DICS spatial filter and estimate source time courses on evoked data
+stc = dics(evoked, forward, noise_csd, data_csd)
+
+plt.figure()
+ts_show = -30 # show the 40 largest responses
+plt.plot(1e3 * stc.times,
+ stc.data[np.argsort(stc.data.max(axis=1))[ts_show:]].T)
+plt.xlabel('Time (ms)')
+plt.ylabel('DICS value')
+plt.title('DICS time course of the 30 largest sources.')
+plt.show()
+
+# Plot brain in 3D with PySurfer if available. Note that the subject name
+# is already known by the SourceEstimate stc object.
+brain = stc.plot(surface='inflated', hemi='rh', subjects_dir=subjects_dir)
+brain.set_data_time_index(180)
+brain.scale_data_colormap(fmin=4, fmid=6, fmax=8, transparent=True)
+brain.show_view('lateral')
+
+# Uncomment to save image
+#brain.save_image('DICS_map.png')
diff --git a/examples/inverse/plot_dics_source_power.py b/examples/inverse/plot_dics_source_power.py
new file mode 100644
index 0000000..716dff4
--- /dev/null
+++ b/examples/inverse/plot_dics_source_power.py
@@ -0,0 +1,79 @@
+"""
+=========================================
+Compute source power using DICS beamfomer
+=========================================
+
+Compute a Dynamic Imaging of Coherent Sources (DICS) filter from single trial
+activity to estimate source power for two frequencies of interest.
+
+The original reference for DICS is:
+Gross et al. Dynamic imaging of coherent sources: Studying neural interactions
+in the human brain. PNAS (2001) vol. 98 (2) pp. 694-699
+"""
+
+# Author: Roman Goj <roman.goj at gmail.com>
+#
+# License: BSD (3-clause)
+
+print __doc__
+
+import mne
+
+from mne.fiff import Raw
+from mne.datasets import sample
+from mne.time_frequency import compute_epochs_csd
+from mne.beamformer import dics_source_power
+
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
+event_fname = data_path + '/MEG/sample/sample_audvis_raw-eve.fif'
+fname_fwd = data_path + '/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif'
+subjects_dir = data_path + '/subjects'
+
+###############################################################################
+# Read raw data
+raw = Raw(raw_fname)
+raw.info['bads'] = ['MEG 2443'] # 1 bad MEG channel
+
+# Set picks
+picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False, eog=False,
+ stim=False, exclude='bads')
+
+# Read epochs
+event_id, tmin, tmax = 1, -0.2, 0.5
+events = mne.read_events(event_fname)
+epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ picks=picks, baseline=(None, 0), preload=True,
+ reject=dict(grad=4000e-13, mag=4e-12))
+evoked = epochs.average()
+
+# Read forward operator
+forward = mne.read_forward_solution(fname_fwd, surf_ori=True)
+
+# Computing the data and noise cross-spectral density matrices
+# The time-frequency window was chosen on the basis of spectrograms from
+# example time_frequency/plot_time_frequency.py
+# As fsum is False compute_epochs_csd returns a list of CrossSpectralDensity
+# instances than can then be passed to dics_source_power
+data_csds = compute_epochs_csd(epochs, mode='multitaper', tmin=0.04, tmax=0.15,
+ fmin=30, fmax=50, fsum=False)
+noise_csds = compute_epochs_csd(epochs, mode='multitaper', tmin=-0.11,
+ tmax=-0.001, fmin=30, fmax=50, fsum=False)
+
+# Compute DICS spatial filter and estimate source power
+stc = dics_source_power(epochs.info, forward, noise_csds, data_csds)
+
+# Plot source power separately for each frequency of interest
+pow_lim = [[1.88, 2.41, 2.94], # limits for source power at 36.4 Hz
+ [1.41, 1.65, 1.89]] # limits for source power at 45.5 Hz
+for i, csd in enumerate(data_csds):
+ message = 'DICS source power at %0.1f Hz' % csd.frequencies[0]
+ brain = stc.plot(surface='inflated', hemi='rh', subjects_dir=subjects_dir,
+ time_label=message, figure=i)
+ data = stc.data[:, i]
+ brain.set_data_time_index(i)
+ brain.scale_data_colormap(fmin=pow_lim[i][0], fmid=pow_lim[i][1],
+ fmax=pow_lim[i][2], transparent=True)
+ brain.show_view('lateral')
+ # Uncomment line below to save images
+ #brain.save_image('DICS_source_power_freq_%d.png' % csd.frequencies[0])
diff --git a/examples/inverse/plot_gamma_map_inverse.py b/examples/inverse/plot_gamma_map_inverse.py
index 2bbb751..e092197 100644
--- a/examples/inverse/plot_gamma_map_inverse.py
+++ b/examples/inverse/plot_gamma_map_inverse.py
@@ -13,7 +13,7 @@ NeuroImage, vol. 44, no. 3, pp. 947?66, Mar. 2009.
print __doc__
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.datasets import sample
@@ -32,7 +32,8 @@ evoked = mne.fiff.read_evoked(evoked_fname, setno=setno, baseline=(None, 0))
evoked.crop(tmin=-50e-3, tmax=300e-3)
# Read the forward solution
-forward = mne.read_forward_solution(fwd_fname, surf_ori=True, force_fixed=False)
+forward = mne.read_forward_solution(fwd_fname, surf_ori=True,
+ force_fixed=False)
# Read noise covariance matrix and regularize it
cov = mne.read_cov(cov_fname)
@@ -56,11 +57,11 @@ plot_sparse_source_estimates(forward['src'], stc, bgcolor=(1, 1, 1),
# Show the evoked response and the residual for gradiometers
ylim = dict(grad=[-120, 120])
evoked = mne.fiff.pick_types_evoked(evoked, meg='grad', exclude='bads')
-pl.figure()
+plt.figure()
evoked.plot(titles=dict(grad='Evoked Response Gradiometers'), ylim=ylim,
proj=True)
residual = mne.fiff.pick_types_evoked(residual, meg='grad', exclude='bads')
-pl.figure()
+plt.figure()
residual.plot(titles=dict(grad='Residuals Gradiometers'), ylim=ylim,
proj=True)
diff --git a/examples/inverse/plot_label_activation_from_stc.py b/examples/inverse/plot_label_activation_from_stc.py
index dd1d865..71d7db2 100644
--- a/examples/inverse/plot_label_activation_from_stc.py
+++ b/examples/inverse/plot_label_activation_from_stc.py
@@ -19,7 +19,7 @@ import os
import mne
from mne.datasets import sample
-import pylab as pl
+import matplotlib.pyplot as plt
data_path = sample.data_path()
os.environ['SUBJECTS_DIR'] = data_path + '/subjects'
@@ -44,19 +44,19 @@ vtx, _, t_rh = stc_rh.center_of_mass('sample')
mni_rh = mne.vertex_to_mni(vtx, 1, 'sample')[0]
# plot the activation
-pl.figure()
-pl.axes([.1, .275, .85, .625])
-hl = pl.plot(stc.times, stc_lh.data.mean(0), 'b')
-hr = pl.plot(stc.times, stc_rh.data.mean(0), 'g')
-hb = pl.plot(stc.times, stc_bh.data.mean(0), 'r')
-pl.xlabel('Time (s)')
-pl.ylabel('Source amplitude (dSPM)')
-pl.xlim(stc.times[0], stc.times[-1])
+plt.figure()
+plt.axes([.1, .275, .85, .625])
+hl = plt.plot(stc.times, stc_lh.data.mean(0), 'b')
+hr = plt.plot(stc.times, stc_rh.data.mean(0), 'g')
+hb = plt.plot(stc.times, stc_bh.data.mean(0), 'r')
+plt.xlabel('Time (s)')
+plt.ylabel('Source amplitude (dSPM)')
+plt.xlim(stc.times[0], stc.times[-1])
# add a legend including center-of-mass mni coordinates to the plot
labels = ['LH: center of mass = %s' % mni_lh.round(2),
'RH: center of mass = %s' % mni_rh.round(2),
'Combined LH & RH']
-pl.figlegend([hl, hr, hb], labels, 'lower center')
-pl.suptitle('Average activation in auditory cortex labels', fontsize=20)
-pl.show()
+plt.figlegend([hl, hr, hb], labels, 'lower center')
+plt.suptitle('Average activation in auditory cortex labels', fontsize=20)
+plt.show()
diff --git a/examples/inverse/plot_label_from_stc.py b/examples/inverse/plot_label_from_stc.py
new file mode 100644
index 0000000..cd2c3f4
--- /dev/null
+++ b/examples/inverse/plot_label_from_stc.py
@@ -0,0 +1,105 @@
+"""
+=================================================
+Generate a functional label from source estimates
+=================================================
+
+Threshold source estimates and produce a functional label. The label
+is typically the region of interest that contains high values.
+Here we compare the average time course in the anatomical label obtained
+by FreeSurfer segmentation and the average time course from the
+functional label. As expected the time course in the functional
+label yields higher values.
+
+"""
+
+# Author: Luke Bloy <luke.bloy at gmail.com>
+# Alex Gramfort <alexandre.gramfort at telecom-paristech.fr>
+# License: BSD (3-clause)
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+import mne
+from mne.minimum_norm import read_inverse_operator, apply_inverse
+from mne.fiff import Evoked
+from mne.datasets import sample
+
+data_path = sample.data_path()
+subjects_dir = data_path + '/subjects'
+fname_inv = data_path + '/MEG/sample/sample_audvis-meg-oct-6-meg-inv.fif'
+fname_evoked = data_path + '/MEG/sample/sample_audvis-ave.fif'
+subjects_dir = data_path + '/subjects'
+subject = 'sample'
+
+snr = 3.0
+lambda2 = 1.0 / snr ** 2
+method = "dSPM" # use dSPM method (could also be MNE or sLORETA)
+
+# Compute a label/ROI based on the peak power between 80 and 120 ms.
+# The label bankssts-lh is used for the comparison.
+aparc_label_name = 'bankssts-lh'
+tmin, tmax = 0.080, 0.120
+
+# Load data
+evoked = Evoked(fname_evoked, setno=0, baseline=(None, 0))
+inverse_operator = read_inverse_operator(fname_inv)
+src = inverse_operator['src'] # get the source space
+
+# Compute inverse solution
+stc = apply_inverse(evoked, inverse_operator, lambda2, method,
+ pick_normal=True)
+
+# Make an STC in the time interval of interest and take the mean
+stc_mean = stc.copy().crop(tmin, tmax).mean()
+
+# use the stc_mean to generate a functional label
+# region growing is halted at 60% of the peak value within the
+# anatomical label / ROI specified by aparc_label_name
+label = mne.labels_from_parc(subject, parc='aparc', subjects_dir=subjects_dir,
+ regexp=aparc_label_name)[0][0]
+stc_mean_label = stc_mean.in_label(label)
+data = np.abs(stc_mean_label.data)
+stc_mean_label.data[data < 0.6 * np.max(data)] = 0.
+
+func_labels, _ = mne.stc_to_label(stc_mean_label, src=src, smooth=5,
+ subjects_dir=subjects_dir, connected=True)
+
+# take first as func_labels are ordered based on maximum values in stc
+func_label = func_labels[0]
+
+# load the anatomical ROI for comparison
+anat_label = mne.labels_from_parc(subject, parc='aparc',
+ subjects_dir=subjects_dir,
+ regexp=aparc_label_name)[0][0]
+
+# extract the anatomical time course for each label
+stc_anat_label = stc.in_label(anat_label)
+pca_anat = stc.extract_label_time_course(anat_label, src, mode='pca_flip')[0]
+
+stc_func_label = stc.in_label(func_label)
+pca_func = stc.extract_label_time_course(func_label, src, mode='pca_flip')[0]
+
+# flip the pca so that the max power between tmin and tmax is positive
+pca_anat *= np.sign(pca_anat[np.argmax(np.abs(pca_anat))])
+pca_func *= np.sign(pca_func[np.argmax(np.abs(pca_anat))])
+
+###############################################################################
+# plot the time courses....
+plt.figure()
+plt.plot(1e3 * stc_anat_label.times, pca_anat, 'k',
+ label='Anatomical %s' % aparc_label_name)
+plt.plot(1e3 * stc_func_label.times, pca_func, 'b',
+ label='Functional %s' % aparc_label_name)
+plt.legend()
+plt.show()
+
+###############################################################################
+# Plot brain in 3D with PySurfer if available. Note that the subject name
+# is already known by the SourceEstimate stc object.
+brain = stc_mean.plot(surface='inflated', hemi='lh', subjects_dir=subjects_dir)
+brain.scale_data_colormap(fmin=0, fmid=350, fmax=700, transparent=True)
+brain.show_view('lateral')
+
+# show both labels
+brain.add_label(anat_label, borders=True, color='k')
+brain.add_label(func_label, borders=True, color='b')
diff --git a/examples/inverse/plot_label_source_activations.py b/examples/inverse/plot_label_source_activations.py
index 3d258cb..dc31433 100644
--- a/examples/inverse/plot_label_source_activations.py
+++ b/examples/inverse/plot_label_source_activations.py
@@ -37,9 +37,9 @@ inverse_operator = read_inverse_operator(fname_inv)
src = inverse_operator['src']
# Compute inverse solution
-pick_normal = True # Get signed values to see the effect of sign filp
+pick_ori = "normal" # Get signed values to see the effect of sign filp
stc = apply_inverse(evoked, inverse_operator, lambda2, method,
- pick_normal=pick_normal)
+ pick_ori=pick_ori)
label = mne.read_label(label_fname)
@@ -51,14 +51,14 @@ pca = stc.extract_label_time_course(label, src, mode='pca_flip')
print "Number of vertices : %d" % len(stc_label.data)
# View source activations
-import pylab as pl
-pl.figure()
-pl.plot(1e3 * stc_label.times, stc_label.data.T, 'k', linewidth=0.5)
-h0, = pl.plot(1e3 * stc_label.times, mean.T, 'r', linewidth=3)
-h1, = pl.plot(1e3 * stc_label.times, mean_flip.T, 'g', linewidth=3)
-h2, = pl.plot(1e3 * stc_label.times, pca.T, 'b', linewidth=3)
-pl.legend([h0, h1, h2], ['mean', 'mean flip', 'PCA flip'])
-pl.xlabel('Time (ms)')
-pl.ylabel('Source amplitude')
-pl.title('Activations in Label : %s' % label)
-pl.show()
+import matplotlib.pyplot as plt
+plt.figure()
+plt.plot(1e3 * stc_label.times, stc_label.data.T, 'k', linewidth=0.5)
+h0, = plt.plot(1e3 * stc_label.times, mean.T, 'r', linewidth=3)
+h1, = plt.plot(1e3 * stc_label.times, mean_flip.T, 'g', linewidth=3)
+h2, = plt.plot(1e3 * stc_label.times, pca.T, 'b', linewidth=3)
+plt.legend([h0, h1, h2], ['mean', 'mean flip', 'PCA flip'])
+plt.xlabel('Time (ms)')
+plt.ylabel('Source amplitude')
+plt.title('Activations in Label : %s' % label)
+plt.show()
diff --git a/examples/inverse/plot_lcmv_beamformer.py b/examples/inverse/plot_lcmv_beamformer.py
index 519ec68..294b7a5 100644
--- a/examples/inverse/plot_lcmv_beamformer.py
+++ b/examples/inverse/plot_lcmv_beamformer.py
@@ -14,7 +14,7 @@ of source orientation and stores the solutions in stc files for visualisation.
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
import numpy as np
import mne
@@ -58,12 +58,13 @@ noise_cov = mne.cov.regularize(noise_cov, evoked.info,
data_cov = mne.compute_covariance(epochs, tmin=0.04, tmax=0.15)
-pl.close('all')
+plt.close('all')
-pick_oris = [None, 'max-power']
-names = ['free', 'max-power']
-descriptions = ['Free orientation', 'Max-power orientation']
-colors = ['b', 'r']
+pick_oris = [None, 'normal', 'max-power']
+names = ['free', 'normal', 'max-power']
+descriptions = ['Free orientation', 'Normal orientation', 'Max-power '
+ 'orientation']
+colors = ['b', 'k', 'r']
for pick_ori, name, desc, color in zip(pick_oris, names, descriptions, colors):
stc = lcmv(evoked, forward, noise_cov, data_cov, reg=0.01,
@@ -75,11 +76,11 @@ for pick_ori, name, desc, color in zip(pick_oris, names, descriptions, colors):
# View activation time-series
data, times, _ = mne.label_time_courses(fname_label, "lcmv-" + name +
"-lh.stc")
- pl.plot(1e3 * times, np.mean(data, axis=0), color, hold=True, label=desc)
-
-pl.xlabel('Time (ms)')
-pl.ylabel('LCMV value')
-pl.ylim(-0.8, 2.2)
-pl.title('LCMV in %s' % label_name)
-pl.legend()
-pl.show()
+ plt.plot(1e3 * times, np.mean(data, axis=0), color, hold=True, label=desc)
+
+plt.xlabel('Time (ms)')
+plt.ylabel('LCMV value')
+plt.ylim(-0.8, 2.2)
+plt.title('LCMV in %s' % label_name)
+plt.legend()
+plt.show()
diff --git a/examples/inverse/plot_lcmv_beamformer_volume.py b/examples/inverse/plot_lcmv_beamformer_volume.py
index 4f57a73..6378564 100644
--- a/examples/inverse/plot_lcmv_beamformer_volume.py
+++ b/examples/inverse/plot_lcmv_beamformer_volume.py
@@ -16,7 +16,7 @@ Freeview.
print __doc__
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.datasets import sample
from mne.fiff import Raw, pick_types
@@ -58,7 +58,8 @@ noise_cov = mne.cov.regularize(noise_cov, evoked.info,
data_cov = mne.compute_covariance(epochs, tmin=0.04, tmax=0.15)
# Run free orientation (vector) beamformer. Source orientation can be
-# restricted by setting pick_ori to 'max-power'
+# restricted by setting pick_ori to 'max-power' (or 'normal' but only when
+# using a surface-based source space)
stc = lcmv(evoked, forward, noise_cov, data_cov, reg=0.01, pick_ori=None)
# Save result in stc files
@@ -71,20 +72,20 @@ img = mne.save_stc_as_volume('lcmv_inverse.nii.gz', stc,
forward['src'], mri_resolution=False) # True for full MRI resolution
# plot result (one slice)
-pl.close('all')
+plt.close('all')
data = img.get_data()
coronal_slice = data[:, 10, :, 60]
-pl.figure()
-pl.imshow(np.ma.masked_less(coronal_slice, 1), cmap=pl.cm.Reds,
- interpolation='nearest')
-pl.colorbar()
-pl.contour(coronal_slice != 0, 1, colors=['black'])
-pl.xticks([])
-pl.yticks([])
+plt.figure()
+plt.imshow(np.ma.masked_less(coronal_slice, 1), cmap=plt.cm.Reds,
+ interpolation='nearest')
+plt.colorbar()
+plt.contour(coronal_slice != 0, 1, colors=['black'])
+plt.xticks([])
+plt.yticks([])
# plot source time courses with the maximum peak amplitudes
-pl.figure()
-pl.plot(stc.times, stc.data[np.argsort(np.max(stc.data, axis=1))[-40:]].T)
-pl.xlabel('Time (ms)')
-pl.ylabel('LCMV value')
-pl.show()
+plt.figure()
+plt.plot(stc.times, stc.data[np.argsort(np.max(stc.data, axis=1))[-40:]].T)
+plt.xlabel('Time (ms)')
+plt.ylabel('LCMV value')
+plt.show()
diff --git a/examples/inverse/plot_make_inverse_operator.py b/examples/inverse/plot_make_inverse_operator.py
index d198576..eeafd48 100644
--- a/examples/inverse/plot_make_inverse_operator.py
+++ b/examples/inverse/plot_make_inverse_operator.py
@@ -15,12 +15,12 @@ in stc files for visualisation.
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.datasets import sample
from mne.fiff import Evoked
-from mne.minimum_norm import make_inverse_operator, apply_inverse, \
- write_inverse_operator
+from mne.minimum_norm import (make_inverse_operator, apply_inverse,
+ write_inverse_operator)
data_path = sample.data_path()
fname_fwd_meeg = data_path + '/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif'
@@ -50,9 +50,9 @@ info = evoked.info
inverse_operator_meeg = make_inverse_operator(info, forward_meeg, noise_cov,
loose=0.2, depth=0.8)
inverse_operator_meg = make_inverse_operator(info, forward_meg, noise_cov,
- loose=0.2, depth=0.8)
+ loose=0.2, depth=0.8)
inverse_operator_eeg = make_inverse_operator(info, forward_eeg, noise_cov,
- loose=0.2, depth=0.8)
+ loose=0.2, depth=0.8)
write_inverse_operator('sample_audvis-meeg-oct-6-inv.fif',
inverse_operator_meeg)
@@ -64,11 +64,11 @@ write_inverse_operator('sample_audvis-eeg-oct-6-inv.fif',
# Compute inverse solution
stcs = dict()
stcs['meeg'] = apply_inverse(evoked, inverse_operator_meeg, lambda2, "dSPM",
- pick_normal=False)
+ pick_ori=None)
stcs['meg'] = apply_inverse(evoked, inverse_operator_meg, lambda2, "dSPM",
- pick_normal=False)
+ pick_ori=None)
stcs['eeg'] = apply_inverse(evoked, inverse_operator_eeg, lambda2, "dSPM",
- pick_normal=False)
+ pick_ori=None)
# Save result in stc files
names = ['meeg', 'meg', 'eeg']
@@ -77,13 +77,13 @@ for name in names:
###############################################################################
# View activation time-series
-pl.close('all')
-pl.figure(figsize=(8, 6))
+plt.close('all')
+plt.figure(figsize=(8, 6))
for ii in range(len(stcs)):
name = names[ii]
stc = stcs[name]
- pl.subplot(len(stcs), 1, ii + 1)
- pl.plot(1e3 * stc.times, stc.data[::150, :].T)
- pl.ylabel('%s\ndSPM value' % str.upper(name))
-pl.xlabel('time (ms)')
-pl.show()
\ No newline at end of file
+ plt.subplot(len(stcs), 1, ii + 1)
+ plt.plot(1e3 * stc.times, stc.data[::150, :].T)
+ plt.ylabel('%s\ndSPM value' % str.upper(name))
+plt.xlabel('time (ms)')
+plt.show()
diff --git a/examples/inverse/plot_mixed_norm_L21_inverse.py b/examples/inverse/plot_mixed_norm_L21_inverse.py
index edb1e1e..4f9b9ff 100644
--- a/examples/inverse/plot_mixed_norm_L21_inverse.py
+++ b/examples/inverse/plot_mixed_norm_L21_inverse.py
@@ -38,8 +38,8 @@ forward = mne.read_forward_solution(fwd_fname, surf_ori=True)
cov = mne.cov.regularize(cov, evoked.info)
-import pylab as pl
-pl.figure()
+import matplotlib.pyplot as plt
+plt.figure()
ylim = dict(eeg=[-10, 10], grad=[-400, 400], mag=[-600, 600])
evoked.plot(ylim=ylim, proj=True)
@@ -56,11 +56,11 @@ stc_dspm = apply_inverse(evoked, inverse_operator, lambda2=1. / 9.,
# Compute MxNE inverse solution
stc, residual = mixed_norm(evoked, forward, cov, alpha, loose=loose,
- depth=depth, maxit=3000, tol=1e-4, active_set_size=10,
- debias=True, weights=stc_dspm, weights_min=8.,
- return_residual=True)
+ depth=depth, maxit=3000, tol=1e-4,
+ active_set_size=10, debias=True, weights=stc_dspm,
+ weights_min=8., return_residual=True)
-pl.figure()
+plt.figure()
residual.plot(ylim=ylim, proj=True)
###############################################################################
diff --git a/examples/inverse/plot_morph_data.py b/examples/inverse/plot_morph_data.py
index df1aab3..af589f2 100644
--- a/examples/inverse/plot_morph_data.py
+++ b/examples/inverse/plot_morph_data.py
@@ -47,11 +47,11 @@ stc_to_2 = mne.morph_data_precomputed(subject_from, subject_to,
stc_to_2.save('%s_audvis-meg_2' % subject_to)
# View source activations
-import pylab as pl
-pl.plot(stc_from.times, stc_from.data.mean(axis=0), 'r', label='from')
-pl.plot(stc_to.times, stc_to.data.mean(axis=0), 'b', label='to')
-pl.plot(stc_to_2.times, stc_to.data.mean(axis=0), 'g', label='to_2')
-pl.xlabel('time (ms)')
-pl.ylabel('Mean Source amplitude')
-pl.legend()
-pl.show()
+import matplotlib.pyplot as plt
+plt.plot(stc_from.times, stc_from.data.mean(axis=0), 'r', label='from')
+plt.plot(stc_to.times, stc_to.data.mean(axis=0), 'b', label='to')
+plt.plot(stc_to_2.times, stc_to.data.mean(axis=0), 'g', label='to_2')
+plt.xlabel('time (ms)')
+plt.ylabel('Mean Source amplitude')
+plt.legend()
+plt.show()
diff --git a/examples/inverse/plot_read_stc.py b/examples/inverse/plot_read_stc.py
index f1b3aa4..3e483c8 100644
--- a/examples/inverse/plot_read_stc.py
+++ b/examples/inverse/plot_read_stc.py
@@ -25,8 +25,8 @@ print "stc data size: %s (nb of vertices) x %s (nb of samples)" % (
n_vertices, n_samples)
# View source activations
-import pylab as pl
-pl.plot(stc.times, stc.data[::100, :].T)
-pl.xlabel('time (ms)')
-pl.ylabel('Source amplitude')
-pl.show()
+import matplotlib.pyplot as plt
+plt.plot(stc.times, stc.data[::100, :].T)
+plt.xlabel('time (ms)')
+plt.ylabel('Source amplitude')
+plt.show()
diff --git a/examples/inverse/plot_tf_dics.py b/examples/inverse/plot_tf_dics.py
new file mode 100644
index 0000000..0b583d0
--- /dev/null
+++ b/examples/inverse/plot_tf_dics.py
@@ -0,0 +1,116 @@
+"""
+=====================================
+Time-frequency beamforming using DICS
+=====================================
+
+Compute DICS source power in a grid of time-frequency windows and display
+results.
+
+The original reference is:
+Dalal et al. Five-dimensional neuroimaging: Localization of the time-frequency
+dynamics of cortical activity. NeuroImage (2008) vol. 40 (4) pp. 1686-1700
+"""
+
+# Author: Roman Goj <roman.goj at gmail.com>
+#
+# License: BSD (3-clause)
+
+print __doc__
+
+import mne
+from mne.fiff import Raw
+from mne.event import make_fixed_length_events
+from mne.datasets import sample
+from mne.time_frequency import compute_epochs_csd
+from mne.beamformer import tf_dics
+from mne.viz import plot_source_spectrogram
+
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
+noise_fname = data_path + '/MEG/sample/ernoise_raw.fif'
+event_fname = data_path + '/MEG/sample/sample_audvis_raw-eve.fif'
+fname_fwd = data_path + '/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif'
+subjects_dir = data_path + '/subjects'
+label_name = 'Aud-lh'
+fname_label = data_path + '/MEG/sample/labels/%s.label' % label_name
+
+###############################################################################
+# Read raw data
+raw = Raw(raw_fname)
+raw.info['bads'] = ['MEG 2443'] # 1 bad MEG channel
+
+# Pick a selection of magnetometer channels. A subset of all channels was used
+# to speed up the example. For a solution based on all MEG channels use
+# meg=True, selection=None and add mag=4e-12 to the reject dictionary.
+left_temporal_channels = mne.read_selection('Left-temporal')
+picks = mne.fiff.pick_types(raw.info, meg='mag', eeg=False, eog=False,
+ stim=False, exclude='bads',
+ selection=left_temporal_channels)
+reject = dict(mag=4e-12)
+
+# Read epochs
+event_id, epoch_tmin, epoch_tmax = 1, -0.3, 0.5
+events = mne.read_events(event_fname)
+epochs = mne.Epochs(raw, events, event_id, epoch_tmin, epoch_tmax, proj=True,
+ picks=picks, baseline=(None, 0), preload=True,
+ reject=reject)
+
+# Read empty room noise raw data
+raw_noise = Raw(noise_fname)
+raw_noise.info['bads'] = ['MEG 2443'] # 1 bad MEG channel
+
+# Create noise epochs and make sure the number of noise epochs corresponds to
+# the number of data epochs
+events_noise = make_fixed_length_events(raw_noise, event_id)
+epochs_noise = mne.Epochs(raw_noise, events_noise, event_id, epoch_tmin,
+ epoch_tmax, proj=True, picks=picks,
+ baseline=(None, 0), preload=True,
+ reject=reject)
+# then make sure the number of epochs is the same
+epochs_noise = epochs_noise[:len(epochs.events)]
+
+# Read forward operator
+forward = mne.read_forward_solution(fname_fwd, surf_ori=True)
+
+# Read label
+label = mne.read_label(fname_label)
+
+###############################################################################
+# Time-frequency beamforming based on DICS
+
+# Setting frequency bins as in Dalal et al. 2008
+freq_bins = [(4, 12), (12, 30), (30, 55), (65, 300)] # Hz
+win_lengths = [0.3, 0.2, 0.15, 0.1] # s
+# Then set FFTs length for each frequency range.
+# Should be a power of 2 to be faster.
+n_ffts = [256, 128, 128, 128]
+
+# Setting time windows, please note tmin stretches over the baseline, which is
+# selected to be as long as the longest time window. This enables a smooth and
+# accurate localization of activity in time
+tmin = -0.3 # s
+tmax = 0.5 # s
+tstep = 0.05 # s
+
+# Subtract evoked response prior to computation?
+subtract_evoked = False
+
+# Calculating noise cross-spectral density from empty room noise for each
+# frequency bin and the corresponding time window length. To calculate noise
+# from the baseline period in the data, change epochs_noise to epochs
+noise_csds = []
+for freq_bin, win_length, n_fft in zip(freq_bins, win_lengths, n_ffts):
+ noise_csd = compute_epochs_csd(epochs_noise, mode='fourier',
+ fmin=freq_bin[0], fmax=freq_bin[1],
+ fsum=True, tmin=tmin,
+ tmax=tmin + win_length, n_fft=n_fft)
+ noise_csds.append(noise_csd)
+
+# Computing DICS solutions for time-frequency windows in a label in source
+# space for faster computation, use label=None for full solution
+stcs = tf_dics(epochs, forward, noise_csds, tmin, tmax, tstep, win_lengths,
+ freq_bins=freq_bins, subtract_evoked=subtract_evoked,
+ n_ffts=n_ffts, reg=0.001, label=label)
+
+# Plotting source spectrogram for source with maximum activity
+plot_source_spectrogram(stcs, freq_bins, source_index=None, colorbar=True)
diff --git a/examples/inverse/plot_tf_lcmv.py b/examples/inverse/plot_tf_lcmv.py
new file mode 100644
index 0000000..e65482e
--- /dev/null
+++ b/examples/inverse/plot_tf_lcmv.py
@@ -0,0 +1,130 @@
+"""
+=====================================
+Time-frequency beamforming using LCMV
+=====================================
+
+Compute LCMV source power in a grid of time-frequency windows and display
+results.
+
+The original reference is:
+Dalal et al. Five-dimensional neuroimaging: Localization of the time-frequency
+dynamics of cortical activity. NeuroImage (2008) vol. 40 (4) pp. 1686-1700
+"""
+
+# Author: Roman Goj <roman.goj at gmail.com>
+#
+# License: BSD (3-clause)
+
+print __doc__
+
+import mne
+from mne import compute_covariance
+from mne.fiff import Raw
+from mne.datasets import sample
+from mne.event import make_fixed_length_events
+from mne.beamformer import tf_lcmv
+from mne.viz import plot_source_spectrogram
+
+
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
+noise_fname = data_path + '/MEG/sample/ernoise_raw.fif'
+event_fname = data_path + '/MEG/sample/sample_audvis_raw-eve.fif'
+fname_fwd = data_path + '/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif'
+subjects_dir = data_path + '/subjects'
+label_name = 'Aud-lh'
+fname_label = data_path + '/MEG/sample/labels/%s.label' % label_name
+
+###############################################################################
+# Read raw data, preload to allow filtering
+raw = Raw(raw_fname, preload=True)
+raw.info['bads'] = ['MEG 2443'] # 1 bad MEG channel
+
+# Pick a selection of magnetometer channels. A subset of all channels was used
+# to speed up the example. For a solution based on all MEG channels use
+# meg=True, selection=None and add grad=4000e-13 to the reject dictionary.
+left_temporal_channels = mne.read_selection('Left-temporal')
+picks = mne.fiff.pick_types(raw.info, meg='mag', eeg=False, eog=False,
+ stim=False, exclude='bads',
+ selection=left_temporal_channels)
+reject = dict(mag=4e-12)
+
+# Read epochs. Note that preload is set to False to enable tf_lcmv to read the
+# underlying raw object from epochs.raw, which would be set to None during
+# preloading. Filtering is then performed on raw data in tf_lcmv and the epochs
+# parameters passed here are used to create epochs from filtered data. However,
+# reading epochs without preloading means that bad epoch rejection is delayed
+# until later. To perform bad epoch rejection based on the reject parameter
+# passed here, run epochs.drop_bad_epochs(). This is done automatically in
+# tf_lcmv to reject bad epochs based on unfiltered data.
+event_id, tmin, tmax = 1, -0.3, 0.5
+events = mne.read_events(event_fname)
+epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ picks=picks, baseline=(None, 0), preload=False,
+ reject=reject)
+
+# Read empty room noise, preload to allow filtering
+raw_noise = Raw(noise_fname, preload=True)
+raw_noise.info['bads'] = ['MEG 2443'] # 1 bad MEG channel
+
+# Create artificial events for empty room noise data
+events_noise = make_fixed_length_events(raw_noise, event_id, duration=1.)
+# Create an epochs object using preload=True to reject bad epochs based on
+# unfiltered data
+epochs_noise = mne.Epochs(raw_noise, events_noise, event_id, tmin, tmax,
+ proj=True, picks=picks, baseline=(None, 0),
+ preload=True, reject=reject)
+
+# Make sure the number of noise epochs is the same as data epochs
+epochs_noise = epochs_noise[:len(epochs.events)]
+
+# Read forward operator
+forward = mne.read_forward_solution(fname_fwd, surf_ori=True)
+
+# Read label
+label = mne.read_label(fname_label)
+
+###############################################################################
+# Time-frequency beamforming based on LCMV
+
+# Setting frequency bins as in Dalal et al. 2008 (high gamma was subdivided)
+freq_bins = [(4, 12), (12, 30), (30, 55), (65, 299)] # Hz
+win_lengths = [0.3, 0.2, 0.15, 0.1] # s
+
+# Setting the time step
+tstep = 0.05
+
+# Setting the noise covariance and whitened data covariance regularization
+# parameters
+noise_reg = 0.03
+data_reg = 0.001
+
+# Subtract evoked response prior to computation?
+subtract_evoked = False
+
+# Calculating covariance from empty room noise. To use baseline data as noise
+# substitute raw for raw_noise, epochs for epochs_noise, and 0 for tmax.
+# Note, if using baseline data, the averaged evoked response in the baseline
+# epoch should be flat.
+noise_covs = []
+for (l_freq, h_freq) in freq_bins:
+ raw_band = raw_noise.copy()
+ raw_band.filter(l_freq, h_freq, picks=epochs.picks, method='iir', n_jobs=1)
+ epochs_band = mne.Epochs(raw_band, epochs_noise.events, event_id,
+ tmin=tmin, tmax=tmax, picks=epochs.picks,
+ proj=True)
+
+ noise_cov = compute_covariance(epochs_band)
+ noise_cov = mne.cov.regularize(noise_cov, epochs_band.info, mag=noise_reg,
+ grad=noise_reg, eeg=noise_reg, proj=True)
+ noise_covs.append(noise_cov)
+ del raw_band # to save memory
+
+# Computing LCMV solutions for time-frequency windows in a label in source
+# space for faster computation, use label=None for full solution
+stcs = tf_lcmv(epochs, forward, noise_covs, tmin, tmax, tstep, win_lengths,
+ freq_bins=freq_bins, subtract_evoked=subtract_evoked,
+ reg=data_reg, label=label)
+
+# Plotting source spectrogram for source with maximum activity
+plot_source_spectrogram(stcs, freq_bins, source_index=None, colorbar=True)
diff --git a/examples/inverse/plot_time_frequency_mixed_norm_inverse.py b/examples/inverse/plot_time_frequency_mixed_norm_inverse.py
index 754a3fd..48f2a27 100644
--- a/examples/inverse/plot_time_frequency_mixed_norm_inverse.py
+++ b/examples/inverse/plot_time_frequency_mixed_norm_inverse.py
@@ -86,23 +86,24 @@ stc_dspm = apply_inverse(evoked, inverse_operator, lambda2=1. / 9.,
# Compute TF-MxNE inverse solution
stc, residual = tf_mixed_norm(evoked, forward, cov, alpha_space, alpha_time,
- loose=loose, depth=depth, maxit=200, tol=1e-4,
- weights=stc_dspm, weights_min=8., debias=True,
- wsize=16, tstep=4, window=0.05, return_residual=True)
+ loose=loose, depth=depth, maxit=200, tol=1e-4,
+ weights=stc_dspm, weights_min=8., debias=True,
+ wsize=16, tstep=4, window=0.05,
+ return_residual=True)
# Crop to remove edges
stc.crop(tmin=-0.05, tmax=0.3)
evoked.crop(tmin=-0.05, tmax=0.3)
residual.crop(tmin=-0.05, tmax=0.3)
-import pylab as pl
-pl.figure()
+import matplotlib.pyplot as plt
+plt.figure()
ylim = dict(eeg=[-10, 10], grad=[-200, 250], mag=[-600, 600])
picks = fiff.pick_types(evoked.info, meg='grad', exclude='bads')
evoked.plot(picks=picks, ylim=ylim, proj=True,
titles=dict(grad='Evoked Response (grad)'))
-pl.figure()
+plt.figure()
picks = fiff.pick_types(residual.info, meg='grad', exclude='bads')
residual.plot(picks=picks, ylim=ylim, proj=True,
titles=dict(grad='Residual (grad)'))
diff --git a/examples/plot_channel_epochs_image.py b/examples/plot_channel_epochs_image.py
index 74121d5..61dc87d 100644
--- a/examples/plot_channel_epochs_image.py
+++ b/examples/plot_channel_epochs_image.py
@@ -24,7 +24,7 @@ print __doc__
# License: BSD (3-clause)
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne import fiff
@@ -57,16 +57,18 @@ epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
# and order with spectral reordering
# If you don't have scikit-learn installed set order_func to None
from sklearn.cluster.spectral import spectral_embedding
+from sklearn.metrics.pairwise import rbf_kernel
def order_func(times, data):
this_data = data[:, (times > 0.0) & (times < 0.350)]
- return np.argsort(spectral_embedding(np.corrcoef(this_data),
+ this_data /= np.sqrt(np.sum(this_data ** 2, axis=1))[:, np.newaxis]
+ return np.argsort(spectral_embedding(rbf_kernel(this_data, gamma=1.),
n_components=1, random_state=0).ravel())
good_pick = 97 # channel with a clear evoked response
bad_pick = 98 # channel with no evoked response
-pl.close('all')
+plt.close('all')
mne.viz.plot_image_epochs(epochs, [good_pick, bad_pick], sigma=0.5, vmin=-100,
- vmax=250, colorbar=True, order=order_func, show=True)
+ vmax=250, colorbar=True, order=order_func, show=True)
diff --git a/examples/plot_decimate_head_surface.py b/examples/plot_decimate_head_surface.py
new file mode 100644
index 0000000..99d71d4
--- /dev/null
+++ b/examples/plot_decimate_head_surface.py
@@ -0,0 +1,39 @@
+"""
+========================
+Decimating scalp surface
+========================
+
+This can be useful to reduce computation time when
+using a cloud of digitization points for coordinate alignment
+instead of e.g. EEG-cap positions.
+
+"""
+print __doc__
+
+# Authors: Denis Engemann <d.engemann at fz-juelich.de>
+# Alexandre Gramfort <alexandre.gramfort at telecom-paristech.fr>
+#
+# License: BSD (3-clause)
+
+import mne
+from mne.surface import decimate_surface
+
+path = mne.datasets.sample.data_path()
+surf = mne.read_bem_surfaces(path + '/subjects/sample/bem/sample-head.fif')[0]
+
+points, triangles = surf['rr'], surf['tris']
+
+# reduce to 30000 meshes equaling ${SUBJECT}-head-medium.fif output from
+# mne_make_scalp_surfaces.py and mne_make_scalp_surfaces
+points_dec, triangles_dec = decimate_surface(points, triangles,
+ n_triangles=30000)
+
+try:
+ from enthought.mayavi import mlab
+except:
+ from mayavi import mlab
+
+head_col = (0.95, 0.83, 0.83) # light pink
+
+p, t = points_dec, triangles_dec
+mlab.triangular_mesh(p[:, 0], p[:, 1], p[:, 2], t, color=head_col)
diff --git a/examples/plot_define_target_events.py b/examples/plot_define_target_events.py
index 468f867..f5027db 100644
--- a/examples/plot_define_target_events.py
+++ b/examples/plot_define_target_events.py
@@ -54,7 +54,7 @@ new_id = 42 # the new event id for a hit. If None, reference_id is used.
fill_na = 99 # the fill value for misses
events_, lag = define_target_events(events, reference_id, target_id,
- sfreq, tmin, tmax, new_id, fill_na)
+ sfreq, tmin, tmax, new_id, fill_na)
print events_ # The 99 indicates missing or too late button presses
@@ -81,18 +81,18 @@ early, late = [epochs[k].average() for k in event_id]
###############################################################################
# View evoked response
-import pylab as pl
+import matplotlib.pyplot as plt
times = 1e3 * epochs.times # time in milliseconds
title = 'Evoked response followed by %s button press'
-pl.clf()
-ax = pl.subplot(2, 1, 1)
+plt.clf()
+ax = plt.subplot(2, 1, 1)
early.plot(axes=ax)
-pl.title(title % 'late')
-pl.ylabel('Evoked field (fT)')
-ax = pl.subplot(2, 1, 2)
+plt.title(title % 'late')
+plt.ylabel('Evoked field (fT)')
+ax = plt.subplot(2, 1, 2)
late.plot(axes=ax)
-pl.title(title % 'early')
-pl.ylabel('Evoked field (fT)')
-pl.show()
+plt.title(title % 'early')
+plt.ylabel('Evoked field (fT)')
+plt.show()
diff --git a/examples/plot_evoked_delayed_ssp.py b/examples/plot_evoked_delayed_ssp.py
index b41c65f..313f944 100644
--- a/examples/plot_evoked_delayed_ssp.py
+++ b/examples/plot_evoked_delayed_ssp.py
@@ -19,7 +19,7 @@ on the evoked data.
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne import fiff
from mne.datasets import sample
@@ -63,7 +63,7 @@ title = 'Incremental SSP application'
# let's first move the proj list to another location
projs, evoked.info['projs'] = evoked.info['projs'], []
-fig, axes = pl.subplots(2, 2) # create 4 subplots for our four vectors
+fig, axes = plt.subplots(2, 2) # create 4 subplots for our four vectors
# As the bulk of projectors was extracted from the same source, we can simply
# iterate over our collection of projs and add them step by step to see how
@@ -75,8 +75,8 @@ for proj, ax in zip(projs, axes.flatten()):
evoked.add_proj(proj) # add projection vectors loop by loop.
evoked.copy().apply_proj().plot(axes=ax) # apply on a copy of evoked
ax.set_title('+ %s' % proj['desc']) # extract description.
-pl.suptitle(title)
-pl.show()
+plt.suptitle(title)
+plt.show()
# We also could have easily visualized the impact of single projection vectors
# by deleting the vector directly after visualizing the changes.
@@ -88,8 +88,8 @@ pl.show()
# check box that allows us to reversibly select projection vectors. Any
# modification of the selection will immediately cause the figure to update.
-pl.figure()
+plt.figure()
evoked.plot(proj='interactive')
-pl.show()
+plt.show()
# Hint: the same works with evoked.plot_topomap
diff --git a/examples/plot_evoked_whitening.py b/examples/plot_evoked_whitening.py
index 0d4b98a..201333b 100644
--- a/examples/plot_evoked_whitening.py
+++ b/examples/plot_evoked_whitening.py
@@ -43,6 +43,5 @@ evoked_white = mne.whiten_evoked(evoked, noise_cov, picks, diag=True)
# plot the whitened evoked data to see if baseline signals match the
# assumption of Gaussian whiten noise from which we expect values around
# and less than 2 standard deviations.
-import pylab as pl
-pl.figure()
+import matplotlib.pyplot as plt
evoked_white.plot(picks=picks, unit=False, hline=[-2, 2])
diff --git a/examples/plot_from_raw_to_epochs_to_evoked.py b/examples/plot_from_raw_to_epochs_to_evoked.py
index 3590879..4646a73 100644
--- a/examples/plot_from_raw_to_epochs_to_evoked.py
+++ b/examples/plot_from_raw_to_epochs_to_evoked.py
@@ -9,6 +9,7 @@ data and then saved to disk.
"""
# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Denis A. Engemann <d.engemann at fz-juelich.de>
#
# License: BSD (3-clause)
@@ -42,7 +43,11 @@ picks = fiff.pick_types(raw.info, meg=False, eeg=True, stim=False, eog=True,
include=include, exclude='bads')
# Read epochs
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks,
- baseline=(None, 0), reject=dict(eeg=80e-6, eog=150e-6))
+ baseline=(None, 0), reject=dict(eeg=80e-6, eog=150e-6),
+ preload=True)
+
+epochs.plot()
+
evoked = epochs.average() # average epochs and get an Evoked dataset.
evoked.save('sample_audvis_eeg-ave.fif') # save evoked data to disk
@@ -50,14 +55,14 @@ evoked.save('sample_audvis_eeg-ave.fif') # save evoked data to disk
###############################################################################
# View evoked response
times = 1e3 * epochs.times # time in miliseconds
-import pylab as pl
-pl.figure()
+import matplotlib.pyplot as plt
+plt.figure()
evoked.plot()
-pl.xlim([times[0], times[-1]])
-pl.xlabel('time (ms)')
-pl.ylabel('Potential (uV)')
-pl.title('EEG evoked potential')
-pl.show()
+plt.xlim([times[0], times[-1]])
+plt.xlabel('time (ms)')
+plt.ylabel('Potential (uV)')
+plt.title('EEG evoked potential')
+plt.show()
# Look at channels that caused dropped events, showing that the subject's
# blinks were likely to blame for most epochs being dropped
diff --git a/examples/plot_from_raw_to_multiple_epochs_to_evoked.py b/examples/plot_from_raw_to_multiple_epochs_to_evoked.py
index 671bbcd..d0aa70c 100644
--- a/examples/plot_from_raw_to_multiple_epochs_to_evoked.py
+++ b/examples/plot_from_raw_to_multiple_epochs_to_evoked.py
@@ -58,14 +58,14 @@ fiff.write_evoked('sample_auditory_and_visual_eeg-ave.fif', evokeds)
###############################################################################
# View evoked response
-import pylab as pl
-pl.clf()
-ax = pl.subplot(2, 1, 1)
+import matplotlib.pyplot as plt
+plt.clf()
+ax = plt.subplot(2, 1, 1)
evokeds[0].plot(axes=ax)
-pl.title('EEG evoked potential, auditory trials')
-pl.ylabel('Potential (uV)')
-ax = pl.subplot(2, 1, 2)
+plt.title('EEG evoked potential, auditory trials')
+plt.ylabel('Potential (uV)')
+ax = plt.subplot(2, 1, 2)
evokeds[1].plot(axes=ax)
-pl.title('EEG evoked potential, visual trials')
-pl.ylabel('Potential (uV)')
-pl.show()
+plt.title('EEG evoked potential, visual trials')
+plt.ylabel('Potential (uV)')
+plt.show()
diff --git a/examples/plot_make_forward.py b/examples/plot_make_forward.py
new file mode 100644
index 0000000..8ac7951
--- /dev/null
+++ b/examples/plot_make_forward.py
@@ -0,0 +1,54 @@
+"""
+======================================================
+Create a forward operator and display sensitivity maps
+======================================================
+"""
+# Author: Eric Larson <larson.eric.d at gmail.com>
+#
+# License: BSD (3-clause)
+
+print __doc__
+
+import mne
+from mne.datasets import sample
+data_path = sample.data_path()
+
+raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
+mri = data_path + '/MEG/sample/sample_audvis_raw-trans.fif'
+src = data_path + '/subjects/sample/bem/sample-oct-6-src.fif'
+bem = data_path + '/subjects/sample/bem/sample-5120-5120-5120-bem-sol.fif'
+subjects_dir = data_path + '/subjects'
+
+fwd = mne.make_forward_solution(raw_fname, mri=mri, src=src, bem=bem,
+ fname=None, meg=True, eeg=True, mindist=5.0,
+ n_jobs=2, overwrite=True)
+
+# convert to surface orientation for better visualization
+fwd = mne.convert_forward_solution(fwd, surf_ori=True)
+leadfield = fwd['sol']['data']
+
+print "Leadfield size : %d x %d" % leadfield.shape
+
+grad_map = mne.sensitivity_map(fwd, ch_type='grad', mode='fixed')
+mag_map = mne.sensitivity_map(fwd, ch_type='mag', mode='fixed')
+eeg_map = mne.sensitivity_map(fwd, ch_type='eeg', mode='fixed')
+
+###############################################################################
+# Show gain matrix a.k.a. leadfield matrix with sensitivy map
+
+import matplotlib.pyplot as plt
+plt.matshow(leadfield[:, :500])
+plt.xlabel('sources')
+plt.ylabel('sensors')
+plt.title('Lead field matrix (500 dipoles only)')
+
+plt.figure()
+plt.hist([grad_map.data.ravel(), mag_map.data.ravel(), eeg_map.data.ravel()],
+ bins=20, label=['Gradiometers', 'Magnetometers', 'EEG'])
+plt.legend()
+plt.title('Normal orientation sensitivity')
+plt.show()
+
+args = dict(fmin=0.1, fmid=0.5, fmax=0.9, smoothing_steps=7)
+grad_map.plot(subject='sample', time_label='Gradiometer sensitivity',
+ subjects_dir=subjects_dir, **args)
diff --git a/examples/plot_megsim_data.py b/examples/plot_megsim_data.py
index 1126357..1521563 100644
--- a/examples/plot_megsim_data.py
+++ b/examples/plot_megsim_data.py
@@ -15,7 +15,7 @@ Gilliam K, Donahue CH, Montano R, Bryant JE, Scott A, Stephen JM
Realistic Simulated and Empirical Data. Neuroinformatics 10:141-158
"""
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.datasets.megsim import load_data
@@ -44,10 +44,10 @@ epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks,
baseline=(None, 0),
reject=dict(grad=4000e-13, mag=4e-12, eog=150e-6))
evoked = epochs.average() # average epochs and get an Evoked dataset.
-pl.figure()
+plt.figure()
evoked.plot()
# Compare to the simulated data
evoked_sim = mne.fiff.Evoked(evoked_fnames[0])
-pl.figure()
+plt.figure()
evoked_sim.plot()
diff --git a/examples/plot_megsim_data_single_trial.py b/examples/plot_megsim_data_single_trial.py
index 3d87ef1..7d2e568 100644
--- a/examples/plot_megsim_data_single_trial.py
+++ b/examples/plot_megsim_data_single_trial.py
@@ -15,7 +15,6 @@ Gilliam K, Donahue CH, Montano R, Bryant JE, Scott A, Stephen JM
Realistic Simulated and Empirical Data. Neuroinformatics 10:141-158
"""
-import pylab as pl
import mne
from mne.datasets.megsim import load_data
diff --git a/examples/plot_read_forward.py b/examples/plot_read_forward.py
index bef623c..3ca2947 100644
--- a/examples/plot_read_forward.py
+++ b/examples/plot_read_forward.py
@@ -14,6 +14,7 @@ from mne.datasets import sample
data_path = sample.data_path()
fname = data_path + '/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif'
+subjects_dir = data_path + '/subjects'
fwd = mne.read_forward_solution(fname, surf_ori=True)
leadfield = fwd['sol']['data']
@@ -27,18 +28,19 @@ eeg_map = mne.sensitivity_map(fwd, ch_type='eeg', mode='fixed')
###############################################################################
# Show gain matrix a.k.a. leadfield matrix with sensitivy map
-import pylab as pl
-pl.matshow(leadfield[:, :500])
-pl.xlabel('sources')
-pl.ylabel('sensors')
-pl.title('Lead field matrix (500 dipoles only)')
+import matplotlib.pyplot as plt
+plt.matshow(leadfield[:, :500])
+plt.xlabel('sources')
+plt.ylabel('sensors')
+plt.title('Lead field matrix (500 dipoles only)')
-pl.figure()
-pl.hist([grad_map.data.ravel(), mag_map.data.ravel(), eeg_map.data.ravel()],
- bins=20, label=['Gradiometers', 'Magnetometers', 'EEG'])
-pl.legend()
-pl.title('Normal orientation sensitivity')
-pl.show()
+plt.figure()
+plt.hist([grad_map.data.ravel(), mag_map.data.ravel(), eeg_map.data.ravel()],
+ bins=20, label=['Gradiometers', 'Magnetometers', 'EEG'])
+plt.legend()
+plt.title('Normal orientation sensitivity')
+plt.show()
args = dict(fmin=0.1, fmid=0.5, fmax=0.9, smoothing_steps=7)
-grad_map.plot(subject='sample', time_label='Gradiometers sensitivity', **args)
+grad_map.plot(subject='sample', time_label='Gradiometer sensitivity',
+ subjects_dir=subjects_dir, **args)
diff --git a/examples/plot_read_noise_covariance_matrix.py b/examples/plot_read_noise_covariance_matrix.py
index a997660..b583578 100644
--- a/examples/plot_read_noise_covariance_matrix.py
+++ b/examples/plot_read_noise_covariance_matrix.py
@@ -23,7 +23,7 @@ print cov
# Note: if you have the measurement info you can use mne.viz.plot_cov
-import pylab as pl
-pl.matshow(cov.data)
-pl.title('Noise covariance matrix (%d channels)' % cov.data.shape[0])
-pl.show()
+import matplotlib.pyplot as plt
+plt.matshow(cov.data)
+plt.title('Noise covariance matrix (%d channels)' % cov.data.shape[0])
+plt.show()
diff --git a/examples/plot_shift_evoked.py b/examples/plot_shift_evoked.py
index 4b6175c..bec25b5 100644
--- a/examples/plot_shift_evoked.py
+++ b/examples/plot_shift_evoked.py
@@ -10,7 +10,7 @@ Shifting time-scale in evoked data
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
from mne import fiff
from mne.datasets import sample
@@ -26,7 +26,7 @@ picks = fiff.pick_channels(ch_names=evoked.info['ch_names'],
include="MEG 2332", exclude="bad")
# Create subplots
-f, axarr = pl.subplots(3)
+f, axarr = plt.subplots(3)
evoked.plot(exclude=[], picks=picks, axes=axarr[0],
titles=dict(grad='Before time shifting'))
diff --git a/examples/plot_simulate_evoked_data.py b/examples/plot_simulate_evoked_data.py
index 4e36d26..8c954c9 100644
--- a/examples/plot_simulate_evoked_data.py
+++ b/examples/plot_simulate_evoked_data.py
@@ -10,7 +10,7 @@ Generate simulated evoked data
# License: BSD (3-clause)
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.fiff.pick import pick_types_evoked, pick_types_forward
@@ -76,10 +76,10 @@ evoked = generate_evoked(fwd, stc, evoked_template, cov, snr,
###############################################################################
# Plot
plot_sparse_source_estimates(fwd['src'], stc, bgcolor=(1, 1, 1),
- opacity=0.5, high_resolution=True)
+ opacity=0.5, high_resolution=True)
-pl.figure()
-pl.psd(evoked.data[0])
+plt.figure()
+plt.psd(evoked.data[0])
-pl.figure()
+plt.figure()
plot_evoked(evoked)
diff --git a/examples/plot_ssp_projs_sensitivity_map.py b/examples/plot_ssp_projs_sensitivity_map.py
index 79a19cd..c64bc2e 100644
--- a/examples/plot_ssp_projs_sensitivity_map.py
+++ b/examples/plot_ssp_projs_sensitivity_map.py
@@ -16,6 +16,7 @@ import mne
from mne.datasets import sample
data_path = sample.data_path()
+subjects_dir = data_path + '/subjects'
fname = data_path + '/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif'
ecg_fname = data_path + '/MEG/sample/sample_audvis_ecg_proj.fif'
@@ -30,9 +31,10 @@ ssp_ecg_map = mne.sensitivity_map(fwd, ch_type='grad', projs=projs,
###############################################################################
# Show sensitivy map
-import pylab as pl
-pl.hist(ssp_ecg_map.data.ravel())
-pl.show()
+import matplotlib.pyplot as plt
+plt.hist(ssp_ecg_map.data.ravel())
+plt.show()
-args = dict(fmin=0.2, fmid=0.6, fmax=1., smoothing_steps=7, hemi='rh')
+args = dict(fmin=0.2, fmid=0.6, fmax=1., smoothing_steps=7, hemi='rh',
+ subjects_dir=subjects_dir)
ssp_ecg_map.plot(subject='sample', time_label='ECG SSP sensitivity', **args)
diff --git a/examples/plot_ssp_projs_topomaps.py b/examples/plot_ssp_projs_topomaps.py
index 00451a6..5cec40e 100644
--- a/examples/plot_ssp_projs_topomaps.py
+++ b/examples/plot_ssp_projs_topomaps.py
@@ -12,7 +12,7 @@ The projections used are the ones correcting for ECG artifacts.
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.datasets import sample
data_path = sample.data_path()
@@ -26,6 +26,6 @@ projs = mne.read_proj(ecg_fname)
layouts = [mne.layouts.read_layout('Vectorview-all'),
mne.layouts.make_eeg_layout(evoked.info)]
-pl.figure(figsize=(10, 6))
+plt.figure(figsize=(10, 6))
mne.viz.plot_projs_topomap(projs, layout=layouts)
mne.viz.tight_layout()
diff --git a/examples/plot_topo_channel_epochs_image.py b/examples/plot_topo_channel_epochs_image.py
index f657e71..312b7be 100644
--- a/examples/plot_topo_channel_epochs_image.py
+++ b/examples/plot_topo_channel_epochs_image.py
@@ -16,7 +16,7 @@ print __doc__
#
# License: BSD (3-clause)
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne import fiff
@@ -52,4 +52,4 @@ layout = read_layout('Vectorview-all')
title = 'ERF images - MNE sample data'
mne.viz.plot_topo_image_epochs(epochs, layout, sigma=0.5, vmin=-200, vmax=200,
colorbar=True, title=title)
-pl.show()
+plt.show()
diff --git a/examples/plot_topo_compare_conditions.py b/examples/plot_topo_compare_conditions.py
index 230c59f..d1c3458 100644
--- a/examples/plot_topo_compare_conditions.py
+++ b/examples/plot_topo_compare_conditions.py
@@ -18,7 +18,7 @@ evoked responses.
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.fiff import Raw, pick_types
@@ -66,6 +66,6 @@ plot_topo(evokeds, color=colors, title=title)
conditions = [e.comment for e in evokeds]
for cond, col, pos in zip(conditions, colors, (0.025, 0.07)):
- pl.figtext(0.775, pos, cond, color=col, fontsize=12)
+ plt.figtext(0.775, pos, cond, color=col, fontsize=12)
-pl.show()
+plt.show()
diff --git a/examples/plot_topography.py b/examples/plot_topography.py
index a478988..5b5f0c5 100644
--- a/examples/plot_topography.py
+++ b/examples/plot_topography.py
@@ -11,7 +11,7 @@ Plot topographies for MEG sensors
print __doc__
-import pylab as pl
+import matplotlib.pyplot as plt
from mne import fiff
from mne.viz import plot_topo
@@ -27,4 +27,4 @@ evoked = fiff.read_evoked(fname, setno=0, baseline=(None, 0))
# Show topography
title = 'MNE sample data (condition : %s)' % evoked.comment
plot_topo(evoked, title=title)
-pl.show()
+plt.show()
diff --git a/examples/preprocessing/plot_find_ecg_artifacts.py b/examples/preprocessing/plot_find_ecg_artifacts.py
index 3d665a2..47ccf4a 100644
--- a/examples/preprocessing/plot_find_ecg_artifacts.py
+++ b/examples/preprocessing/plot_find_ecg_artifacts.py
@@ -13,7 +13,7 @@ Locate QRS component of ECG.
print __doc__
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne import fiff
from mne.datasets import sample
@@ -28,7 +28,7 @@ raw = fiff.Raw(raw_fname)
event_id = 999
ecg_events, _, _ = mne.preprocessing.find_ecg_events(raw, event_id,
- ch_name='MEG 1531')
+ ch_name='MEG 1531')
# Read epochs
picks = fiff.pick_types(raw.info, meg=False, eeg=False, stim=False, eog=False,
@@ -42,7 +42,7 @@ print "Number of detected ECG artifacts : %d" % len(data)
###############################################################################
# Plot ECG artifacts
-pl.plot(1e3 * epochs.times, np.squeeze(data).T)
-pl.xlabel('Times (ms)')
-pl.ylabel('ECG')
-pl.show()
+plt.plot(1e3 * epochs.times, np.squeeze(data).T)
+plt.xlabel('Times (ms)')
+plt.ylabel('ECG')
+plt.show()
diff --git a/examples/preprocessing/plot_find_eog_artifacts.py b/examples/preprocessing/plot_find_eog_artifacts.py
index 6945ff6..d59d0fe 100644
--- a/examples/preprocessing/plot_find_eog_artifacts.py
+++ b/examples/preprocessing/plot_find_eog_artifacts.py
@@ -13,7 +13,7 @@ Locate peaks of EOG to spot blinks and general EOG artifacts.
print __doc__
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne import fiff
from mne.datasets import sample
@@ -40,7 +40,7 @@ print "Number of detected EOG artifacts : %d" % len(data)
###############################################################################
# Plot EOG artifacts
-pl.plot(1e3 * epochs.times, np.squeeze(data).T)
-pl.xlabel('Times (ms)')
-pl.ylabel('EOG (muV)')
-pl.show()
+plt.plot(1e3 * epochs.times, np.squeeze(data).T)
+plt.xlabel('Times (ms)')
+plt.ylabel('EOG (muV)')
+plt.show()
diff --git a/examples/preprocessing/plot_ica_from_epochs.py b/examples/preprocessing/plot_ica_from_epochs.py
index 95dc0c7..95f56a2 100644
--- a/examples/preprocessing/plot_ica_from_epochs.py
+++ b/examples/preprocessing/plot_ica_from_epochs.py
@@ -17,7 +17,7 @@ print __doc__
#
# License: BSD (3-clause)
-import matplotlib.pylab as pl
+import matplotlib.pyplot as plt
import numpy as np
import mne
from mne.fiff import Raw
@@ -31,6 +31,7 @@ data_path = sample.data_path()
raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
raw = Raw(raw_fname, preload=True)
+raw.apply_proj()
picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False, eog=True,
ecg=True, stim=False, exclude='bads')
@@ -43,17 +44,26 @@ events = mne.find_events(raw, stim_channel='STI 014')
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=False, picks=picks,
baseline=baseline, preload=True, reject=reject)
+random_state = np.random.RandomState(42)
+
###############################################################################
# Setup ICA seed decompose data, then access and plot sources.
# for more background information visit the plot_ica_from_raw.py example
# fit sources from epochs or from raw (both works for epochs)
ica = ICA(n_components=0.90, n_pca_components=64, max_pca_components=100,
- noise_cov=None, random_state=0)
+ noise_cov=None, random_state=random_state)
-ica.decompose_epochs(epochs)
+ica.decompose_epochs(epochs, decim=2)
print ica
+# plot spatial sensitivities of a few ICA components
+title = 'Spatial patterns of ICA components (Magnetometers)'
+source_idx = range(35, 50)
+ica.plot_topomap(source_idx, ch_type='mag')
+plt.suptitle(title, fontsize=12)
+
+
###############################################################################
# Automatically find ECG and EOG component using correlation coefficient.
@@ -61,26 +71,17 @@ print ica
# beats: 'MEG 1531'. We can directly pass the name to the find_sources method.
# In our example, the find_sources method returns and array of correlation
# scores for each ICA source.
-
-ecg_scores = ica.find_sources_epochs(epochs, target='MEG 1531',
+ecg_ch_name = 'MEG 1531'
+ecg_scores = ica.find_sources_epochs(epochs, target=ecg_ch_name,
score_func='pearsonr')
-# get maximum correlation index for ECG
-ecg_source_idx = np.abs(ecg_scores).argmax()
-
-# get sources from concatenated epochs
-sources = ica.get_sources_epochs(epochs, concatenate=True)
+# get the source most correlated with the ECG.
+ecg_source_idx = np.argsort(np.abs(ecg_scores))[-1]
-# plot first epoch
-times = epochs.times
-first_trial = np.arange(len(times))
-
-pl.figure()
-pl.title('Source most correlated with the ECG channel')
-pl.plot(times, sources[ecg_source_idx, first_trial].T, color='r')
-pl.xlabel('Time (s)')
-pl.ylabel('AU')
-pl.show()
+# get sources as epochs object and inspect some trial
+some_trial = 10
+title = 'Source most similar to ECG'
+ica.plot_sources_epochs(epochs[some_trial], ecg_source_idx, title=title)
# As we have an EOG channel, we can use it to detect the source.
eog_scores = ica.find_sources_epochs(epochs, target='EOG 061',
@@ -89,36 +90,39 @@ eog_scores = ica.find_sources_epochs(epochs, target='EOG 061',
# get maximum correlation index for EOG
eog_source_idx = np.abs(eog_scores).argmax()
-# compute times for concatenated epochs
-times = np.linspace(times[0], times[-1] * len(epochs), sources.shape[1])
-
# As the subject did not constantly move her eyes, the movement artifacts
# may remain hidden when plotting single epochs.
# Plotting the identified source across epochs reveals
# considerable EOG artifacts.
-
-pl.figure()
-pl.title('Source most correlated with the EOG channel')
-pl.plot(times, sources[eog_source_idx].T, color='r')
-pl.xlabel('Time (s)')
-pl.ylabel('AU')
-pl.xlim(times[[0, -1]])
-pl.show()
+title = 'Source most similar to EOG'
+ica.plot_sources_epochs(epochs, eog_source_idx, title=title)
###############################################################################
# Reject artifact sources and compare results
-# Add the detected artifact indices to ica.exclude
+# Add detected artifact sources to exclusion list
ica.exclude += [ecg_source_idx, eog_source_idx]
# Restore sensor space data
epochs_ica = ica.pick_sources_epochs(epochs)
+
# First show unprocessed, then cleaned epochs
-for e in epochs, epochs_ica:
- pl.figure()
- e.average().plot()
- pl.show()
+mags = mne.fiff.pick_types(epochs.info, meg='mag', exclude=[])
+fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
+times = epochs.times * 1e3
+scale = 1e15
+titles = ['raw - ', 'cleaned - ']
+ecg_ch = epochs.ch_names.index(ecg_ch_name)
+for e, (ax1, ax2), title in zip([epochs, epochs_ica], axes.T, titles):
+ ax1.plot(times, e.average(mags).data.T * scale, color='k')
+ ax1.set_title(title + 'evoked')
+ ax2.plot(times, e._data[some_trial, ecg_ch].T * scale, color='r')
+ ax2.set_title(title + 'single trial')
+ if title == 'raw':
+ ax1.set_ylabel('data (fT)')
+ else:
+ ax2.set_xlabel('Time (ms)')
###############################################################################
# Inspect evoked ICA sources
@@ -129,7 +133,7 @@ ica_epochs = ica.sources_as_epochs(epochs)
# don't exclude bad sources by passing an empty list.
ica_picks = mne.fiff.pick_types(ica_epochs.info, misc=True, exclude=[])
ica_evoked = ica_epochs.average(ica_picks)
-pl.figure()
+plt.figure()
ica_evoked.plot(titles=dict(misc='ICA sources'))
# Tip: use this for epochs constructed around ECG r-peaks to check whether all
diff --git a/examples/preprocessing/plot_ica_from_raw.py b/examples/preprocessing/plot_ica_from_raw.py
index 8579184..ba9a848 100644
--- a/examples/preprocessing/plot_ica_from_raw.py
+++ b/examples/preprocessing/plot_ica_from_raw.py
@@ -19,12 +19,13 @@ print __doc__
# License: BSD (3-clause)
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.fiff import Raw
from mne.preprocessing.ica import ICA
from mne.datasets import sample
+from mne.filter import band_pass_filter
###############################################################################
# Setup paths and prepare raw data
@@ -47,24 +48,20 @@ picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False, eog=False,
# additional PCA components up to rank 64 of the MEG data.
# This allows to control the trade-off between denoising and preserving signal.
-ica = ICA(n_components=0.90, n_pca_components=64, max_pca_components=100,
- noise_cov=None, random_state=0)
+ica = ICA(n_components=0.90, n_pca_components=None, max_pca_components=100,
+ random_state=0)
# 1 minute exposure should be sufficient for artifact detection.
# However, rejection performance may significantly improve when using
# the entire data range
-start, stop = 100., 160. # floats, otherwise it will be interpreted as index
-
-# decompose sources for raw data
-ica.decompose_raw(raw, start=start, stop=stop, picks=picks)
+# decompose sources for raw data using each third sample.
+ica.decompose_raw(raw, picks=picks, decim=3)
print ica
-sources = ica.get_sources_raw(raw, start=start, stop=stop)
-
# plot reasonable time window for inspection
start_plot, stop_plot = 100., 103.
-ica.plot_sources_raw(raw, start=start_plot, stop=stop_plot)
+ica.plot_sources_raw(raw, range(30), start=start_plot, stop=stop_plot)
###############################################################################
# Automatically find the ECG component using correlation with ECG signal.
@@ -75,39 +72,31 @@ ica.plot_sources_raw(raw, start=start_plot, stop=stop_plot)
# the default score_func.
from scipy.stats import pearsonr
-
corr = lambda x, y: np.array([pearsonr(a, y.ravel()) for a in x])[:, 0]
# As we don't have an ECG channel we use one that correlates a lot with heart
-# beats: 'MEG 1531'. We can directly pass the name to the find_sources method.
-# In our example, the find_sources method returns and array of correlation
+# beats: 'MEG 1531'. To improve detection, we filter the the channel and pass
+# it directly to find sources. The method then returns an array of correlation
# scores for each ICA source.
-ecg_scores = ica.find_sources_raw(raw, target='MEG 1531', score_func=corr)
-
-# get sources
-sources = ica.get_sources_raw(raw, start=start_plot, stop=stop_plot)
-
-# compute times
-times = np.linspace(start_plot, stop_plot, sources.shape[1])
+ecg_ch_name = 'MEG 1531'
+l_freq, h_freq = 8, 16
+ecg = raw[[raw.ch_names.index(ecg_ch_name)], :][0]
+ecg = band_pass_filter(ecg, raw.info['sfreq'], l_freq, h_freq)
+ecg_scores = ica.find_sources_raw(raw, target=ecg, score_func=corr)
# get maximum correlation index for ECG
ecg_source_idx = np.abs(ecg_scores).argmax()
-
-pl.figure()
-pl.plot(times, sources[ecg_source_idx], color='r')
-pl.title('ICA source matching ECG')
-pl.xlabel('Time (s)')
-pl.ylabel('AU')
-pl.show()
+title = 'ICA source matching ECG'
+ica.plot_sources_raw(raw, ecg_source_idx, title=title, stop=3.0)
# let us have a look which other components resemble the ECG.
# We can do this by reordering the plot by our scores using order
# and generating sort indices for the sources:
-ecg_order = np.abs(ecg_scores).argsort()[::-1] # ascending order
+ecg_order = np.abs(ecg_scores).argsort()[::-1][:30] # ascending order
-ica.plot_sources_raw(raw, order=ecg_order, start=start_plot, stop=stop_plot)
+ica.plot_sources_raw(raw, ecg_order, start=start_plot, stop=stop_plot)
# Let's make our ECG component selection more liberal and include sources
# for which the variance explanation in terms of \{r^2}\ exceeds 5 percent.
@@ -126,12 +115,14 @@ eog_scores = ica.find_sources_raw(raw, target='EOG 061', score_func=corr)
eog_source_idx = np.abs(eog_scores).argmax()
# plot the component that correlates most with the EOG
-pl.figure()
-pl.plot(times, sources[eog_source_idx], color='r')
-pl.title('ICA source matching EOG')
-pl.xlabel('Time (s)')
-pl.ylabel('AU')
-pl.show()
+title = 'ICA source matching EOG'
+ica.plot_sources_raw(raw, eog_source_idx, title=title, stop=3.0)
+
+# plot spatial sensitivities of EOG and ECG ICA components
+title = 'Spatial patterns of ICA components for ECG+EOG (Magnetometers)'
+source_idx = range(15)
+ica.plot_topomap([ecg_source_idx, eog_source_idx], ch_type='mag')
+plt.suptitle(title, fontsize=12)
###############################################################################
# Show MEG data before and after ICA cleaning.
@@ -147,45 +138,45 @@ start_compare, stop_compare = raw.time_as_index([100, 106])
data, times = raw[picks, start_compare:stop_compare]
data_clean, _ = raw_ica[picks, start_compare:stop_compare]
-pl.figure()
-pl.plot(times, data.T)
-pl.xlabel('time (s)')
-pl.xlim(100, 106)
-pl.ylabel('Raw MEG data (T)')
-y0, y1 = pl.ylim()
-
-pl.figure()
-pl.plot(times, data_clean.T)
-pl.xlabel('time (s)')
-pl.xlim(100, 106)
-pl.ylabel('Denoised MEG data (T)')
-pl.ylim(y0, y1)
-pl.show()
+plt.figure()
+plt.plot(times, data.T)
+plt.xlabel('time (s)')
+plt.xlim(100, 106)
+plt.ylabel('Raw MEG data (T)')
+y0, y1 = plt.ylim()
+
+plt.figure()
+plt.plot(times, data_clean.T)
+plt.xlabel('time (s)')
+plt.xlim(100, 106)
+plt.ylabel('Denoised MEG data (T)')
+plt.ylim(y0, y1)
+plt.show()
###############################################################################
# Compare the affected channel before and after ICA cleaning.
-affected_idx = raw.ch_names.index('MEG 1531')
+affected_idx = raw.ch_names.index(ecg_ch_name)
# plot the component that correlates most with the ECG
-pl.figure()
-pl.plot(times, data[affected_idx], color='k')
-pl.title('Affected channel MEG 1531 before cleaning.')
-y0, y1 = pl.ylim()
+plt.figure()
+plt.plot(times, data[affected_idx], color='k')
+plt.title('Affected channel MEG 1531 before cleaning.')
+y0, y1 = plt.ylim()
# plot the component that correlates most with the ECG
-pl.figure()
-pl.plot(times, data_clean[affected_idx], color='k')
-pl.title('Affected channel MEG 1531 after cleaning.')
-pl.ylim(y0, y1)
-pl.show()
+plt.figure()
+plt.plot(times, data_clean[affected_idx], color='k')
+plt.title('Affected channel MEG 1531 after cleaning.')
+plt.ylim(y0, y1)
+plt.show()
###############################################################################
# Export ICA as raw for subsequent processing steps in ICA space.
from mne.layouts import make_grid_layout
-ica_raw = ica.sources_as_raw(raw, start=start, stop=stop, picks=None)
+ica_raw = ica.sources_as_raw(raw, start=100., stop=160., picks=None)
print ica_raw.ch_names[:5] # just a few
diff --git a/examples/realtime/README.txt b/examples/realtime/README.txt
new file mode 100644
index 0000000..89785e9
--- /dev/null
+++ b/examples/realtime/README.txt
@@ -0,0 +1,5 @@
+Real-time M/EEG Acquisition
+---------------------------
+
+Receive data from an MNE Real-time server (mne_rt_server, part of MNE-CPP),
+compute real-time moving averages, etc.
diff --git a/examples/realtime/plot_compute_rt_average.py b/examples/realtime/plot_compute_rt_average.py
new file mode 100644
index 0000000..a9463c4
--- /dev/null
+++ b/examples/realtime/plot_compute_rt_average.py
@@ -0,0 +1,64 @@
+"""
+========================================================
+Compute real-time evoked responses using moving averages
+========================================================
+
+This example demonstrates how to connect to an MNE Real-time server
+using the RtClient and use it together with RtEpochs to compute
+evoked responses using moving averages.
+
+Note: The MNE Real-time server (mne_rt_server), which is part of mne-cpp,
+has to be running on the same computer.
+"""
+
+print __doc__
+
+# Authors: Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Mainak Jas <mainak at neuro.hut.fi>
+#
+# License: BSD (3-clause)
+
+import time
+
+import mne
+from mne.datasets import sample
+from mne.realtime import RtEpochs, MockRtClient
+
+# Fiff file to simulate the realtime client
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
+raw = mne.fiff.Raw(raw_fname, preload=True)
+
+# select gradiometers
+picks = mne.fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
+ stim=True, exclude=raw.info['bads'])
+
+# select the left-auditory condition
+event_id, tmin, tmax = 1, -0.2, 0.5
+
+# create the mock-client object
+rt_client = MockRtClient(raw)
+
+# create the real-time epochs object
+rt_epochs = RtEpochs(rt_client, event_id, tmin, tmax, picks=picks,
+ decim=1, reject=dict(grad=4000e-13, eog=150e-6))
+
+# start the acquisition
+rt_epochs.start()
+
+# send raw buffers
+rt_client.send_data(rt_epochs, picks, tmin=0, tmax=150, buffer_size=1000)
+
+evoked = None
+
+for ii, ev in enumerate(rt_epochs.iter_evoked()):
+
+ print "Just got epoch %d" % (ii + 1)
+
+ if evoked is None:
+ evoked = ev
+ else:
+ evoked += ev
+
+ evoked.plot()
+ time.sleep(0.1)
diff --git a/examples/realtime/plot_compute_rt_decoder.py b/examples/realtime/plot_compute_rt_decoder.py
new file mode 100644
index 0000000..9446b3b
--- /dev/null
+++ b/examples/realtime/plot_compute_rt_decoder.py
@@ -0,0 +1,111 @@
+"""
+=======================
+Decoding real-time data
+=======================
+
+Supervised machine learning applied to MEG data in sensor space.
+Here the classifier is updated every 5 trials and the decoding
+accuracy is plotted
+"""
+# Authors: Mainak Jas <mainak at neuro.hut.fi>
+#
+# License: BSD (3-clause)
+
+print __doc__
+
+import time
+
+import mne
+from mne.realtime import MockRtClient, RtEpochs
+from mne.datasets import sample
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+# Fiff file to simulate the realtime client
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
+raw = mne.fiff.Raw(raw_fname, preload=True)
+
+tmin, tmax = -0.2, 0.5
+event_id = dict(aud_l=1, vis_l=3)
+
+tr_percent = 60 # Training percentage
+min_trials = 10 # minimum trials after which decoding should start
+
+# select gradiometers
+picks = mne.fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
+ stim=True, exclude=raw.info['bads'])
+
+# create the mock-client object
+rt_client = MockRtClient(raw)
+
+# create the real-time epochs object
+rt_epochs = RtEpochs(rt_client, event_id, tmin, tmax, picks=picks, decim=1,
+ reject=dict(grad=4000e-13, eog=150e-6))
+
+# start the acquisition
+rt_epochs.start()
+
+# send raw buffers
+rt_client.send_data(rt_epochs, picks, tmin=0, tmax=90, buffer_size=1000)
+
+# Decoding in sensor space using a linear SVM
+n_times = len(rt_epochs.times)
+
+from sklearn import preprocessing
+from sklearn.svm import SVC
+from sklearn.pipeline import Pipeline
+from sklearn.cross_validation import cross_val_score, ShuffleSplit
+
+from mne.decoding import ConcatenateChannels, FilterEstimator
+
+scores_x, scores, std_scores = [], [], []
+
+filt = FilterEstimator(rt_epochs.info, 1, 40)
+scaler = preprocessing.StandardScaler()
+concatenator = ConcatenateChannels()
+clf = SVC(C=1, kernel='linear')
+
+concat_classifier = Pipeline([('filter', filt), ('concat', concatenator),
+ ('scaler', scaler), ('svm', clf)])
+
+for ev_num, ev in enumerate(rt_epochs.iter_evoked()):
+
+ print "Just got epoch %d" % (ev_num + 1)
+
+ if ev_num == 0:
+ X = ev.data[None, ...]
+ y = int(ev.comment)
+ else:
+ X = np.concatenate((X, ev.data[None, ...]), axis=0)
+ y = np.append(y, int(ev.comment))
+
+ if ev_num >= min_trials:
+
+ cv = ShuffleSplit(len(y), 5, test_size=0.2, random_state=42)
+ scores_t = cross_val_score(concat_classifier, X, y, cv=cv,
+ n_jobs=1) * 100
+
+ std_scores.append(scores_t.std())
+ scores.append(scores_t.mean())
+ scores_x.append(ev_num)
+
+ # Plot accuracy
+ plt.clf()
+
+ plt.plot(scores_x[-5:], scores[-5:], '+', label="Classif. score")
+ plt.hold(True)
+ plt.plot(scores_x[-5:], scores[-5:])
+ plt.axhline(50, color='k', linestyle='--', label="Chance level")
+ hyp_limits = (np.asarray(scores[-5:]) - np.asarray(std_scores[-5:]),
+ np.asarray(scores[-5:]) + np.asarray(std_scores[-5:]))
+ plt.fill_between(scores_x[-5:], hyp_limits[0], y2=hyp_limits[1],
+ color='b', alpha=0.5)
+ plt.xlabel('Trials')
+ plt.ylabel('Classification score (% correct)')
+ plt.ylim([30, 105])
+ plt.title('Real-time decoding')
+ plt.show()
+
+ time.sleep(0.1)
diff --git a/examples/realtime/rt_feedback_client.py b/examples/realtime/rt_feedback_client.py
new file mode 100644
index 0000000..192533d
--- /dev/null
+++ b/examples/realtime/rt_feedback_client.py
@@ -0,0 +1,116 @@
+"""
+==============================================
+Real-time feedback for decoding :: Client Side
+==============================================
+
+This example demonstrates how to setup a real-time feedback
+mechanism using StimServer and StimClient.
+
+The idea here is to display future stimuli for the class which
+is predicted less accurately. This allows on-demand adaptation
+of the stimuli depending on the needs of the classifier.
+
+To run this example, open ipython in two separate terminals.
+In the first, run rt_feedback_server.py and then wait for the
+message
+
+ RtServer: Start
+
+Once that appears, run rt_feedback_client.py in the other terminal
+and the feedback script should start.
+
+All brain responses are simulated from a fiff file to make it easy
+to test. However, it should be possible to adapt this script
+for a real experiment.
+
+"""
+
+print __doc__
+
+# Author: Mainak Jas <mainak at neuro.hut.fi>
+#
+# License: BSD (3-clause)
+
+from mne.realtime import StimClient
+from psychopy import visual, core
+
+# Instantiating stimulation client
+
+# Port number must match port number used to instantiate
+# StimServer. Any port number above 1000 should be fine
+# because they do not require root permission.
+stim_client = StimClient('localhost', port=4218)
+
+# create a window
+mywin = visual.Window([800, 600], monitor="testMonitor", units="deg")
+
+# create the stimuli
+
+# right checkerboard stimuli
+right_cb = visual.RadialStim(mywin, tex='sqrXsqr', color=1, size=5,
+ visibleWedge=[0, 180], radialCycles=4,
+ angularCycles=8, interpolate=False,
+ autoLog=False)
+
+# left checkerboard stimuli
+left_cb = visual.RadialStim(mywin, tex='sqrXsqr', color=1, size=5,
+ visibleWedge=[180, 360], radialCycles=4,
+ angularCycles=8, interpolate=False,
+ autoLog=False)
+
+# fixation dot
+fixation = visual.PatchStim(mywin, color=-1, colorSpace='rgb', tex=None,
+ mask='circle', size=0.2)
+
+# the most accurate method is using frame refresh periods
+# however, since the actual refresh rate is not known
+# we use the Clock
+timer1 = core.Clock()
+timer2 = core.Clock()
+
+ev_list = list() # list of events displayed
+
+# start with right checkerboard stimuli. This is required
+# because the ev_list.append(ev_list[-1]) will not work
+# if ev_list is empty.
+trig = 4
+
+# iterating over 50 epochs
+for ii in range(50):
+
+ if trig is not None:
+ ev_list.append(trig) # use the last trigger received
+ else:
+ ev_list.append(ev_list[-1]) # use the last stimuli
+
+ # draw left or right checkerboard according to ev_list
+ if ev_list[ii] == 3:
+ left_cb.draw()
+ else:
+ right_cb.draw()
+
+ fixation.draw() # draw fixation
+ mywin.flip() # show the stimuli
+
+ timer1.reset() # reset timer
+ timer1.add(0.75) # display stimuli for 0.75 sec
+
+ # return within 0.2 seconds (< 0.75 seconds) to ensure good timing
+ trig = stim_client.get_trigger(timeout=0.2)
+
+ # wait till 0.75 sec elapses
+ while timer1.getTime() < 0:
+ pass
+
+ fixation.draw() # draw fixation
+ mywin.flip() # show fixation dot
+
+ timer2.reset() # reset timer
+ timer2.add(0.25) # display stimuli for 0.25 sec
+
+ # display fixation cross for 0.25 seconds
+ while timer2.getTime() < 0:
+ pass
+
+mywin.close() # close the window
+core.quit()
diff --git a/examples/realtime/rt_feedback_server.py b/examples/realtime/rt_feedback_server.py
new file mode 100644
index 0000000..e103add
--- /dev/null
+++ b/examples/realtime/rt_feedback_server.py
@@ -0,0 +1,144 @@
+"""
+==============================================
+Real-time feedback for decoding :: Server Side
+==============================================
+
+This example demonstrates how to setup a real-time feedback
+mechanism using StimServer and StimClient.
+
+The idea here is to display future stimuli for the class which
+is predicted less accurately. This allows on-demand adaptation
+of the stimuli depending on the needs of the classifier.
+
+To run this example, open ipython in two separate terminals.
+In the first, run rt_feedback_server.py and then wait for the
+message
+
+ RtServer: Start
+
+Once that appears, run rt_feedback_client.py in the other terminal
+and the feedback script should start.
+
+All brain responses are simulated from a fiff file to make it easy
+to test. However, it should be possible to adapt this script
+for a real experiment.
+
+"""
+
+print __doc__
+
+# Author: Mainak Jas <mainak at neuro.hut.fi>
+#
+# License: BSD (3-clause)
+
+import time
+import mne
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+from mne.datasets import sample
+from mne.realtime import StimServer
+from mne.realtime import MockRtClient
+from mne.decoding import ConcatenateChannels, FilterEstimator
+
+from sklearn import preprocessing
+from sklearn.svm import SVC
+from sklearn.pipeline import Pipeline
+from sklearn.cross_validation import train_test_split
+from sklearn.metrics import confusion_matrix
+
+# Load fiff file to simulate data
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
+raw = mne.fiff.Raw(raw_fname, preload=True)
+
+# Instantiating stimulation server
+
+# The with statement is necessary to ensure a clean exit
+with StimServer('localhost', port=4218) as stim_server:
+
+ # The channels to be used while decoding
+ picks = mne.fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
+ stim=True, exclude=raw.info['bads'])
+
+ rt_client = MockRtClient(raw)
+
+ # Constructing the pipeline for classification
+ filt = FilterEstimator(raw.info, 1, 40)
+ scaler = preprocessing.StandardScaler()
+ concatenator = ConcatenateChannels()
+ clf = SVC(C=1, kernel='linear')
+
+ concat_classifier = Pipeline([('filter', filt), ('concat', concatenator),
+ ('scaler', scaler), ('svm', clf)])
+
+ stim_server.start(verbose=True)
+
+ # Just some initially decided events to be simulated
+ # Rest will decided on the fly
+ ev_list = [4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4]
+
+ score_c1, score_c2, score_x = [], [], []
+
+ for ii in range(50):
+
+ # Tell the stim_client about the next stimuli
+ stim_server.add_trigger(ev_list[ii])
+
+ # Collecting data
+ if ii == 0:
+ X = rt_client.get_event_data(event_id=ev_list[ii], tmin=-0.2,
+ tmax=0.5, picks=picks,
+ stim_channel='STI 014')[None, ...]
+ y = ev_list[ii]
+ else:
+ X_temp = rt_client.get_event_data(event_id=ev_list[ii], tmin=-0.2,
+ tmax=0.5, picks=picks,
+ stim_channel='STI 014')
+ X_temp = X_temp[np.newaxis, ...]
+
+ X = np.concatenate((X, X_temp), axis=0)
+
+ time.sleep(1) # simulating the isi
+ y = np.append(y, ev_list[ii])
+
+ # Start decoding after collecting sufficient data
+ if ii >= 10:
+ # Now start doing rtfeedback
+ X_train, X_test, y_train, y_test = train_test_split(X, y,
+ test_size=0.2,
+ random_state=7)
+
+ y_pred = concat_classifier.fit(X_train, y_train).predict(X_test)
+
+ cm = confusion_matrix(y_test, y_pred)
+
+ score_c1.append(float(cm[0, 0]) / sum(cm, 1)[0] * 100)
+ score_c2.append(float(cm[1, 1]) / sum(cm, 1)[1] * 100)
+
+ # do something if one class is decoded better than the other
+ if score_c1[-1] < score_c2[-1]:
+ print "We decoded class RV better than class LV"
+ ev_list.append(3) # adding more LV to future simulated data
+ else:
+ print "We decoded class LV better than class RV"
+ ev_list.append(4) # adding more RV to future simulated data
+
+ # Clear the figure
+ plt.clf()
+
+ # The x-axis for the plot
+ score_x.append(ii)
+
+ # Now plot the accuracy
+ plt.plot(score_x[-5:], score_c1[-5:])
+ plt.hold(True)
+ plt.plot(score_x[-5:], score_c2[-5:])
+ plt.xlabel('Trials')
+ plt.ylabel('Classification score (% correct)')
+ plt.title('Real-time feedback')
+ plt.ylim([0, 100])
+ plt.xticks(score_x[-5:])
+ plt.legend(('LV', 'RV'), loc='upper left')
+ plt.show()
diff --git a/examples/stats/plot_cluster_1samp_test_time_frequency.py b/examples/stats/plot_cluster_1samp_test_time_frequency.py
index 2a1e46b..f4e01fa 100644
--- a/examples/stats/plot_cluster_1samp_test_time_frequency.py
+++ b/examples/stats/plot_cluster_1samp_test_time_frequency.py
@@ -47,7 +47,7 @@ raw.info['bads'] += ['MEG 2443', 'EEG 053'] # bads + 2 more
# picks MEG gradiometers
picks = fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
- stim=False, include=include, exclude='bads')
+ stim=False, include=include, exclude='bads')
# Load condition 1
event_id = 1
@@ -103,18 +103,18 @@ T_obs, clusters, cluster_p_values, H0 = \
###############################################################################
# View time-frequency plots
-import pylab as pl
-pl.clf()
-pl.subplots_adjust(0.12, 0.08, 0.96, 0.94, 0.2, 0.43)
-pl.subplot(2, 1, 1)
-pl.plot(times, evoked_data.T)
-pl.title('Evoked response (%s)' % ch_name)
-pl.xlabel('time (ms)')
-pl.ylabel('Magnetic Field (fT/cm)')
-pl.xlim(times[0], times[-1])
-pl.ylim(-100, 250)
-
-pl.subplot(2, 1, 2)
+import matplotlib.pyplot as plt
+plt.clf()
+plt.subplots_adjust(0.12, 0.08, 0.96, 0.94, 0.2, 0.43)
+plt.subplot(2, 1, 1)
+plt.plot(times, evoked_data.T)
+plt.title('Evoked response (%s)' % ch_name)
+plt.xlabel('time (ms)')
+plt.ylabel('Magnetic Field (fT/cm)')
+plt.xlim(times[0], times[-1])
+plt.ylim(-100, 250)
+
+plt.subplot(2, 1, 2)
# Create new stats image with only significant clusters
T_obs_plot = np.nan * np.ones_like(T_obs)
@@ -124,16 +124,14 @@ for c, p_val in zip(clusters, cluster_p_values):
vmax = np.max(np.abs(T_obs))
vmin = -vmax
-pl.imshow(T_obs, cmap=pl.cm.gray, extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]],
- aspect='auto', origin='lower',
- vmin=vmin, vmax=vmax)
-pl.imshow(T_obs_plot, cmap=pl.cm.jet, extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]],
- aspect='auto', origin='lower',
- vmin=vmin, vmax=vmax)
-pl.colorbar()
-pl.xlabel('time (ms)')
-pl.ylabel('Frequency (Hz)')
-pl.title('Induced power (%s)' % ch_name)
-pl.show()
+plt.imshow(T_obs, cmap=plt.cm.gray,
+ extent=[times[0], times[-1], frequencies[0], frequencies[-1]],
+ aspect='auto', origin='lower', vmin=vmin, vmax=vmax)
+plt.imshow(T_obs_plot, cmap=plt.cm.jet,
+ extent=[times[0], times[-1], frequencies[0], frequencies[-1]],
+ aspect='auto', origin='lower', vmin=vmin, vmax=vmax)
+plt.colorbar()
+plt.xlabel('time (ms)')
+plt.ylabel('Frequency (Hz)')
+plt.title('Induced power (%s)' % ch_name)
+plt.show()
diff --git a/examples/stats/plot_cluster_methods_tutorial.py b/examples/stats/plot_cluster_methods_tutorial.py
index f4c0af4..308ea00 100644
--- a/examples/stats/plot_cluster_methods_tutorial.py
+++ b/examples/stats/plot_cluster_methods_tutorial.py
@@ -56,8 +56,8 @@ import numpy as np
from scipy import stats
from functools import partial
-from mne.stats import spatio_temporal_cluster_1samp_test, \
- bonferroni_correction, ttest_1samp_no_p
+from mne.stats import (spatio_temporal_cluster_1samp_test,
+ bonferroni_correction, ttest_1samp_no_p)
try:
from sklearn.feature_extraction.image import grid_to_graph
@@ -158,10 +158,10 @@ ps_tfce_hat = -np.log10(p_values.reshape((width, width)))
###############################################################################
# Visualize results
-import pylab as pl
+import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # this changes hidden matplotlib vars
-pl.ion()
-fig = pl.figure(facecolor='w')
+plt.ion()
+fig = plt.figure(facecolor='w')
x, y = np.mgrid[0:width, 0:width]
kwargs = dict(rstride=1, cstride=1, linewidth=0, cmap='Greens')
@@ -182,16 +182,16 @@ titles = ['Standard clustering', 'Clust. w/"hat"',
axs = []
for ii, (p, title) in enumerate(zip(pvals, titles)):
ax = fig.add_subplot(2, 4, 5 + ii)
- pl.imshow(p, cmap='Purples', vmin=p_lims[0], vmax=p_lims[1])
+ plt.imshow(p, cmap='Purples', vmin=p_lims[0], vmax=p_lims[1])
ax.set_xticks([])
ax.set_yticks([])
ax.set_title(title)
axs.append(ax)
-pl.tight_layout()
+plt.tight_layout()
for ax in axs:
- cbar = pl.colorbar(ax=ax, shrink=0.75, orientation='horizontal',
- fraction=0.1, pad=0.025)
+ cbar = plt.colorbar(ax=ax, shrink=0.75, orientation='horizontal',
+ fraction=0.1, pad=0.025)
cbar.set_label('-log10(p)')
cbar.set_ticks(p_lims)
cbar.set_ticklabels(['%0.1f' % p for p in p_lims])
diff --git a/examples/stats/plot_cluster_stats_evoked.py b/examples/stats/plot_cluster_stats_evoked.py
index 3644408..649ffd8 100644
--- a/examples/stats/plot_cluster_stats_evoked.py
+++ b/examples/stats/plot_cluster_stats_evoked.py
@@ -65,24 +65,25 @@ T_obs, clusters, cluster_p_values, H0 = \
###############################################################################
# Plot
times = epochs1.times
-import pylab as pl
-pl.close('all')
-pl.subplot(211)
-pl.title('Channel : ' + channel)
-pl.plot(times, condition1.mean(axis=0) - condition2.mean(axis=0),
- label="ERF Contrast (Event 1 - Event 2)")
-pl.ylabel("MEG (T / m)")
-pl.legend()
-pl.subplot(212)
+import matplotlib.pyplot as plt
+plt.close('all')
+plt.subplot(211)
+plt.title('Channel : ' + channel)
+plt.plot(times, condition1.mean(axis=0) - condition2.mean(axis=0),
+ label="ERF Contrast (Event 1 - Event 2)")
+plt.ylabel("MEG (T / m)")
+plt.legend()
+plt.subplot(212)
for i_c, c in enumerate(clusters):
c = c[0]
if cluster_p_values[i_c] <= 0.05:
- h = pl.axvspan(times[c.start], times[c.stop - 1], color='r', alpha=0.3)
+ h = plt.axvspan(times[c.start], times[c.stop - 1],
+ color='r', alpha=0.3)
else:
- pl.axvspan(times[c.start], times[c.stop - 1], color=(0.3, 0.3, 0.3),
- alpha=0.3)
-hf = pl.plot(times, T_obs, 'g')
-pl.legend((h, ), ('cluster p-value < 0.05', ))
-pl.xlabel("time (ms)")
-pl.ylabel("f-values")
-pl.show()
+ plt.axvspan(times[c.start], times[c.stop - 1], color=(0.3, 0.3, 0.3),
+ alpha=0.3)
+hf = plt.plot(times, T_obs, 'g')
+plt.legend((h, ), ('cluster p-value < 0.05', ))
+plt.xlabel("time (ms)")
+plt.ylabel("f-values")
+plt.show()
diff --git a/examples/stats/plot_cluster_stats_spatio_temporal.py b/examples/stats/plot_cluster_stats_spatio_temporal.py
index 6a79b95..bbad9f9 100644
--- a/examples/stats/plot_cluster_stats_spatio_temporal.py
+++ b/examples/stats/plot_cluster_stats_spatio_temporal.py
@@ -22,11 +22,11 @@ from numpy.random import randn
from scipy import stats as stats
import mne
-from mne import fiff, spatial_tris_connectivity, compute_morph_matrix,\
- grade_to_tris
+from mne import (fiff, spatial_tris_connectivity, compute_morph_matrix,
+ grade_to_tris)
from mne.epochs import equalize_epoch_counts
-from mne.stats import spatio_temporal_cluster_1samp_test,\
- summarize_clusters_stc
+from mne.stats import (spatio_temporal_cluster_1samp_test,
+ summarize_clusters_stc)
from mne.minimum_norm import apply_inverse, read_inverse_operator
from mne.datasets import sample
from mne.viz import mne_analyze_colormap
@@ -161,19 +161,19 @@ print 'Visualizing clusters.'
# Now let's build a convenient representation of each cluster, where each
# cluster becomes a "time point" in the SourceEstimate
stc_all_cluster_vis = summarize_clusters_stc(clu, tstep=tstep,
- vertno=fsave_vertices, subject='fsaverage')
+ vertno=fsave_vertices,
+ subject='fsaverage')
# Let's actually plot the first "time point" in the SourceEstimate, which
# shows all the clusters, weighted by duration
colormap = mne_analyze_colormap(limits=[0, 10, 50])
subjects_dir = op.join(data_path, 'subjects')
# blue blobs are for condition A < condition B, red for A > B
-brains = stc_all_cluster_vis.plot('fsaverage', 'inflated', 'both', colormap,
- subjects_dir=subjects_dir,
- time_label='Duration significant (ms)')
-for idx, brain in enumerate(brains):
- brain.set_data_time_index(0)
- # The colormap requires brain data to be scaled -fmax -> fmax
- brain.scale_data_colormap(fmin=-50, fmid=0, fmax=50, transparent=False)
- brain.show_view('lateral')
- brain.save_image('clusters-%s.png' % ('lh' if idx == 0 else 'rh'))
+brain = stc_all_cluster_vis.plot('fsaverage', 'inflated', 'both', colormap,
+ subjects_dir=subjects_dir,
+ time_label='Duration significant (ms)')
+brain.set_data_time_index(0)
+# The colormap requires brain data to be scaled -fmax -> fmax
+brain.scale_data_colormap(fmin=-50, fmid=0, fmax=50, transparent=False)
+brain.show_view('lateral')
+brain.save_image('clusters.png')
diff --git a/examples/stats/plot_cluster_stats_spatio_temporal_2samp.py b/examples/stats/plot_cluster_stats_spatio_temporal_2samp.py
index a891817..e7ac096 100644
--- a/examples/stats/plot_cluster_stats_spatio_temporal_2samp.py
+++ b/examples/stats/plot_cluster_stats_spatio_temporal_2samp.py
@@ -90,18 +90,18 @@ print 'Visualizing clusters.'
# cluster becomes a "time point" in the SourceEstimate
fsave_vertices = [np.arange(10242), np.arange(10242)]
stc_all_cluster_vis = summarize_clusters_stc(clu, tstep=tstep,
- vertno=fsave_vertices, subject='fsaverage')
+ vertno=fsave_vertices,
+ subject='fsaverage')
# Let's actually plot the first "time point" in the SourceEstimate, which
# shows all the clusters, weighted by duration
subjects_dir = op.join(data_path, 'subjects')
# blue blobs are for condition A != condition B
-brains = stc_all_cluster_vis.plot('fsaverage', 'inflated', 'both',
- subjects_dir=subjects_dir,
- time_label='Duration significant (ms)',
- fmin=0, fmid=25, fmax=50)
-for idx, brain in enumerate(brains):
- brain.set_data_time_index(0)
- brain.scale_data_colormap(fmin=0, fmid=25, fmax=50, transparent=True)
- brain.show_view('lateral')
- brain.save_image('clusters-%s.png' % ('lh' if idx == 0 else 'rh'))
+brain = stc_all_cluster_vis.plot('fsaverage', 'inflated', 'both',
+ subjects_dir=subjects_dir,
+ time_label='Duration significant (ms)',
+ fmin=0, fmid=25, fmax=50)
+brain.set_data_time_index(0)
+brain.scale_data_colormap(fmin=0, fmid=25, fmax=50, transparent=True)
+brain.show_view('lateral')
+brain.save_image('clusters.png')
diff --git a/examples/stats/plot_cluster_stats_spatio_temporal_repeated_measures_anova.py b/examples/stats/plot_cluster_stats_spatio_temporal_repeated_measures_anova.py
index d57915a..94fb0b3 100644
--- a/examples/stats/plot_cluster_stats_spatio_temporal_repeated_measures_anova.py
+++ b/examples/stats/plot_cluster_stats_spatio_temporal_repeated_measures_anova.py
@@ -27,10 +27,10 @@ import numpy as np
from numpy.random import randn
import mne
-from mne import fiff, spatial_tris_connectivity, compute_morph_matrix,\
- grade_to_tris
-from mne.stats import spatio_temporal_cluster_test, f_threshold_twoway_rm, \
- f_twoway_rm, summarize_clusters_stc
+from mne import (fiff, spatial_tris_connectivity, compute_morph_matrix,
+ grade_to_tris)
+from mne.stats import (spatio_temporal_cluster_test, f_threshold_twoway_rm,
+ f_twoway_rm, summarize_clusters_stc)
from mne.minimum_norm import apply_inverse, read_inverse_operator
from mne.datasets import sample
@@ -58,7 +58,7 @@ picks = fiff.pick_types(raw.info, meg=True, eog=True, exclude='bads')
event_id = dict(l_aud=1, r_aud=2, l_vis=3, r_vis=4)
reject = dict(grad=1000e-13, mag=4000e-15, eog=150e-6)
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks,
- baseline=(None, 0), reject=reject, preload=True)
+ baseline=(None, 0), reject=reject, preload=True)
# Equalize trial counts to eliminate bias (which would otherwise be
# introduced by the abs() performed below)
@@ -169,10 +169,12 @@ def stat_fun(*args):
# The following expression catches the list input, swaps the first and the
# second dimension and puts the remaining observations in the third
# dimension.
- data = np.swapaxes(np.asarray(args), 1, 0).reshape(n_subjects, \
- n_conditions, n_times * n_vertices_fsave)
+ data = np.swapaxes(np.asarray(args), 1, 0).reshape(n_subjects,
+ n_conditions, n_times *
+ n_vertices_fsave)
return f_twoway_rm(data, factor_levels=factor_levels, effects=effects,
- return_pvals=return_pvals)[0] # drop p-values (empty array).
+ return_pvals=return_pvals)[0]
+ # drop p-values (empty array).
# Note. for further details on this ANOVA function consider the
# corresponding time frequency example.
@@ -199,7 +201,8 @@ print 'Clustering.'
T_obs, clusters, cluster_p_values, H0 = clu = \
spatio_temporal_cluster_test(X, connectivity=connectivity, n_jobs=1,
threshold=f_thresh, stat_fun=stat_fun,
- n_permutations=n_permutations)
+ n_permutations=n_permutations,
+ buffer_size=None)
# Now select the clusters that are sig. at p < 0.05 (note that this value
# is multiple-comparisons corrected).
good_cluster_inds = np.where(cluster_p_values < 0.05)[0]
@@ -212,7 +215,8 @@ print 'Visualizing clusters.'
# Now let's build a convenient representation of each cluster, where each
# cluster becomes a "time point" in the SourceEstimate
stc_all_cluster_vis = summarize_clusters_stc(clu, tstep=tstep,
- vertno=fsave_vertices, subject='fsaverage')
+ vertno=fsave_vertices,
+ subject='fsaverage')
# Let's actually plot the first "time point" in the SourceEstimate, which
# shows all the clusters, weighted by duration
@@ -222,8 +226,8 @@ subjects_dir = op.join(data_path, 'subjects')
# stimulus modality and stimulus location
brain = stc_all_cluster_vis.plot('fsaverage', 'inflated', 'lh',
- subjects_dir=subjects_dir,
- time_label='Duration significant (ms)')
+ subjects_dir=subjects_dir,
+ time_label='Duration significant (ms)')
brain.set_data_time_index(0)
brain.scale_data_colormap(fmin=5, fmid=10, fmax=30, transparent=True)
@@ -235,16 +239,17 @@ brain.show_view('medial')
# Finally, let's investigate interaction effect by reconstructing the time
# courses
-import pylab as pl
+import matplotlib.pyplot as plt
inds_t, inds_v = [(clusters[cluster_ind]) for ii, cluster_ind in
- enumerate(good_cluster_inds)][0] # first cluster
+ enumerate(good_cluster_inds)][0] # first cluster
times = np.arange(X[0].shape[1]) * tstep * 1e3
-pl.clf()
+plt.clf()
colors = ['y', 'b', 'g', 'purple']
-for ii, (condition, color, eve_id) in enumerate(
- zip(X, colors, ['l_aud', 'r_aud', 'l_vis', 'r_vis'])):
+event_ids = ['l_aud', 'r_aud', 'l_vis', 'r_vis']
+
+for ii, (condition, color, eve_id) in enumerate(zip(X, colors, event_ids)):
# extract time course at cluster vertices
condition = condition[:, :, inds_v]
# normally we would normalize values across subjects but
@@ -252,15 +257,15 @@ for ii, (condition, color, eve_id) in enumerate(
# create average time series across subjects and vertices.
mean_tc = condition.mean(axis=2).mean(axis=0)
std_tc = condition.std(axis=2).std(axis=0)
- pl.plot(times, mean_tc.T, color=color, label=eve_id)
- pl.fill_between(times, mean_tc + std_tc, mean_tc - std_tc, color='gray',
- alpha=0.5, label='')
-
-pl.xlabel('Time (ms)')
-pl.ylabel('Activation (F-values)')
-pl.xlim(times[[0, -1]])
-pl.fill_betweenx(np.arange(*pl.ylim()), times[inds_t[0]],
- times[inds_t[-1]], color='orange', alpha=0.3)
-pl.legend()
-pl.title('Interaction between stimulus-modality and location.')
-pl.show()
+ plt.plot(times, mean_tc.T, color=color, label=eve_id)
+ plt.fill_between(times, mean_tc + std_tc, mean_tc - std_tc, color='gray',
+ alpha=0.5, label='')
+
+plt.xlabel('Time (ms)')
+plt.ylabel('Activation (F-values)')
+plt.xlim(times[[0, -1]])
+plt.fill_betweenx(np.arange(*plt.ylim()), times[inds_t[0]],
+ times[inds_t[-1]], color='orange', alpha=0.3)
+plt.legend()
+plt.title('Interaction between stimulus-modality and location.')
+plt.show()
diff --git a/examples/stats/plot_cluster_stats_time_frequency.py b/examples/stats/plot_cluster_stats_time_frequency.py
index a331e9b..812cbde 100644
--- a/examples/stats/plot_cluster_stats_time_frequency.py
+++ b/examples/stats/plot_cluster_stats_time_frequency.py
@@ -116,19 +116,19 @@ T_obs, clusters, cluster_p_values, H0 = \
###############################################################################
# View time-frequency plots
-import pylab as pl
-pl.clf()
-pl.subplots_adjust(0.12, 0.08, 0.96, 0.94, 0.2, 0.43)
-pl.subplot(2, 1, 1)
+import matplotlib.pyplot as plt
+plt.clf()
+plt.subplots_adjust(0.12, 0.08, 0.96, 0.94, 0.2, 0.43)
+plt.subplot(2, 1, 1)
evoked_contrast = np.mean(data_condition_1, 0) - np.mean(data_condition_2, 0)
-pl.plot(times, evoked_contrast.T)
-pl.title('Contrast of evoked response (%s)' % ch_name)
-pl.xlabel('time (ms)')
-pl.ylabel('Magnetic Field (fT/cm)')
-pl.xlim(times[0], times[-1])
-pl.ylim(-100, 200)
+plt.plot(times, evoked_contrast.T)
+plt.title('Contrast of evoked response (%s)' % ch_name)
+plt.xlabel('time (ms)')
+plt.ylabel('Magnetic Field (fT/cm)')
+plt.xlim(times[0], times[-1])
+plt.ylim(-100, 200)
-pl.subplot(2, 1, 2)
+plt.subplot(2, 1, 2)
# Create new stats image with only significant clusters
T_obs_plot = np.nan * np.ones_like(T_obs)
@@ -136,14 +136,14 @@ for c, p_val in zip(clusters, cluster_p_values):
if p_val <= 0.05:
T_obs_plot[c] = T_obs[c]
-pl.imshow(T_obs, cmap=pl.cm.gray, extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]],
- aspect='auto', origin='lower')
-pl.imshow(T_obs_plot, cmap=pl.cm.jet, extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]],
- aspect='auto', origin='lower')
-
-pl.xlabel('time (ms)')
-pl.ylabel('Frequency (Hz)')
-pl.title('Induced power (%s)' % ch_name)
-pl.show()
+plt.imshow(T_obs, cmap=plt.cm.gray,
+ extent=[times[0], times[-1], frequencies[0], frequencies[-1]],
+ aspect='auto', origin='lower')
+plt.imshow(T_obs_plot, cmap=plt.cm.jet,
+ extent=[times[0], times[-1], frequencies[0], frequencies[-1]],
+ aspect='auto', origin='lower')
+
+plt.xlabel('time (ms)')
+plt.ylabel('Frequency (Hz)')
+plt.title('Induced power (%s)' % ch_name)
+plt.show()
diff --git a/examples/stats/plot_cluster_stats_time_frequency_repeated_measures_anova.py b/examples/stats/plot_cluster_stats_time_frequency_repeated_measures_anova.py
index 480d704..2a48d71 100644
--- a/examples/stats/plot_cluster_stats_time_frequency_repeated_measures_anova.py
+++ b/examples/stats/plot_cluster_stats_time_frequency_repeated_measures_anova.py
@@ -60,8 +60,8 @@ ch_name = raw.info['ch_names'][picks[0]]
reject = dict(grad=4000e-13, eog=150e-6)
event_id = dict(aud_l=1, aud_r=2, vis_l=3, vis_r=4)
epochs = mne.Epochs(raw, events, event_id, tmin, tmax,
- picks=picks, baseline=(None, 0),
- reject=reject)
+ picks=picks, baseline=(None, 0),
+ reject=reject)
# make sure all conditions have the same counts, as the ANOVA expects a
# fully balanced data matrix and does not forgive imbalances that generously
@@ -82,7 +82,8 @@ baseline_mask = times[::decim] < 0
epochs_power = []
for condition in [epochs[k].get_data()[:, 97:98, :] for k in event_id]:
this_power = single_trial_power(condition, Fs=Fs, frequencies=frequencies,
- n_cycles=n_cycles, use_fft=False, decim=decim)
+ n_cycles=n_cycles, use_fft=False,
+ decim=decim)
this_power = this_power[:, 0, :, :] # we only have one channel.
# Compute ratio with baseline power (be sure to correct time vector with
# decimation factor)
@@ -129,25 +130,25 @@ print data.shape
fvals, pvals = f_twoway_rm(data, factor_levels, effects=effects)
effect_labels = ['modality', 'location', 'modality by location']
-import pylab as pl
+import matplotlib.pyplot as plt
# let's visualize our effects by computing f-images
for effect, sig, effect_label in zip(fvals, pvals, effect_labels):
- pl.figure()
+ plt.figure()
# show naive F-values in gray
- pl.imshow(effect.reshape(8, 211), cmap=pl.cm.gray, extent=[times[0],
- times[-1], frequencies[0], frequencies[-1]], aspect='auto',
- origin='lower')
+ plt.imshow(effect.reshape(8, 211), cmap=plt.cm.gray, extent=[times[0],
+ times[-1], frequencies[0], frequencies[-1]], aspect='auto',
+ origin='lower')
# create mask for significant Time-frequency locations
effect = np.ma.masked_array(effect, [sig > .05])
- pl.imshow(effect.reshape(8, 211), cmap=pl.cm.jet, extent=[times[0],
- times[-1], frequencies[0], frequencies[-1]], aspect='auto',
- origin='lower')
- pl.colorbar()
- pl.xlabel('time (ms)')
- pl.ylabel('Frequency (Hz)')
- pl.title(r"Time-locked response for '%s' (%s)" % (effect_label, ch_name))
- pl.show()
+ plt.imshow(effect.reshape(8, 211), cmap=plt.cm.jet, extent=[times[0],
+ times[-1], frequencies[0], frequencies[-1]], aspect='auto',
+ origin='lower')
+ plt.colorbar()
+ plt.xlabel('time (ms)')
+ plt.ylabel('Frequency (Hz)')
+ plt.title(r"Time-locked response for '%s' (%s)" % (effect_label, ch_name))
+ plt.show()
# Note. As we treat trials as subjects, the test only accounts for
# time locked responses despite the 'induced' approach.
@@ -173,10 +174,11 @@ def stat_fun(*args):
# The following expression catches the list input, swaps the first and the
# second dimension and puts the remaining observations in the third
# dimension.
- data = np.swapaxes(np.asarray(args), 1, 0).reshape(n_replications, \
- n_conditions, n_times * n_frequencies)
- return f_twoway_rm(data, factor_levels=factor_levels, effects=effects,
- return_pvals=False)[0]
+ data = np.swapaxes(np.asarray(args), 1, 0).reshape(n_replications,
+ n_conditions,
+ n_times * n_frequencies)
+ return f_twoway_rm(data, factor_levels=factor_levels,
+ effects=effects, return_pvals=False)[0]
# The ANOVA returns a tuple f-values and p-values, we will pick the former.
@@ -187,38 +189,38 @@ tail = 1 # f-test, so tail > 0
n_permutations = 256 # Save some time (the test won't be too sensitive ...)
T_obs, clusters, cluster_p_values, h0 = mne.stats.permutation_cluster_test(
epochs_power, stat_fun=stat_fun, threshold=f_thresh, tail=tail, n_jobs=1,
- n_permutations=n_permutations)
+ n_permutations=n_permutations, buffer_size=None)
# Create new stats image with only significant clusters
good_clusers = np.where(cluster_p_values < .05)[0]
T_obs_plot = np.ma.masked_array(T_obs, np.invert(clusters[good_clusers]))
-pl.figure()
-for f_image, cmap in zip([T_obs, T_obs_plot], [pl.cm.gray, pl.cm.jet]):
- pl.imshow(f_image, cmap=cmap, extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]], aspect='auto',
- origin='lower')
-pl.xlabel('time (ms)')
-pl.ylabel('Frequency (Hz)')
-pl.title('Time-locked response for \'modality by location\' (%s)\n'
+plt.figure()
+for f_image, cmap in zip([T_obs, T_obs_plot], [plt.cm.gray, plt.cm.jet]):
+ plt.imshow(f_image, cmap=cmap, extent=[times[0], times[-1],
+ frequencies[0], frequencies[-1]], aspect='auto',
+ origin='lower')
+plt.xlabel('time (ms)')
+plt.ylabel('Frequency (Hz)')
+plt.title('Time-locked response for \'modality by location\' (%s)\n'
' cluster-level corrected (p <= 0.05)' % ch_name)
-pl.show()
+plt.show()
# now using FDR
mask, _ = fdr_correction(pvals[2])
T_obs_plot2 = np.ma.masked_array(T_obs, np.invert(mask))
-pl.figure()
-for f_image, cmap in zip([T_obs, T_obs_plot2], [pl.cm.gray, pl.cm.jet]):
- pl.imshow(f_image, cmap=cmap, extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]], aspect='auto',
- origin='lower')
+plt.figure()
+for f_image, cmap in zip([T_obs, T_obs_plot2], [plt.cm.gray, plt.cm.jet]):
+ plt.imshow(f_image, cmap=cmap, extent=[times[0], times[-1],
+ frequencies[0], frequencies[-1]], aspect='auto',
+ origin='lower')
-pl.xlabel('time (ms)')
-pl.ylabel('Frequency (Hz)')
-pl.title('Time-locked response for \'modality by location\' (%s)\n'
+plt.xlabel('time (ms)')
+plt.ylabel('Frequency (Hz)')
+plt.title('Time-locked response for \'modality by location\' (%s)\n'
' FDR corrected (p <= 0.05)' % ch_name)
-pl.show()
+plt.show()
# Both, cluster level and FDR correction help getting rid of
# putatively spots we saw in the naive f-images.
diff --git a/examples/stats/plot_fdr_stats_evoked.py b/examples/stats/plot_fdr_stats_evoked.py
index 897c236..5484f64 100644
--- a/examples/stats/plot_fdr_stats_evoked.py
+++ b/examples/stats/plot_fdr_stats_evoked.py
@@ -65,17 +65,17 @@ threshold_fdr = np.min(np.abs(T)[reject_fdr])
# Plot
times = 1e3 * epochs.times
-import pylab as pl
-pl.close('all')
-pl.plot(times, T, 'k', label='T-stat')
-xmin, xmax = pl.xlim()
-pl.hlines(threshold_uncorrected, xmin, xmax, linestyle='--', colors='k',
- label='p=0.05 (uncorrected)', linewidth=2)
-pl.hlines(threshold_bonferroni, xmin, xmax, linestyle='--', colors='r',
- label='p=0.05 (Bonferroni)', linewidth=2)
-pl.hlines(threshold_fdr, xmin, xmax, linestyle='--', colors='b',
- label='p=0.05 (FDR)', linewidth=2)
-pl.legend()
-pl.xlabel("Time (ms)")
-pl.ylabel("T-stat")
-pl.show()
+import matplotlib.pyplot as plt
+plt.close('all')
+plt.plot(times, T, 'k', label='T-stat')
+xmin, xmax = plt.xlim()
+plt.hlines(threshold_uncorrected, xmin, xmax, linestyle='--', colors='k',
+ label='p=0.05 (uncorrected)', linewidth=2)
+plt.hlines(threshold_bonferroni, xmin, xmax, linestyle='--', colors='r',
+ label='p=0.05 (Bonferroni)', linewidth=2)
+plt.hlines(threshold_fdr, xmin, xmax, linestyle='--', colors='b',
+ label='p=0.05 (FDR)', linewidth=2)
+plt.legend()
+plt.xlabel("Time (ms)")
+plt.ylabel("T-stat")
+plt.show()
diff --git a/examples/stats/plot_sensor_permutation_test.py b/examples/stats/plot_sensor_permutation_test.py
index d244049..1586820 100644
--- a/examples/stats/plot_sensor_permutation_test.py
+++ b/examples/stats/plot_sensor_permutation_test.py
@@ -62,7 +62,7 @@ print "Sensors names : %s" % significant_sensors_names
###############################################################################
# View location of significantly active sensors
-import pylab as pl
+import matplotlib.pyplot as plt
# load sensor layout
from mne.layouts import read_layout
@@ -77,14 +77,12 @@ mask_significant_sensors[idx_of_sensors] = True
mask_non_significant_sensors = mask_significant_sensors == False
# plot it
-pl.figure(facecolor='k')
-pl.axis('off')
-pl.axis('tight')
-pl.scatter(layout.pos[mask_significant_sensors, 0],
- layout.pos[mask_significant_sensors, 1], s=50, c='r')
-pl.scatter(layout.pos[mask_non_significant_sensors, 0],
- layout.pos[mask_non_significant_sensors, 1], c='w')
-title = 'MNE sample data (Left auditory between 40 and 60 ms)'
-pl.figtext(0.03, 0.93, title, color='w', fontsize=18)
-pl.show()
-pl.show()
+plt.figure(figsize=(5, 3.5), facecolor='k')
+plt.axis('off')
+plt.scatter(layout.pos[mask_significant_sensors, 0],
+ layout.pos[mask_significant_sensors, 1], s=50, c='r')
+plt.scatter(layout.pos[mask_non_significant_sensors, 0],
+ layout.pos[mask_non_significant_sensors, 1], c='w')
+title = 'Left auditory between 40 and 60 ms'
+plt.figtext(0.03, 0.93, title, color='w', fontsize=18)
+plt.show()
diff --git a/examples/time_frequency/plot_compute_raw_data_spectrum.py b/examples/time_frequency/plot_compute_raw_data_spectrum.py
index 798074a..5b1fc85 100644
--- a/examples/time_frequency/plot_compute_raw_data_spectrum.py
+++ b/examples/time_frequency/plot_compute_raw_data_spectrum.py
@@ -9,14 +9,15 @@ to the data to reduce ECG and EOG artifacts.
"""
# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Eric Larson <larson.eric.d at gmail.com>
# License: BSD (3-clause)
print __doc__
import numpy as np
+import matplotlib.pyplot as plt
from mne import fiff, read_proj, read_selection
-from mne.time_frequency import compute_raw_psd
from mne.datasets import sample
###############################################################################
@@ -33,6 +34,17 @@ raw.info['bads'] += ['MEG 2443', 'EEG 053'] # bads + 2 more
projs = read_proj(proj_fname)
raw.add_proj(projs, remove_existing=True)
+
+tmin, tmax = 0, 60 # use the first 60s of data
+fmin, fmax = 2, 300 # look at frequencies between 2 and 300Hz
+n_fft = 2048 # the FFT size (NFFT). Ideally a power of 2
+
+plt.ion()
+
+# Let's first check out all channel types
+raw.plot_psds(area_mode='range', tmax=10.0)
+
+# Now let's focus on a smaller subset:
# Pick MEG magnetometers in the Left-temporal region
selection = read_selection('Left-temporal')
picks = fiff.pick_types(raw.info, meg='mag', eeg=False, eog=False,
@@ -41,46 +53,19 @@ picks = fiff.pick_types(raw.info, meg='mag', eeg=False, eog=False,
# Let's just look at the first few channels for demonstration purposes
picks = picks[:4]
-tmin, tmax = 0, 60 # use the first 60s of data
-fmin, fmax = 2, 300 # look at frequencies between 2 and 300Hz
-NFFT = 2048 # the FFT size (NFFT). Ideally a power of 2
-psds, freqs = compute_raw_psd(raw, tmin=tmin, tmax=tmax, picks=picks,
- fmin=fmin, fmax=fmax, NFFT=NFFT, n_jobs=1,
- plot=False, proj=False)
+plt.figure()
+ax = plt.axes()
+raw.plot_psds(tmin=tmin, tmax=tmax, fmin=fmin, fmax=fmax, n_fft=n_fft,
+ n_jobs=1, proj=False, ax=ax, color=(0, 0, 1), picks=picks)
# And now do the same with SSP applied
-psds_ssp, freqs = compute_raw_psd(raw, tmin=tmin, tmax=tmax, picks=picks,
- fmin=fmin, fmax=fmax, NFFT=NFFT, n_jobs=1,
- plot=False, proj=True)
+raw.plot_psds(tmin=tmin, tmax=tmax, fmin=fmin, fmax=fmax, n_fft=n_fft,
+ n_jobs=1, proj=True, ax=ax, color=(0, 1, 0), picks=picks)
# And now do the same with SSP + notch filtering
raw.notch_filter(np.arange(60, 241, 60), picks=picks, n_jobs=1)
-psds_notch, freqs = compute_raw_psd(raw, tmin=tmin, tmax=tmax, picks=picks,
- fmin=fmin, fmax=fmax, NFFT=NFFT, n_jobs=1,
- plot=False, proj=True)
+raw.plot_psds(tmin=tmin, tmax=tmax, fmin=fmin, fmax=fmax, n_fft=n_fft,
+ n_jobs=1, proj=True, ax=ax, color=(1, 0, 0), picks=picks)
-# Convert PSDs to dB
-psds = 10 * np.log10(psds)
-psds_ssp = 10 * np.log10(psds_ssp)
-psds_notch = 10 * np.log10(psds_notch)
-
-###############################################################################
-# Compute mean and standard deviation across channels and then plot
-def plot_psds(freqs, psds, fill_color):
- psd_mean = np.mean(psds, axis=0)
- psd_std = np.std(psds, axis=0)
- hyp_limits = (psd_mean - psd_std, psd_mean + psd_std)
-
- pl.plot(freqs, psd_mean)
- pl.fill_between(freqs, hyp_limits[0], y2=hyp_limits[1], color=fill_color,
- alpha=0.5)
-
-import pylab as pl
-pl.figure()
-plot_psds(freqs, psds, (0, 0, 1, .3))
-plot_psds(freqs, psds_ssp, (0, 1, 0, .3))
-plot_psds(freqs, psds_notch, (0, 0.5, 0.5, .3))
-pl.xlabel('Freq (Hz)')
-pl.ylabel('Power Spectral Density (dB/Hz)')
-pl.legend(['Without SSP', 'With SSP', 'SSP + Notch'])
-pl.show()
+ax.set_title('Four left-temporal magnetometers')
+plt.legend(['Without SSP', 'With SSP', 'SSP + Notch'])
diff --git a/examples/time_frequency/plot_compute_source_psd_epochs.py b/examples/time_frequency/plot_compute_source_psd_epochs.py
index 9f49141..39583f0 100644
--- a/examples/time_frequency/plot_compute_source_psd_epochs.py
+++ b/examples/time_frequency/plot_compute_source_psd_epochs.py
@@ -16,7 +16,7 @@ Discrete Prolate Spheroidal Sequence (DPSS) windows.
print __doc__
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.datasets import sample
from mne.fiff import Raw, pick_types
@@ -82,8 +82,8 @@ for i, stc in enumerate(stcs):
psd_avg /= n_epochs
freqs = stc.times # the frequencies are stored here
-pl.figure()
-pl.plot(freqs, psd_avg)
-pl.xlabel('Freq (Hz)')
-pl.ylabel('Power Spectral Density')
-pl.show()
+plt.figure()
+plt.plot(freqs, psd_avg)
+plt.xlabel('Freq (Hz)')
+plt.ylabel('Power Spectral Density')
+plt.show()
diff --git a/examples/time_frequency/plot_single_trial_spectra.py b/examples/time_frequency/plot_single_trial_spectra.py
new file mode 100644
index 0000000..735ac7b
--- /dev/null
+++ b/examples/time_frequency/plot_single_trial_spectra.py
@@ -0,0 +1,84 @@
+"""
+======================================
+Investigate Single Trial Power Spectra
+======================================
+
+In this example we will look at single trial spectra and then
+compute average spectra to identify channels and
+frequencies of interest for subsequent TFR analyses.
+"""
+
+# Authors: Denis Engemann <d.engemann at fz-juelich.de>
+#
+# License: BSD (3-clause)
+
+print __doc__
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+import mne
+from mne import fiff
+from mne.datasets import sample
+from mne.time_frequency import compute_epochs_psd
+###############################################################################
+# Set parameters
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
+event_fname = data_path + '/MEG/sample/sample_audvis_raw-eve.fif'
+
+# Setup for reading the raw data
+raw = fiff.Raw(raw_fname)
+events = mne.read_events(event_fname)
+
+tmin, tmax, event_id = -1., 1., 1
+include = []
+raw.info['bads'] += ['MEG 2443'] # bads
+
+# picks MEG gradiometers
+picks = fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
+ stim=False, include=include, exclude='bads')
+
+epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks, proj=True,
+ baseline=(None, 0), reject=dict(grad=4000e-13, eog=150e-6))
+
+
+n_fft = 256 # the FFT size. Ideally a power of 2
+psds, freqs = compute_epochs_psd(epochs, fmin=2, fmax=200, n_fft=n_fft,
+ n_jobs=2)
+
+# average psds and save psds from first trial separately
+average_psds = psds.mean(0)
+average_psds = 10 * np.log10(average_psds) # transform into dB
+some_psds = 10 * np.log10(psds[12])
+
+
+fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True, figsize=(10, 5))
+
+fig.suptitle('Single trial power', fontsize=12)
+
+freq_mask = freqs < 150
+freqs = freqs[freq_mask]
+
+ax1.set_title('single trial', fontsize=10)
+ax1.imshow(some_psds[:, freq_mask].T, aspect='auto', origin='lower')
+ax1.set_yticks(np.arange(0, len(freqs), 10))
+ax1.set_yticklabels(freqs[::10].round(1))
+ax1.set_ylabel('Frequency (Hz)')
+
+ax2.set_title('averaged over trials', fontsize=10)
+ax2.imshow(average_psds[:, freq_mask].T, aspect='auto', origin='lower')
+ax2.set_xticks(np.arange(0, len(picks), 30))
+ax2.set_xticklabels(picks[::30])
+ax2.set_xlabel('MEG channel index (Gradiomemters)')
+
+mne.viz.tight_layout()
+plt.show()
+
+# In the second image we clearly observe certain channel groups exposing
+# stronger power than others. Second, in comparison to the single
+# trial image we can see the frequency extent slightly growing for these
+# channels which might indicate oscillatory responses.
+# The ``plot_time_frequency.py`` example investigates one of the channels
+# around index 140.
+# Finally, also note the power line artifacts across all channels.
diff --git a/examples/time_frequency/plot_source_label_time_frequency.py b/examples/time_frequency/plot_source_label_time_frequency.py
index a1654e9..b0e6553 100644
--- a/examples/time_frequency/plot_source_label_time_frequency.py
+++ b/examples/time_frequency/plot_source_label_time_frequency.py
@@ -3,10 +3,13 @@
Compute power and phase lock in label of the source space
=========================================================
-Returns time-frequency maps of induced power and phase lock
-in the source space. The inverse method is linear based on dSPM inverse
-operator.
+Compute time-frequency maps of power and phase lock in the source space.
+The inverse method is linear based on dSPM inverse operator.
+The example also shows the difference in the time-frequency maps
+when they are computed with and without subtracting the evoked response
+from each epoch. The former results in induced activity only while the
+latter also includes evoked (stimulus-locked) activity.
"""
# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
#
@@ -26,10 +29,10 @@ from mne.minimum_norm import read_inverse_operator, source_induced_power
data_path = sample.data_path()
raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
fname_inv = data_path + '/MEG/sample/sample_audvis-meg-oct-6-meg-inv.fif'
-label_name = 'Aud-lh'
+label_name = 'Aud-rh'
fname_label = data_path + '/MEG/sample/labels/%s.label' % label_name
-tmin, tmax, event_id = -0.2, 0.5, 1
+tmin, tmax, event_id = -0.2, 0.5, 2
# Setup for reading the raw data
raw = fiff.Raw(raw_fname)
@@ -39,48 +42,59 @@ inverse_operator = read_inverse_operator(fname_inv)
include = []
raw.info['bads'] += ['MEG 2443', 'EEG 053'] # bads + 2 more
-# picks MEG channels
+# Picks MEG channels
picks = fiff.pick_types(raw.info, meg=True, eeg=False, eog=True,
- stim=False, include=include, exclude='bads')
+ stim=False, include=include, exclude='bads')
+reject = dict(grad=4000e-13, mag=4e-12, eog=150e-6)
-# Load condition 1
-event_id = 1
+# Load epochs
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks,
- baseline=(None, 0), reject=dict(grad=4000e-13, eog=150e-6),
+ baseline=(None, 0), reject=reject,
preload=True)
-# Compute a source estimate per frequency band
+# Compute a source estimate per frequency band including and excluding the
+# evoked response
frequencies = np.arange(7, 30, 2) # define frequencies of interest
label = mne.read_label(fname_label)
-n_cycles = frequencies / float(7) # different number of cycle per frequency
-power, phase_lock = source_induced_power(epochs, inverse_operator, frequencies,
- label, baseline=(-0.1, 0), baseline_mode='percent',
- n_cycles=n_cycles, n_jobs=1)
+n_cycles = frequencies / 3. # different number of cycle per frequency
-power = np.mean(power, axis=0) # average over sources
-phase_lock = np.mean(phase_lock, axis=0) # average over sources
-times = epochs.times
+# subtract the evoked response in order to exclude evoked activity
+epochs_induced = epochs.copy().subtract_evoked()
-###############################################################################
-# View time-frequency plots
-import pylab as pl
-pl.clf()
-pl.subplots_adjust(0.1, 0.08, 0.96, 0.94, 0.2, 0.43)
-pl.subplot(2, 1, 1)
-pl.imshow(20 * power, extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]],
- aspect='auto', origin='lower')
-pl.xlabel('Time (s)')
-pl.ylabel('Frequency (Hz)')
-pl.title('Induced power in %s' % label_name)
-pl.colorbar()
-
-pl.subplot(2, 1, 2)
-pl.imshow(phase_lock, extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]],
- aspect='auto', origin='lower')
-pl.xlabel('Time (s)')
-pl.ylabel('Frequency (Hz)')
-pl.title('Phase-lock in %s' % label_name)
-pl.colorbar()
-pl.show()
+import matplotlib.pyplot as plt
+plt.close('all')
+
+for ii, (this_epochs, title) in enumerate(zip([epochs, epochs_induced],
+ ['evoked + induced',
+ 'induced only'])):
+ # compute the source space power and phase lock
+ power, phase_lock = source_induced_power(this_epochs, inverse_operator,
+ frequencies, label, baseline=(-0.1, 0), baseline_mode='percent',
+ n_cycles=n_cycles, n_jobs=1)
+
+ power = np.mean(power, axis=0) # average over sources
+ phase_lock = np.mean(phase_lock, axis=0) # average over sources
+ times = epochs.times
+
+ ##########################################################################
+ # View time-frequency plots
+ plt.subplots_adjust(0.1, 0.08, 0.96, 0.94, 0.2, 0.43)
+ plt.subplot(2, 2, 2 * ii + 1)
+ plt.imshow(20 * power,
+ extent=[times[0], times[-1], frequencies[0], frequencies[-1]],
+ aspect='auto', origin='lower', vmin=0., vmax=30.)
+ plt.xlabel('Time (s)')
+ plt.ylabel('Frequency (Hz)')
+ plt.title('Power (%s)' % title)
+ plt.colorbar()
+
+ plt.subplot(2, 2, 2 * ii + 2)
+ plt.imshow(phase_lock,
+ extent=[times[0], times[-1], frequencies[0], frequencies[-1]],
+ aspect='auto', origin='lower', vmin=0, vmax=0.7)
+ plt.xlabel('Time (s)')
+ plt.ylabel('Frequency (Hz)')
+ plt.title('Phase-lock (%s)' % title)
+ plt.colorbar()
+
+plt.show()
diff --git a/examples/time_frequency/plot_source_power_spectrum.py b/examples/time_frequency/plot_source_power_spectrum.py
index 0a7d05f..d761cd1 100644
--- a/examples/time_frequency/plot_source_power_spectrum.py
+++ b/examples/time_frequency/plot_source_power_spectrum.py
@@ -41,15 +41,15 @@ label = mne.read_label(fname_label)
stc = compute_source_psd(raw, inverse_operator, lambda2=1. / 9., method="dSPM",
tmin=tmin, tmax=tmax, fmin=fmin, fmax=fmax,
- pick_normal=True, NFFT=NFFT, label=label)
+ pick_ori="normal", NFFT=NFFT, label=label)
stc.save('psd_dSPM')
###############################################################################
# View PSD of sources in label
-import pylab as pl
-pl.plot(1e3 * stc.times, stc.data.T)
-pl.xlabel('Frequency (Hz)')
-pl.ylabel('PSD (dB)')
-pl.title('Source Power Spectrum (PSD)')
-pl.show()
+import matplotlib.pyplot as plt
+plt.plot(1e3 * stc.times, stc.data.T)
+plt.xlabel('Frequency (Hz)')
+plt.ylabel('PSD (dB)')
+plt.title('Source Power Spectrum (PSD)')
+plt.show()
diff --git a/examples/time_frequency/plot_source_space_time_frequency.py b/examples/time_frequency/plot_source_space_time_frequency.py
index 81cea6a..33b6002 100644
--- a/examples/time_frequency/plot_source_space_time_frequency.py
+++ b/examples/time_frequency/plot_source_space_time_frequency.py
@@ -57,11 +57,11 @@ for b, stc in stcs.iteritems():
###############################################################################
# plot mean power
-import pylab as pl
-pl.plot(stcs['alpha'].times, stcs['alpha'].data.mean(axis=0), label='Alpha')
-pl.plot(stcs['beta'].times, stcs['beta'].data.mean(axis=0), label='Beta')
-pl.xlabel('Time (ms)')
-pl.ylabel('Power')
-pl.legend()
-pl.title('Mean source induced power')
-pl.show()
+import matplotlib.pyplot as plt
+plt.plot(stcs['alpha'].times, stcs['alpha'].data.mean(axis=0), label='Alpha')
+plt.plot(stcs['beta'].times, stcs['beta'].data.mean(axis=0), label='Beta')
+plt.xlabel('Time (ms)')
+plt.ylabel('Power')
+plt.legend()
+plt.title('Mean source induced power')
+plt.show()
diff --git a/examples/time_frequency/plot_temporal_whitening.py b/examples/time_frequency/plot_temporal_whitening.py
index 45ed5b4..1185955 100644
--- a/examples/time_frequency/plot_temporal_whitening.py
+++ b/examples/time_frequency/plot_temporal_whitening.py
@@ -15,7 +15,7 @@ print __doc__
import numpy as np
from scipy import signal
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne.time_frequency import ar_raw
@@ -49,15 +49,15 @@ d_ = np.r_[d_[0] * np.ones(order), d_] # dummy samples to keep signal length
###############################################################################
# Plot the different time series and PSDs
-pl.close('all')
-pl.figure()
-pl.plot(d[:100], label='signal')
-pl.plot(d_[:100], label='regenerated signal')
-pl.legend()
-
-pl.figure()
-pl.psd(d, Fs=raw.info['sfreq'], NFFT=2048)
-pl.psd(innovation, Fs=raw.info['sfreq'], NFFT=2048)
-pl.psd(d_, Fs=raw.info['sfreq'], NFFT=2048, linestyle='--')
-pl.legend(('Signal', 'Innovation', 'Regenerated signal'))
-pl.show()
+plt.close('all')
+plt.figure()
+plt.plot(d[:100], label='signal')
+plt.plot(d_[:100], label='regenerated signal')
+plt.legend()
+
+plt.figure()
+plt.psd(d, Fs=raw.info['sfreq'], NFFT=2048)
+plt.psd(innovation, Fs=raw.info['sfreq'], NFFT=2048)
+plt.psd(d_, Fs=raw.info['sfreq'], NFFT=2048, linestyle='--')
+plt.legend(('Signal', 'Innovation', 'Regenerated signal'))
+plt.show()
diff --git a/examples/time_frequency/plot_tfr_topography.py b/examples/time_frequency/plot_tfr_topography.py
index 5757485..9b3b87e 100644
--- a/examples/time_frequency/plot_tfr_topography.py
+++ b/examples/time_frequency/plot_tfr_topography.py
@@ -13,7 +13,7 @@ print __doc__
# License: BSD (3-clause)
import numpy as np
-import pylab as pl
+import matplotlib.pyplot as plt
import mne
from mne import fiff
from mne.time_frequency import induced_power
@@ -66,7 +66,7 @@ mode = 'ratio' # set mode for baseline rescaling
title = 'Induced power - MNE sample data'
plot_topo_power(epochs, power, frequencies, layout, baseline=baseline,
mode=mode, decim=decim, vmin=0., vmax=14, title=title)
-pl.show()
+plt.show()
###############################################################################
# Show topography of phase locking value (PLV)
@@ -77,4 +77,4 @@ title = 'Phase locking value - MNE sample data'
plot_topo_phase_lock(epochs, phase_lock, frequencies, layout,
baseline=baseline, mode=mode, decim=decim, title=title)
-pl.show()
+plt.show()
diff --git a/examples/time_frequency/plot_time_frequency.py b/examples/time_frequency/plot_time_frequency.py
index 4fefd0a..98248b1 100644
--- a/examples/time_frequency/plot_time_frequency.py
+++ b/examples/time_frequency/plot_time_frequency.py
@@ -64,32 +64,32 @@ power /= np.mean(power[:, :, times[::decim] < 0], axis=2)[:, :, None]
###############################################################################
# View time-frequency plots
-import pylab as pl
-pl.clf()
-pl.subplots_adjust(0.1, 0.08, 0.96, 0.94, 0.2, 0.63)
-pl.subplot(3, 1, 1)
-pl.plot(times, evoked_data.T)
-pl.title('Evoked response (%s)' % evoked.ch_names[97])
-pl.xlabel('time (ms)')
-pl.ylabel('Magnetic Field (fT/cm)')
-pl.xlim(times[0], times[-1])
-pl.ylim(-150, 300)
-
-pl.subplot(3, 1, 2)
-pl.imshow(20 * np.log10(power[0]), extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]],
- aspect='auto', origin='lower')
-pl.xlabel('Time (s)')
-pl.ylabel('Frequency (Hz)')
-pl.title('Induced power (%s)' % evoked.ch_names[97])
-pl.colorbar()
-
-pl.subplot(3, 1, 3)
-pl.imshow(phase_lock[0], extent=[times[0], times[-1],
- frequencies[0], frequencies[-1]],
- aspect='auto', origin='lower')
-pl.xlabel('Time (s)')
-pl.ylabel('Frequency (Hz)')
-pl.title('Phase-lock (%s)' % evoked.ch_names[97])
-pl.colorbar()
-pl.show()
+import matplotlib.pyplot as plt
+plt.clf()
+plt.subplots_adjust(0.1, 0.08, 0.96, 0.94, 0.2, 0.63)
+plt.subplot(3, 1, 1)
+plt.plot(times, evoked_data.T)
+plt.title('Evoked response (%s)' % evoked.ch_names[97])
+plt.xlabel('time (ms)')
+plt.ylabel('Magnetic Field (fT/cm)')
+plt.xlim(times[0], times[-1])
+plt.ylim(-150, 300)
+
+plt.subplot(3, 1, 2)
+plt.imshow(20 * np.log10(power[0]),
+ extent=[times[0], times[-1], frequencies[0], frequencies[-1]],
+ aspect='auto', origin='lower')
+plt.xlabel('Time (s)')
+plt.ylabel('Frequency (Hz)')
+plt.title('Induced power (%s)' % evoked.ch_names[97])
+plt.colorbar()
+
+plt.subplot(3, 1, 3)
+plt.imshow(phase_lock[0],
+ extent=[times[0], times[-1], frequencies[0], frequencies[-1]],
+ aspect='auto', origin='lower')
+plt.xlabel('Time (s)')
+plt.ylabel('Frequency (Hz)')
+plt.title('Phase-lock (%s)' % evoked.ch_names[97])
+plt.colorbar()
+plt.show()
diff --git a/mne/__init__.py b/mne/__init__.py
index b2d9480..0533066 100644
--- a/mne/__init__.py
+++ b/mne/__init__.py
@@ -1,49 +1,56 @@
"""MNE for MEG and EEG data analysis
"""
-__version__ = '0.6'
+__version__ = '0.7.git'
# have to import verbose first since it's needed by many things
-from .utils import set_log_level, set_log_file, verbose, set_config, \
- get_config, get_config_path
+from .utils import (set_log_level, set_log_file, verbose, set_config,
+ get_config, get_config_path, set_cache_dir,
+ set_memmap_min_size)
-from .cov import read_cov, write_cov, Covariance, \
- compute_covariance, compute_raw_data_covariance, \
- whiten_evoked
-from .event import read_events, write_events, find_events, merge_events, \
- pick_events, make_fixed_length_events, concatenate_events, \
- find_stim_steps
-from .forward import read_forward_solution, apply_forward, apply_forward_raw, \
- do_forward_solution, average_forward_solutions, \
- write_forward_solution
-from .source_estimate import read_stc, write_stc, read_w, write_w, \
- read_source_estimate, \
- SourceEstimate, morph_data, \
- morph_data_precomputed, compute_morph_matrix, \
- grade_to_tris, grade_to_vertices, \
- spatial_src_connectivity, \
- spatial_tris_connectivity, \
- spatial_dist_connectivity, \
- spatio_temporal_src_connectivity, \
- spatio_temporal_tris_connectivity, \
- spatio_temporal_dist_connectivity, \
- save_stc_as_volume, extract_label_time_course
-from .surface import read_bem_surfaces, read_surface, write_bem_surface, \
- write_surface
-from .source_space import read_source_spaces, vertex_to_mni, \
- write_source_spaces
+from .cov import (read_cov, write_cov, Covariance,
+ compute_covariance, compute_raw_data_covariance,
+ whiten_evoked)
+from .event import (read_events, write_events, find_events, merge_events,
+ pick_events, make_fixed_length_events, concatenate_events,
+ find_stim_steps)
+from .forward import (read_forward_solution, apply_forward, apply_forward_raw,
+ do_forward_solution, average_forward_solutions,
+ write_forward_solution, make_forward_solution,
+ convert_forward_solution)
+from .source_estimate import (read_source_estimate,
+ SourceEstimate, VolSourceEstimate, morph_data,
+ morph_data_precomputed, compute_morph_matrix,
+ grade_to_tris, grade_to_vertices,
+ spatial_src_connectivity,
+ spatial_tris_connectivity,
+ spatial_dist_connectivity,
+ spatio_temporal_src_connectivity,
+ spatio_temporal_tris_connectivity,
+ spatio_temporal_dist_connectivity,
+ save_stc_as_volume, extract_label_time_course)
+from .surface import (read_bem_surfaces, read_surface, write_bem_surface,
+ write_surface, decimate_surface, read_morph_map,
+ read_bem_solution)
+from .source_space import (read_source_spaces, vertex_to_mni,
+ write_source_spaces, setup_source_space,
+ setup_volume_source_space,
+ add_source_space_distances)
from .epochs import Epochs, read_epochs
-from .label import label_time_courses, read_label, label_sign_flip, \
- write_label, stc_to_label, grow_labels, Label, \
- BiHemiLabel, labels_from_parc
+from .label import (label_time_courses, read_label, label_sign_flip,
+ write_label, stc_to_label, grow_labels, Label,
+ BiHemiLabel, labels_from_parc, parc_from_labels)
from .misc import parse_config, read_reject_parameters
+from .coreg import (create_default_subject, scale_mri, scale_labels,
+ scale_source_space)
from .transforms import transform_coordinates, read_trans, write_trans
-from .proj import read_proj, write_proj, compute_proj_epochs, \
- compute_proj_evoked, compute_proj_raw, sensitivity_map
+from .proj import (read_proj, write_proj, compute_proj_epochs,
+ compute_proj_evoked, compute_proj_raw, sensitivity_map)
from .selection import read_selection
from .dipole import read_dip
from . import beamformer
from . import connectivity
+from . import coreg
from . import cuda
from . import datasets
from . import epochs
@@ -58,6 +65,8 @@ from . import stats
from . import tests
from . import time_frequency
from . import viz
+from . import decoding
+from . import realtime
# initialize logging
set_log_level(None, False)
diff --git a/mne/baseline.py b/mne/baseline.py
index d12b7a6..de81f7e 100644
--- a/mne/baseline.py
+++ b/mne/baseline.py
@@ -6,10 +6,8 @@
# License: BSD (3-clause)
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-from . import verbose
+from .utils import logger, verbose
@verbose
@@ -65,7 +63,11 @@ def rescale(data, times, baseline, mode, verbose=None, copy=True):
else:
imax = int(np.where(times <= bmax)[0][-1]) + 1
- mean = np.mean(data[..., imin:imax], axis=-1)[..., None]
+ # avoid potential "empty slice" warning
+ if data.shape[-1] > 0:
+ mean = np.mean(data[..., imin:imax], axis=-1)[..., None]
+ else:
+ mean = 0 # otherwise we get an ugly nan
if mode == 'mean':
data -= mean
if mode == 'logratio':
diff --git a/mne/beamformer/__init__.py b/mne/beamformer/__init__.py
index b6c1ad7..ad8b9e0 100644
--- a/mne/beamformer/__init__.py
+++ b/mne/beamformer/__init__.py
@@ -1,4 +1,5 @@
"""Beamformers for source localization
"""
-from ._lcmv import lcmv, lcmv_epochs, lcmv_raw
+from ._lcmv import lcmv, lcmv_epochs, lcmv_raw, tf_lcmv
+from ._dics import dics, dics_epochs, dics_source_power, tf_dics
diff --git a/mne/beamformer/_dics.py b/mne/beamformer/_dics.py
new file mode 100644
index 0000000..39b4b16
--- /dev/null
+++ b/mne/beamformer/_dics.py
@@ -0,0 +1,587 @@
+"""Dynamic Imaging of Coherent Sources (DICS).
+"""
+
+# Authors: Roman Goj <roman.goj at gmail.com>
+#
+# License: BSD (3-clause)
+
+import warnings
+from copy import deepcopy
+
+import numpy as np
+from scipy import linalg
+
+from ..utils import logger, verbose
+from ..fiff.pick import pick_types
+from ..forward import _subject_from_forward
+from ..minimum_norm.inverse import combine_xyz
+from ..source_estimate import SourceEstimate
+from ..time_frequency import CrossSpectralDensity, compute_epochs_csd
+from ._lcmv import _prepare_beamformer_input
+
+
+ at verbose
+def _apply_dics(data, info, tmin, forward, noise_csd, data_csd, reg,
+ label=None, picks=None, pick_ori=None, verbose=None):
+ """Dynamic Imaging of Coherent Sources (DICS).
+
+ Calculate the DICS spatial filter based on a given cross-spectral
+ density object and return estimates of source activity based on given data.
+
+ Parameters
+ ----------
+ data : array or list / iterable
+ Sensor space data. If data.ndim == 2 a single observation is assumed
+ and a single stc is returned. If data.ndim == 3 or if data is
+ a list / iterable, a list of stc's is returned.
+ info : dict
+ Measurement info.
+ tmin : float
+ Time of first sample.
+ forward : dict
+ Forward operator.
+ noise_csd : instance of CrossSpectralDensity
+ The noise cross-spectral density.
+ data_csd : instance of CrossSpectralDensity
+ The data cross-spectral density.
+ reg : float
+ The regularization for the cross-spectral density.
+ label : Label | None
+ Restricts the solution to a given label.
+ picks : array of int | None
+ Indices (in info) of data channels. If None, MEG and EEG data channels
+ (without bad channels) will be used.
+ pick_ori : None | 'normal'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ stc : SourceEstimate (or list of SourceEstimate)
+ Source time courses.
+ """
+
+ is_free_ori, picks, _, proj, vertno, G =\
+ _prepare_beamformer_input(info, forward, label, picks, pick_ori)
+
+ Cm = data_csd.data
+
+ # Calculating regularized inverse, equivalent to an inverse operation after
+ # regularization: Cm += reg * np.trace(Cm) / len(Cm) * np.eye(len(Cm))
+ Cm_inv = linalg.pinv(Cm, reg)
+
+ # Compute spatial filters
+ W = np.dot(G.T, Cm_inv)
+ n_orient = 3 if is_free_ori else 1
+ n_sources = G.shape[1] // n_orient
+
+ for k in xrange(n_sources):
+ Wk = W[n_orient * k: n_orient * k + n_orient]
+ Gk = G[:, n_orient * k: n_orient * k + n_orient]
+ Ck = np.dot(Wk, Gk)
+
+ # TODO: max-power is not implemented yet, however DICS does employ
+ # orientation picking when one eigen value is much larger than the
+ # other
+
+ if is_free_ori:
+ # Free source orientation
+ Wk[:] = np.dot(linalg.pinv(Ck, 0.1), Wk)
+ else:
+ # Fixed source orientation
+ Wk /= Ck
+
+ # Noise normalization
+ noise_norm = np.dot(np.dot(Wk.conj(), noise_csd.data), Wk.T)
+ noise_norm = np.abs(noise_norm).trace()
+ Wk /= np.sqrt(noise_norm)
+
+ # Pick source orientation normal to cortical surface
+ if pick_ori == 'normal':
+ W = W[2::3]
+ is_free_ori = False
+
+ if isinstance(data, np.ndarray) and data.ndim == 2:
+ data = [data]
+ return_single = True
+ else:
+ return_single = False
+
+ subject = _subject_from_forward(forward)
+ for i, M in enumerate(data):
+ if len(M) != len(picks):
+ raise ValueError('data and picks must have the same length')
+
+ if not return_single:
+ logger.info("Processing epoch : %d" % (i + 1))
+
+ # Apply SSPs
+ if info['projs']:
+ M = np.dot(proj, M)
+
+ # project to source space using beamformer weights
+ if is_free_ori:
+ sol = np.dot(W, M)
+ logger.info('combining the current components...')
+ sol = combine_xyz(sol)
+ else:
+ # Linear inverse: do not delay compuation due to non-linear abs
+ sol = np.dot(W, M)
+
+ tstep = 1.0 / info['sfreq']
+ if np.iscomplexobj(sol):
+ sol = np.abs(sol) # XXX : STC cannot contain (yet?) complex values
+ yield SourceEstimate(sol, vertices=vertno, tmin=tmin, tstep=tstep,
+ subject=subject)
+
+ logger.info('[done]')
+
+
+ at verbose
+def dics(evoked, forward, noise_csd, data_csd, reg=0.01, label=None,
+ pick_ori=None, verbose=None):
+ """Dynamic Imaging of Coherent Sources (DICS).
+
+ Compute a Dynamic Imaging of Coherent Sources (DICS) beamformer
+ on evoked data and return estimates of source time courses.
+
+ NOTE : Fixed orientation forward operators will result in complex time
+ courses in which case absolute values will be returned. Therefore the
+ orientation will no longer be fixed.
+
+ NOTE : This implementation has not been heavily tested so please
+ report any issues or suggestions.
+
+ Parameters
+ ----------
+ evoked : Evooked
+ Evoked data.
+ forward : dict
+ Forward operator.
+ noise_csd : instance of CrossSpectralDensity
+ The noise cross-spectral density.
+ data_csd : instance of CrossSpectralDensity
+ The data cross-spectral density.
+ reg : float
+ The regularization for the cross-spectral density.
+ label : Label | None
+ Restricts the solution to a given label.
+ pick_ori : None | 'normal'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ stc : SourceEstimate
+ Source time courses
+
+ Notes
+ -----
+ The original reference is:
+ Gross et al. Dynamic imaging of coherent sources: Studying neural
+ interactions in the human brain. PNAS (2001) vol. 98 (2) pp. 694-699
+ """
+ info = evoked.info
+ data = evoked.data
+ tmin = evoked.times[0]
+
+ stc = _apply_dics(data, info, tmin, forward, noise_csd, data_csd, reg=reg,
+ label=label, pick_ori=pick_ori)
+ return stc.next()
+
+
+ at verbose
+def dics_epochs(epochs, forward, noise_csd, data_csd, reg=0.01, label=None,
+ pick_ori=None, return_generator=False, verbose=None):
+ """Dynamic Imaging of Coherent Sources (DICS).
+
+ Compute a Dynamic Imaging of Coherent Sources (DICS) beamformer
+ on single trial data and return estimates of source time courses.
+
+ NOTE : Fixed orientation forward operators will result in complex time
+ courses in which case absolute values will be returned. Therefore the
+ orientation will no longer be fixed.
+
+ NOTE : This implementation has not been heavily tested so please
+ report any issues or suggestions.
+
+ Parameters
+ ----------
+ epochs : Epochs
+ Single trial epochs.
+ forward : dict
+ Forward operator.
+ noise_csd : instance of CrossSpectralDensity
+ The noise cross-spectral density.
+ data_csd : instance of CrossSpectralDensity
+ The data cross-spectral density.
+ reg : float
+ The regularization for the cross-spectral density.
+ label : Label | None
+ Restricts the solution to a given label.
+ pick_ori : None | 'normal'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept.
+ return_generator : bool
+ Return a generator object instead of a list. This allows iterating
+ over the stcs without having to keep them all in memory.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ stc: list | generator of SourceEstimate
+ The source estimates for all epochs
+
+ Notes
+ -----
+ The original reference is:
+ Gross et al. Dynamic imaging of coherent sources: Studying neural
+ interactions in the human brain. PNAS (2001) vol. 98 (2) pp. 694-699
+ """
+
+ info = epochs.info
+ tmin = epochs.times[0]
+
+ # use only the good data channels
+ picks = pick_types(info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
+ data = epochs.get_data()[:, picks, :]
+
+ stcs = _apply_dics(data, info, tmin, forward, noise_csd, data_csd, reg=reg,
+ label=label, pick_ori=pick_ori)
+
+ if not return_generator:
+ stcs = list(stcs)
+
+ return stcs
+
+
+ at verbose
+def dics_source_power(info, forward, noise_csds, data_csds, reg=0.01,
+ label=None, pick_ori=None, verbose=None):
+ """Dynamic Imaging of Coherent Sources (DICS).
+
+ Calculate source power in time and frequency windows specified in the
+ calculation of the data cross-spectral density matrix or matrices. Source
+ power is normalized by noise power.
+
+ NOTE : This implementation has not been heavily tested so please
+ report any issues or suggestions.
+
+ Parameters
+ ----------
+ info : dict
+ Measurement info, e.g. epochs.info.
+ forward : dict
+ Forward operator.
+ noise_csds : instance or list of instances of CrossSpectralDensity
+ The noise cross-spectral density matrix for a single frequency or a
+ list of matrices for multiple frequencies.
+ data_csds : instance or list of instances of CrossSpectralDensity
+ The data cross-spectral density matrix for a single frequency or a list
+ of matrices for multiple frequencies.
+ reg : float
+ The regularization for the cross-spectral density.
+ label : Label | None
+ Restricts the solution to a given label.
+ pick_ori : None | 'normal'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ stc : SourceEstimate
+ Source power with frequency instead of time.
+
+ Notes
+ -----
+ The original reference is:
+ Gross et al. Dynamic imaging of coherent sources: Studying neural
+ interactions in the human brain. PNAS (2001) vol. 98 (2) pp. 694-699
+ """
+
+ if isinstance(data_csds, CrossSpectralDensity):
+ data_csds = [data_csds]
+
+ if isinstance(noise_csds, CrossSpectralDensity):
+ noise_csds = [noise_csds]
+
+ csd_shapes = lambda x: tuple(c.data.shape for c in x)
+ if (csd_shapes(data_csds) != csd_shapes(noise_csds) or
+ any([len(set(csd_shapes(c))) > 1 for c in [data_csds, noise_csds]])):
+ raise ValueError('One noise CSD matrix should be provided for each '
+ 'data CSD matrix and vice versa. All CSD matrices '
+ 'should have identical shape.')
+
+ frequencies = []
+ for data_csd, noise_csd in zip(data_csds, noise_csds):
+ if not np.allclose(data_csd.frequencies, noise_csd.frequencies):
+ raise ValueError('Data and noise CSDs should be calculated at '
+ 'identical frequencies')
+
+ # If CSD is summed over multiple frequencies, take the average
+ # frequency
+ if(len(data_csd.frequencies) > 1):
+ frequencies.append(np.mean(data_csd.frequencies))
+ else:
+ frequencies.append(data_csd.frequencies[0])
+ fmin = frequencies[0]
+
+ if len(frequencies) > 2:
+ fstep = []
+ for i in range(len(frequencies) - 1):
+ fstep.append(frequencies[i+1] - frequencies[i])
+ if not np.allclose(fstep, np.mean(fstep), 1e-5):
+ warnings.warn('Uneven frequency spacing in CSD object, '
+ 'frequencies in the resulting stc file will be '
+ 'inaccurate.')
+ fstep = fstep[0]
+ elif len(frequencies) > 1:
+ fstep = frequencies[1] - frequencies[0]
+ else:
+ fstep = 1 # dummy value
+
+ is_free_ori, picks, _, proj, vertno, G =\
+ _prepare_beamformer_input(info, forward, label, picks=None,
+ pick_ori=pick_ori)
+
+ n_orient = 3 if is_free_ori else 1
+ n_sources = G.shape[1] // n_orient
+ source_power = np.zeros((n_sources, len(data_csds)))
+ n_csds = len(data_csds)
+
+ logger.info('Computing DICS source power...')
+ for i, (data_csd, noise_csd) in enumerate(zip(data_csds, noise_csds)):
+ if n_csds > 1:
+ logger.info(' computing DICS spatial filter %d out of %d' %
+ (i + 1, n_csds))
+
+ Cm = data_csd.data
+
+ # Calculating regularized inverse, equivalent to an inverse operation
+ # after the following regularization:
+ # Cm += reg * np.trace(Cm) / len(Cm) * np.eye(len(Cm))
+ Cm_inv = linalg.pinv(Cm, reg)
+
+ # Compute spatial filters
+ W = np.dot(G.T, Cm_inv)
+ for k in xrange(n_sources):
+ Wk = W[n_orient * k: n_orient * k + n_orient]
+ Gk = G[:, n_orient * k: n_orient * k + n_orient]
+ Ck = np.dot(Wk, Gk)
+
+ if is_free_ori:
+ # Free source orientation
+ Wk[:] = np.dot(linalg.pinv(Ck, 0.1), Wk)
+ else:
+ # Fixed source orientation
+ Wk /= Ck
+
+ # Noise normalization
+ noise_norm = np.dot(np.dot(Wk.conj(), noise_csd.data), Wk.T)
+ noise_norm = np.abs(noise_norm).trace()
+
+ # Calculating source power
+ sp_temp = np.dot(np.dot(Wk.conj(), data_csd.data), Wk.T)
+ sp_temp /= max(noise_norm, 1e-40) # Avoid division by 0
+
+ if pick_ori == 'normal':
+ source_power[k, i] = np.abs(sp_temp)[2, 2]
+ else:
+ source_power[k, i] = np.abs(sp_temp).trace()
+
+ logger.info('[done]')
+
+ subject = _subject_from_forward(forward)
+ return SourceEstimate(source_power, vertices=vertno, tmin=fmin / 1000.,
+ tstep=fstep / 1000., subject=subject)
+
+
+ at verbose
+def tf_dics(epochs, forward, noise_csds, tmin, tmax, tstep, win_lengths,
+ freq_bins, subtract_evoked=False, mode='fourier', n_ffts=None,
+ mt_bandwidths=None, mt_adaptive=False, mt_low_bias=True, reg=0.01,
+ label=None, pick_ori=None, verbose=None):
+ """5D time-frequency beamforming based on DICS.
+
+ Calculate source power in time-frequency windows using a spatial filter
+ based on the Dynamic Imaging of Coherent Sources (DICS) beamforming
+ approach. For each time window and frequency bin combination cross-spectral
+ density (CSD) is computed and used to create a beamformer spatial filter
+ with noise CSD used for normalization.
+
+ NOTE : This implementation has not been heavily tested so please
+ report any issues or suggestions.
+
+ Parameters
+ ----------
+ epochs : Epochs
+ Single trial epochs.
+ forward : dict
+ Forward operator.
+ noise_csds : list of instances of CrossSpectralDensity
+ Noise cross-spectral density for each frequency bin.
+ tmin : float
+ Minimum time instant to consider.
+ tmax : float
+ Maximum time instant to consider.
+ tstep : float
+ Spacing between consecutive time windows, should be smaller than or
+ equal to the shortest time window length.
+ win_lengths : list of float
+ Time window lengths in seconds. One time window length should be
+ provided for each frequency bin.
+ freq_bins : list of tuples of float
+ Start and end point of frequency bins of interest.
+ subtract_evoked : bool
+ If True, subtract the averaged evoked response prior to computing the
+ tf source grid.
+ mode : str
+ Spectrum estimation mode can be either: 'multitaper' or 'fourier'.
+ mt_bandwidths : list of float
+ The bandwidths of the multitaper windowing function in Hz. Only used in
+ 'multitaper' mode. One value should be provided for each frequency bin.
+ mt_adaptive : bool
+ Use adaptive weights to combine the tapered spectra into CSD. Only used
+ in 'multitaper' mode.
+ mt_low_bias : bool
+ Only use tapers with more than 90% spectral concentration within
+ bandwidth. Only used in 'multitaper' mode.
+ reg : float
+ The regularization for the cross-spectral density.
+ label : Label | None
+ Restricts the solution to a given label.
+ pick_ori : None | 'normal'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ stcs : list of SourceEstimate
+ Source power at each time window. One SourceEstimate object is returned
+ for each frequency bin.
+
+ Notes
+ -----
+ The original reference is:
+ Dalal et al. Five-dimensional neuroimaging: Localization of the
+ time-frequency dynamics of cortical activity.
+ NeuroImage (2008) vol. 40 (4) pp. 1686-1700
+
+ NOTE : Dalal et al. used a synthetic aperture magnetometry beamformer (SAM)
+ in each time-frequency window instead of DICS.
+ """
+
+ if pick_ori not in [None, 'normal']:
+ raise ValueError('Unrecognized orientation option in pick_ori, '
+ 'available choices are None and normal')
+ if len(noise_csds) != len(freq_bins):
+ raise ValueError('One noise CSD object expected per frequency bin')
+ if len(win_lengths) != len(freq_bins):
+ raise ValueError('One time window length expected per frequency bin')
+ if any(win_length < tstep for win_length in win_lengths):
+ raise ValueError('Time step should not be larger than any of the '
+ 'window lengths')
+ if n_ffts is not None and len(n_ffts) != len(freq_bins):
+ raise ValueError('When specifiying number of FFT samples, one value '
+ 'must be provided per frequency bin')
+ if mt_bandwidths is not None and len(mt_bandwidths) != len(freq_bins):
+ raise ValueError('When using multitaper mode and specifying '
+ 'multitaper transform bandwidth, one value must be '
+ 'provided per frequency bin')
+
+ if n_ffts is None:
+ n_ffts = [None] * len(freq_bins)
+ if mt_bandwidths is None:
+ mt_bandwidths = [None] * len(freq_bins)
+
+ # Multiplying by 1e3 to avoid numerical issues, e.g. 0.3 // 0.05 == 5
+ n_time_steps = int(((tmax - tmin) * 1e3) // (tstep * 1e3))
+
+ # Subtract evoked response
+ if subtract_evoked:
+ epochs.subtract_evoked()
+
+ sol_final = []
+ for freq_bin, win_length, noise_csd, n_fft, mt_bandwidth in\
+ zip(freq_bins, win_lengths, noise_csds, n_ffts, mt_bandwidths):
+ n_overlap = int((win_length * 1e3) // (tstep * 1e3))
+
+ # Scale noise CSD to allow data and noise CSDs to have different length
+ noise_csd = deepcopy(noise_csd)
+ noise_csd.data /= noise_csd.n_fft
+
+ sol_single = []
+ sol_overlap = []
+ for i_time in range(n_time_steps):
+ win_tmin = tmin + i_time * tstep
+ win_tmax = win_tmin + win_length
+
+ # If in the last step the last time point was not covered in
+ # previous steps and will not be covered now, a solution needs to
+ # be calculated for an additional time window
+ if i_time == n_time_steps - 1 and win_tmax - tstep < tmax and\
+ win_tmax >= tmax + (epochs.times[-1] - epochs.times[-2]):
+ warnings.warn('Adding a time window to cover last time points')
+ win_tmin = tmax - win_length
+ win_tmax = tmax
+
+ if win_tmax < tmax + (epochs.times[-1] - epochs.times[-2]):
+ logger.info('Computing time-frequency DICS beamformer for '
+ 'time window %d to %d ms, in frequency range '
+ '%d to %d Hz' % (win_tmin * 1e3, win_tmax * 1e3,
+ freq_bin[0], freq_bin[1]))
+
+ # Calculating data CSD in current time window
+ data_csd = compute_epochs_csd(epochs, mode=mode,
+ fmin=freq_bin[0],
+ fmax=freq_bin[1], fsum=True,
+ tmin=win_tmin, tmax=win_tmax,
+ n_fft=n_fft,
+ mt_bandwidth=mt_bandwidth,
+ mt_low_bias=mt_low_bias)
+
+ # Scale data CSD to allow data and noise CSDs to have different
+ # length
+ data_csd.data /= data_csd.n_fft
+
+ stc = dics_source_power(epochs.info, forward, noise_csd,
+ data_csd, reg=reg, label=label,
+ pick_ori=pick_ori)
+ sol_single.append(stc.data[:, 0])
+
+ # Average over all time windows that contain the current time
+ # point, which is the current time window along with
+ # n_overlap - 1 previous ones
+ if i_time - n_overlap < 0:
+ curr_sol = np.mean(sol_single[0:i_time + 1], axis=0)
+ else:
+ curr_sol = np.mean(sol_single[i_time - n_overlap + 1:
+ i_time + 1], axis=0)
+
+ # The final result for the current time point in the current
+ # frequency bin
+ sol_overlap.append(curr_sol)
+
+ # Gathering solutions for all time points for current frequency bin
+ sol_final.append(sol_overlap)
+
+ sol_final = np.array(sol_final)
+
+ # Creating stc objects containing all time points for each frequency bin
+ stcs = []
+ for i_freq, _ in enumerate(freq_bins):
+ stc = SourceEstimate(sol_final[i_freq, :, :].T, vertices=stc.vertno,
+ tmin=tmin, tstep=tstep, subject=stc.subject)
+ stcs.append(stc)
+
+ return stcs
diff --git a/mne/beamformer/_lcmv.py b/mne/beamformer/_lcmv.py
index ffe869b..b599ff7 100644
--- a/mne/beamformer/_lcmv.py
+++ b/mne/beamformer/_lcmv.py
@@ -6,21 +6,21 @@
#
# License: BSD (3-clause)
+import warnings
+
import numpy as np
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
from ..fiff.constants import FIFF
from ..fiff.proj import make_projector
from ..fiff.pick import pick_types, pick_channels_forward, pick_channels_cov
from ..forward import _subject_from_forward
from ..minimum_norm.inverse import _get_vertno, combine_xyz
-from ..cov import compute_whitener
-from ..source_estimate import SourceEstimate
+from ..cov import compute_whitener, compute_covariance
+from ..source_estimate import _make_stc, SourceEstimate
from ..source_space import label_src_vertno_sel
-from .. import verbose
+from ..utils import logger, verbose
+from .. import Epochs
@verbose
@@ -51,50 +51,21 @@ def _apply_lcmv(data, info, tmin, forward, noise_cov, data_cov, reg,
picks : array of int | None
Indices (in info) of data channels. If None, MEG and EEG data channels
(without bad channels) will be used.
- pick_ori : None | 'max-power'
- If 'max-power', the source orientation that maximizes output source
- power is chosen.
+ pick_ori : None | 'normal' | 'max-power'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept. If 'max-power', the source
+ orientation that maximizes output source power is chosen.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
Returns
-------
- stc : SourceEstimate (or list of SourceEstimate)
+ stc : SourceEstimate | VolSourceEstimate (or list of thereof)
Source time courses.
"""
- is_free_ori = forward['source_ori'] == FIFF.FIFFV_MNE_FREE_ORI
-
- if pick_ori in ['max-power'] and not is_free_ori:
- raise ValueError('Max-power orientation can only be picked '
- 'when a forward operator with free orientation is '
- 'used.')
-
- if picks is None:
- picks = pick_types(info, meg=True, eeg=True, exclude='bads')
-
- ch_names = [info['ch_names'][k] for k in picks]
-
- # restrict forward solution to selected channels
- forward = pick_channels_forward(forward, include=ch_names)
-
- # get gain matrix (forward operator)
- if label is not None:
- vertno, src_sel = label_src_vertno_sel(label, forward['src'])
-
- if is_free_ori:
- src_sel = 3 * src_sel
- src_sel = np.c_[src_sel, src_sel + 1, src_sel + 2]
- src_sel = src_sel.ravel()
-
- G = forward['sol']['data'][:, src_sel]
- else:
- vertno = _get_vertno(forward['src'])
- G = forward['sol']['data']
-
- # Handle SSPs
- proj, ncomp, _ = make_projector(info['projs'], ch_names)
- G = np.dot(proj, G)
+ is_free_ori, picks, ch_names, proj, vertno, G =\
+ _prepare_beamformer_input(info, forward, label, picks, pick_ori)
# Handle whitening + data covariance
whitener, _ = compute_whitener(noise_cov, info, picks)
@@ -105,9 +76,12 @@ def _apply_lcmv(data, info, tmin, forward, noise_cov, data_cov, reg,
# Apply SSPs + whitener to data covariance
data_cov = pick_channels_cov(data_cov, include=ch_names)
Cm = data_cov['data']
- Cm = np.dot(proj, np.dot(Cm, proj.T))
+ if info['projs']:
+ Cm = np.dot(proj, np.dot(Cm, proj.T))
Cm = np.dot(whitener, np.dot(Cm, whitener.T))
+ # Calculating regularized inverse, equivalent to an inverse operation after
+ # the following regularization:
# Cm += reg * np.trace(Cm) / len(Cm) * np.eye(len(Cm))
Cm_inv = linalg.pinv(Cm, reg)
@@ -151,12 +125,18 @@ def _apply_lcmv(data, info, tmin, forward, noise_cov, data_cov, reg,
if pick_ori == 'max-power':
W = W[0::3]
- # noise normalization
+ # Preparing noise normalization
noise_norm = np.sum(W ** 2, axis=1)
if is_free_ori:
noise_norm = np.sum(np.reshape(noise_norm, (-1, 3)), axis=1)
noise_norm = np.sqrt(noise_norm)
+ # Pick source orientation normal to cortical surface
+ if pick_ori == 'normal':
+ W = W[2::3]
+ is_free_ori = False
+
+ # Applying noise normalization
if not is_free_ori:
W /= noise_norm[:, None]
@@ -175,7 +155,8 @@ def _apply_lcmv(data, info, tmin, forward, noise_cov, data_cov, reg,
logger.info("Processing epoch : %d" % (i + 1))
# SSP and whitening
- M = np.dot(proj, M)
+ if info['projs']:
+ M = np.dot(proj, M)
M = np.dot(whitener, M)
# project to source space using beamformer weights
@@ -195,12 +176,65 @@ def _apply_lcmv(data, info, tmin, forward, noise_cov, data_cov, reg,
sol = np.abs(sol)
tstep = 1.0 / info['sfreq']
- yield SourceEstimate(sol, vertices=vertno, tmin=tmin, tstep=tstep,
- subject=subject)
+ yield _make_stc(sol, vertices=vertno, tmin=tmin, tstep=tstep,
+ subject=subject)
logger.info('[done]')
+def _prepare_beamformer_input(info, forward, label, picks, pick_ori):
+ """Input preparation common for all beamformer functions.
+
+ Check input values, prepare channel list and gain matrix. For documentation
+ of parameters, please refer to _apply_lcmv.
+ """
+
+ is_free_ori = forward['source_ori'] == FIFF.FIFFV_MNE_FREE_ORI
+
+ if pick_ori in ['normal', 'max-power'] and not is_free_ori:
+ raise ValueError('Normal or max-power orientation can only be picked '
+ 'when a forward operator with free orientation is '
+ 'used.')
+ if pick_ori == 'normal' and not forward['surf_ori']:
+ raise ValueError('Normal orientation can only be picked when a '
+ 'forward operator oriented in surface coordinates is '
+ 'used.')
+ if pick_ori == 'normal' and not forward['src'][0]['type'] == 'surf':
+ raise ValueError('Normal orientation can only be picked when a '
+ 'forward operator with a surface-based source space '
+ 'is used.')
+
+ if picks is None:
+ picks = pick_types(info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
+
+ ch_names = [info['ch_names'][k] for k in picks]
+
+ # Restrict forward solution to selected channels
+ forward = pick_channels_forward(forward, include=ch_names)
+
+ # Get gain matrix (forward operator)
+ if label is not None:
+ vertno, src_sel = label_src_vertno_sel(label, forward['src'])
+
+ if is_free_ori:
+ src_sel = 3 * src_sel
+ src_sel = np.c_[src_sel, src_sel + 1, src_sel + 2]
+ src_sel = src_sel.ravel()
+
+ G = forward['sol']['data'][:, src_sel]
+ else:
+ vertno = _get_vertno(forward['src'])
+ G = forward['sol']['data']
+
+ # Apply SSPs
+ proj, ncomp, _ = make_projector(info['projs'], ch_names)
+ if info['projs']:
+ G = np.dot(proj, G)
+
+ return is_free_ori, picks, ch_names, proj, vertno, G
+
+
@verbose
def lcmv(evoked, forward, noise_cov, data_cov, reg=0.01, label=None,
pick_ori=None, verbose=None):
@@ -209,7 +243,7 @@ def lcmv(evoked, forward, noise_cov, data_cov, reg=0.01, label=None,
Compute Linearly Constrained Minimum Variance (LCMV) beamformer
on evoked data.
- NOTE : This implementation has not been heavilly tested so please
+ NOTE : This implementation has not been heavily tested so please
report any issue or suggestions.
Parameters
@@ -226,15 +260,16 @@ def lcmv(evoked, forward, noise_cov, data_cov, reg=0.01, label=None,
The regularization for the whitened data covariance.
label : Label
Restricts the LCMV solution to a given label
- pick_ori : None | 'max-power'
- If 'max-power', the source orientation that maximizes output source
- power is chosen.
+ pick_ori : None | 'normal' | 'max-power'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept. If 'max-power', the source
+ orientation that maximizes output source power is chosen.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
Returns
-------
- stc : SourceEstimate
+ stc : SourceEstimate | VolSourceEstimate
Source time courses
Notes
@@ -268,7 +303,7 @@ def lcmv_epochs(epochs, forward, noise_cov, data_cov, reg=0.01, label=None,
Compute Linearly Constrained Minimum Variance (LCMV) beamformer
on single trial data.
- NOTE : This implementation has not been heavilly tested so please
+ NOTE : This implementation has not been heavily tested so please
report any issue or suggestions.
Parameters
@@ -285,9 +320,10 @@ def lcmv_epochs(epochs, forward, noise_cov, data_cov, reg=0.01, label=None,
The regularization for the whitened data covariance.
label : Label
Restricts the LCMV solution to a given label.
- pick_ori : None | 'max-power'
- If 'max-power', the source orientation that maximizes output source
- power is chosen.
+ pick_ori : None | 'normal' | 'max-power'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept. If 'max-power', the source
+ orientation that maximizes output source power is chosen.
return_generator : bool
Return a generator object instead of a list. This allows iterating
over the stcs without having to keep them all in memory.
@@ -296,7 +332,7 @@ def lcmv_epochs(epochs, forward, noise_cov, data_cov, reg=0.01, label=None,
Returns
-------
- stc: list | generator of SourceEstimate
+ stc: list | generator of (SourceEstimate | VolSourceEstimate)
The source estimates for all epochs
Notes
@@ -316,7 +352,8 @@ def lcmv_epochs(epochs, forward, noise_cov, data_cov, reg=0.01, label=None,
tmin = epochs.times[0]
# use only the good data channels
- picks = pick_types(info, meg=True, eeg=True, exclude='bads')
+ picks = pick_types(info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
data = epochs.get_data()[:, picks, :]
stcs = _apply_lcmv(data, info, tmin, forward, noise_cov, data_cov, reg,
@@ -336,7 +373,7 @@ def lcmv_raw(raw, forward, noise_cov, data_cov, reg=0.01, label=None,
Compute Linearly Constrained Minimum Variance (LCMV) beamformer
on raw data.
- NOTE : This implementation has not been heavilly tested so please
+ NOTE : This implementation has not been heavily tested so please
report any issue or suggestions.
Parameters
@@ -360,15 +397,16 @@ def lcmv_raw(raw, forward, noise_cov, data_cov, reg=0.01, label=None,
picks : array of int
Channel indices in raw to use for beamforming (if None all channels
are used except bad channels).
- pick_ori : None | 'max-power'
- If 'max-power', the source orientation that maximizes output source
- power is chosen.
+ pick_ori : None | 'normal' | 'max-power'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept. If 'max-power', the source
+ orientation that maximizes output source power is chosen.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
Returns
-------
- stc : SourceEstimate
+ stc : SourceEstimate | VolSourceEstimate
Source time courses
Notes
@@ -387,7 +425,8 @@ def lcmv_raw(raw, forward, noise_cov, data_cov, reg=0.01, label=None,
info = raw.info
if picks is None:
- picks = pick_types(info, meg=True, eeg=True, exclude='bads')
+ picks = pick_types(info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
data, times = raw[picks, start:stop]
tmin = times[0]
@@ -396,3 +435,280 @@ def lcmv_raw(raw, forward, noise_cov, data_cov, reg=0.01, label=None,
label, picks, pick_ori).next()
return stc
+
+
+ at verbose
+def _lcmv_source_power(info, forward, noise_cov, data_cov, reg=0.01,
+ label=None, picks=None, pick_ori=None, verbose=None):
+ """Linearly Constrained Minimum Variance (LCMV) beamformer.
+
+ Calculate source power in a time window based on the provided data
+ covariance. Noise covariance is used to whiten the data covariance making
+ the output equivalent to the neural activity index as defined by
+ Van Veen et al. 1997.
+
+ NOTE : This implementation has not been heavily tested so please
+ report any issues or suggestions.
+
+ Parameters
+ ----------
+ info : dict
+ Measurement info, e.g. epochs.info.
+ forward : dict
+ Forward operator.
+ noise_cov : Covariance
+ The noise covariance.
+ data_cov : Covariance
+ The data covariance.
+ reg : float
+ The regularization for the whitened data covariance.
+ label : Label | None
+ Restricts the solution to a given label.
+ picks : array of int | None
+ Indices (in info) of data channels. If None, MEG and EEG data channels
+ (without bad channels) will be used.
+ pick_ori : None | 'normal'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ stc : SourceEstimate
+ Source power with a single time point representing the entire time
+ window for which data covariance was calculated.
+
+ Notes
+ -----
+ The original reference is:
+ Van Veen et al. Localization of brain electrical activity via linearly
+ constrained minimum variance spatial filtering.
+ Biomedical Engineering (1997) vol. 44 (9) pp. 867--880
+ """
+
+ is_free_ori, picks, ch_names, proj, vertno, G =\
+ _prepare_beamformer_input(info, forward, label, picks, pick_ori)
+
+ # Handle whitening
+ whitener, _ = compute_whitener(noise_cov, info, picks)
+
+ # whiten the leadfield
+ G = np.dot(whitener, G)
+
+ # Apply SSPs + whitener to data covariance
+ data_cov = pick_channels_cov(data_cov, include=ch_names)
+ Cm = data_cov['data']
+ if info['projs']:
+ Cm = np.dot(proj, np.dot(Cm, proj.T))
+ Cm = np.dot(whitener, np.dot(Cm, whitener.T))
+
+ # Calculating regularized inverse, equivalent to an inverse operation after
+ # the following regularization:
+ # Cm += reg * np.trace(Cm) / len(Cm) * np.eye(len(Cm))
+ Cm_inv = linalg.pinv(Cm, reg)
+
+ # Compute spatial filters
+ W = np.dot(G.T, Cm_inv)
+ n_orient = 3 if is_free_ori else 1
+ n_sources = G.shape[1] // n_orient
+ source_power = np.zeros((n_sources, 1))
+ for k in range(n_sources):
+ Wk = W[n_orient * k: n_orient * k + n_orient]
+ Gk = G[:, n_orient * k: n_orient * k + n_orient]
+ Ck = np.dot(Wk, Gk)
+
+ if is_free_ori:
+ # Free source orientation
+ Wk[:] = np.dot(linalg.pinv(Ck, 0.1), Wk)
+ else:
+ # Fixed source orientation
+ Wk /= Ck
+
+ # Noise normalization
+ noise_norm = np.dot(Wk, Wk.T)
+ noise_norm = noise_norm.trace()
+
+ # Calculating source power
+ sp_temp = np.dot(np.dot(Wk, Cm), Wk.T)
+ sp_temp /= max(noise_norm, 1e-40) # Avoid division by 0
+
+ if pick_ori == 'normal':
+ source_power[k, 0] = sp_temp[2, 2]
+ else:
+ source_power[k, 0] = sp_temp.trace()
+
+ logger.info('[done]')
+
+ subject = _subject_from_forward(forward)
+ return SourceEstimate(source_power, vertices=vertno, tmin=1,
+ tstep=1, subject=subject)
+
+
+ at verbose
+def tf_lcmv(epochs, forward, noise_covs, tmin, tmax, tstep, win_lengths,
+ freq_bins, subtract_evoked=False, reg=0.01, label=None,
+ pick_ori=None, n_jobs=1, verbose=None):
+ """5D time-frequency beamforming based on LCMV.
+
+ Calculate source power in time-frequency windows using a spatial filter
+ based on the Linearly Constrained Minimum Variance (LCMV) beamforming
+ approach. Band-pass filtered epochs are divided into time windows from
+ which covariance is computed and used to create a beamformer spatial
+ filter.
+
+ NOTE : This implementation has not been heavily tested so please
+ report any issues or suggestions.
+
+ Parameters
+ ----------
+ epochs : Epochs
+ Single trial epochs.
+ forward : dict
+ Forward operator.
+ noise_covs : list of instances of Covariance
+ Noise covariance for each frequency bin.
+ tmin : float
+ Minimum time instant to consider.
+ tmax : float
+ Maximum time instant to consider.
+ tstep : float
+ Spacing between consecutive time windows, should be smaller than or
+ equal to the shortest time window length.
+ win_lengths : list of float
+ Time window lengths in seconds. One time window length should be
+ provided for each frequency bin.
+ freq_bins : list of tuples of float
+ Start and end point of frequency bins of interest.
+ subtract_evoked : bool
+ If True, subtract the averaged evoked response prior to computing the
+ tf source grid.
+ reg : float
+ The regularization for the whitened data covariance.
+ label : Label | None
+ Restricts the solution to a given label.
+ pick_ori : None | 'normal'
+ If 'normal', rather than pooling the orientations by taking the norm,
+ only the radial component is kept.
+ n_jobs : int | str
+ Number of jobs to run in parallel. Can be 'cuda' if scikits.cuda
+ is installed properly and CUDA is initialized.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ stcs : list of SourceEstimate
+ Source power at each time window. One SourceEstimate object is returned
+ for each frequency bin.
+
+ Notes
+ -----
+ The original reference is:
+ Dalal et al. Five-dimensional neuroimaging: Localization of the
+ time-frequency dynamics of cortical activity.
+ NeuroImage (2008) vol. 40 (4) pp. 1686-1700
+ """
+
+ if pick_ori not in [None, 'normal']:
+ raise ValueError('Unrecognized orientation option in pick_ori, '
+ 'available choices are None and normal')
+ if len(noise_covs) != len(freq_bins):
+ raise ValueError('One noise covariance object expected per frequency '
+ 'bin')
+ if len(win_lengths) != len(freq_bins):
+ raise ValueError('One time window length expected per frequency bin')
+ if any(win_length < tstep for win_length in win_lengths):
+ raise ValueError('Time step should not be larger than any of the '
+ 'window lengths')
+
+ # Extract raw object from the epochs object
+ raw = epochs.raw
+ if raw is None:
+ raise ValueError('The provided epochs object does not contain the '
+ 'underlying raw object. Please use preload=False '
+ 'when constructing the epochs object')
+ # Use picks from epochs for picking channels in the raw object
+ raw_picks = [raw.ch_names.index(c) for c in epochs.ch_names]
+
+ # Make sure epochs.events contains only good events:
+ epochs.drop_bad_epochs()
+
+ # Multiplying by 1e3 to avoid numerical issues, e.g. 0.3 // 0.05 == 5
+ n_time_steps = int(((tmax - tmin) * 1e3) // (tstep * 1e3))
+
+ sol_final = []
+ for (l_freq, h_freq), win_length, noise_cov in \
+ zip(freq_bins, win_lengths, noise_covs):
+ n_overlap = int((win_length * 1e3) // (tstep * 1e3))
+
+ raw_band = raw.copy()
+ raw_band.filter(l_freq, h_freq, picks=raw_picks, method='iir',
+ n_jobs=n_jobs)
+ epochs_band = Epochs(raw_band, epochs.events, epochs.event_id,
+ tmin=epochs.tmin, tmax=epochs.tmax,
+ picks=raw_picks, keep_comp=epochs.keep_comp,
+ dest_comp=epochs.dest_comp,
+ proj=epochs.proj, preload=True)
+ del raw_band
+
+ if subtract_evoked:
+ epochs_band.subtract_evoked()
+
+ sol_single = []
+ sol_overlap = []
+ for i_time in range(n_time_steps):
+ win_tmin = tmin + i_time * tstep
+ win_tmax = win_tmin + win_length
+
+ # If in the last step the last time point was not covered in
+ # previous steps and will not be covered now, a solution needs to
+ # be calculated for an additional time window
+ if i_time == n_time_steps - 1 and win_tmax - tstep < tmax and\
+ win_tmax >= tmax + (epochs.times[-1] - epochs.times[-2]):
+ warnings.warn('Adding a time window to cover last time points')
+ win_tmin = tmax - win_length
+ win_tmax = tmax
+
+ if win_tmax < tmax + (epochs.times[-1] - epochs.times[-2]):
+ logger.info('Computing time-frequency LCMV beamformer for '
+ 'time window %d to %d ms, in frequency range '
+ '%d to %d Hz' % (win_tmin * 1e3, win_tmax * 1e3,
+ l_freq, h_freq))
+
+ # Calculating data covariance from filtered epochs in current
+ # time window
+ data_cov = compute_covariance(epochs_band, tmin=win_tmin,
+ tmax=win_tmax)
+
+ stc = _lcmv_source_power(epochs_band.info, forward, noise_cov,
+ data_cov, reg=reg, label=label,
+ pick_ori=pick_ori, verbose=verbose)
+ sol_single.append(stc.data[:, 0])
+
+ # Average over all time windows that contain the current time
+ # point, which is the current time window along with
+ # n_overlap - 1 previous ones
+ if i_time - n_overlap < 0:
+ curr_sol = np.mean(sol_single[0:i_time + 1], axis=0)
+ else:
+ curr_sol = np.mean(sol_single[i_time - n_overlap + 1:
+ i_time + 1], axis=0)
+
+ # The final result for the current time point in the current
+ # frequency bin
+ sol_overlap.append(curr_sol)
+
+ # Gathering solutions for all time points for current frequency bin
+ sol_final.append(sol_overlap)
+
+ sol_final = np.array(sol_final)
+
+ # Creating stc objects containing all time points for each frequency bin
+ stcs = []
+ for i_freq, _ in enumerate(freq_bins):
+ stc = SourceEstimate(sol_final[i_freq, :, :].T, vertices=stc.vertno,
+ tmin=tmin, tstep=tstep, subject=stc.subject)
+ stcs.append(stc)
+
+ return stcs
diff --git a/mne/beamformer/tests/test_dics.py b/mne/beamformer/tests/test_dics.py
new file mode 100644
index 0000000..b76c03e
--- /dev/null
+++ b/mne/beamformer/tests/test_dics.py
@@ -0,0 +1,296 @@
+import warnings
+import os.path as op
+import copy as cp
+
+from nose.tools import assert_true, assert_raises
+import numpy as np
+from numpy.testing import assert_array_equal, assert_array_almost_equal
+
+import mne
+from mne.datasets import sample
+from mne.beamformer import dics, dics_epochs, dics_source_power, tf_dics
+from mne.time_frequency import compute_epochs_csd
+
+# Note that this is the first test file, this will apply to all subsequent
+# tests in a full nosetest:
+warnings.simplefilter("always") # ensure we can verify expected warnings
+
+data_path = sample.data_path(download=False)
+fname_data = op.join(data_path, 'MEG', 'sample', 'sample_audvis-ave.fif')
+fname_raw = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw.fif')
+fname_fwd = op.join(data_path, 'MEG', 'sample',
+ 'sample_audvis-meg-oct-6-fwd.fif')
+fname_fwd_vol = op.join(data_path, 'MEG', 'sample',
+ 'sample_audvis-meg-vol-7-fwd.fif')
+fname_event = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw-eve.fif')
+label = 'Aud-lh'
+fname_label = op.join(data_path, 'MEG', 'sample', 'labels', '%s.label' % label)
+
+
+def _get_data(tmin=-0.11, tmax=0.15, read_all_forward=True, compute_csds=True):
+ """Read in data used in tests
+ """
+ label = mne.read_label(fname_label)
+ events = mne.read_events(fname_event)[:10]
+ raw = mne.fiff.Raw(fname_raw, preload=False)
+ forward = mne.read_forward_solution(fname_fwd)
+ if read_all_forward:
+ forward_surf_ori = mne.read_forward_solution(fname_fwd, surf_ori=True)
+ forward_fixed = mne.read_forward_solution(fname_fwd, force_fixed=True,
+ surf_ori=True)
+ forward_vol = mne.read_forward_solution(fname_fwd_vol, surf_ori=True)
+ else:
+ forward_surf_ori = None
+ forward_fixed = None
+ forward_vol = None
+
+ event_id, tmin, tmax = 1, tmin, tmax
+
+ # Setup for reading the raw data
+ raw.info['bads'] = ['MEG 2443', 'EEG 053'] # 2 bads channels
+
+ # Set up pick list: MEG - bad channels
+ left_temporal_channels = mne.read_selection('Left-temporal')
+ picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False,
+ stim=True, eog=True, exclude='bads',
+ selection=left_temporal_channels)
+
+ # Read epochs
+ epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ picks=picks, baseline=(None, 0), preload=True,
+ reject=dict(grad=4000e-13, mag=4e-12, eog=150e-6))
+ epochs.resample(200, npad=0, n_jobs=2)
+ evoked = epochs.average()
+
+ # Computing the data and noise cross-spectral density matrices
+ if compute_csds:
+ data_csd = compute_epochs_csd(epochs, mode='multitaper', tmin=0.04,
+ tmax=None, fmin=8, fmax=12,
+ mt_bandwidth=72.72)
+ noise_csd = compute_epochs_csd(epochs, mode='multitaper', tmin=None,
+ tmax=0.0, fmin=8, fmax=12,
+ mt_bandwidth=72.72)
+ else:
+ data_csd, noise_csd = None, None
+
+ return raw, epochs, evoked, data_csd, noise_csd, label, forward,\
+ forward_surf_ori, forward_fixed, forward_vol
+
+
+ at sample.requires_sample_data
+def test_dics():
+ """Test DICS with evoked data and single trials
+ """
+ raw, epochs, evoked, data_csd, noise_csd, label, forward,\
+ forward_surf_ori, forward_fixed, forward_vol = _get_data()
+
+ stc = dics(evoked, forward, noise_csd=noise_csd, data_csd=data_csd,
+ label=label)
+
+ stc_pow = np.sum(stc.data, axis=1)
+ idx = np.argmax(stc_pow)
+ max_stc = stc.data[idx]
+ tmax = stc.times[np.argmax(max_stc)]
+
+ assert_true(0.09 < tmax < 0.11)
+ assert_true(10 < np.max(max_stc) < 11)
+
+ # Test picking normal orientation
+ stc_normal = dics(evoked, forward_surf_ori, noise_csd, data_csd,
+ pick_ori="normal", label=label)
+
+ # The amplitude of normal orientation results should always be smaller than
+ # free orientation results
+ assert_true((np.abs(stc_normal.data) <= stc.data).all())
+
+ # Test if fixed forward operator is detected when picking normal
+ # orientation
+ assert_raises(ValueError, dics_epochs, epochs, forward_fixed, noise_csd,
+ data_csd, pick_ori="normal")
+
+ # Test if non-surface oriented forward operator is detected when picking
+ # normal orientation
+ assert_raises(ValueError, dics_epochs, epochs, forward, noise_csd,
+ data_csd, pick_ori="normal")
+
+ # Test if volume forward operator is detected when picking normal
+ # orientation
+ assert_raises(ValueError, dics_epochs, epochs, forward_vol, noise_csd,
+ data_csd, pick_ori="normal")
+
+ # Now test single trial using fixed orientation forward solution
+ # so we can compare it to the evoked solution
+ stcs = dics_epochs(epochs, forward_fixed, noise_csd, data_csd, reg=0.01,
+ label=label)
+
+ # Testing returning of generator
+ stcs_ = dics_epochs(epochs, forward_fixed, noise_csd, data_csd, reg=0.01,
+ return_generator=True, label=label)
+ assert_array_equal(stcs[0].data, stcs_.next().data)
+
+ # Test whether correct number of trials was returned
+ epochs.drop_bad_epochs()
+ assert_true(len(epochs.events) == len(stcs))
+
+ # Average the single trial estimates
+ stc_avg = np.zeros_like(stcs[0].data)
+ for this_stc in stcs:
+ stc_avg += this_stc.data
+ stc_avg /= len(stcs)
+
+ idx = np.argmax(np.max(stc_avg, axis=1))
+ max_stc = stc_avg[idx]
+ tmax = stc.times[np.argmax(max_stc)]
+
+ assert_true(0.045 < tmax < 0.055) # odd due to limited number of epochs
+ assert_true(17.5 < np.max(max_stc) < 18.5)
+
+
+ at sample.requires_sample_data
+def test_dics_source_power():
+ """Test DICS source power computation
+ """
+ raw, epochs, evoked, data_csd, noise_csd, label, forward,\
+ forward_surf_ori, forward_fixed, forward_vol = _get_data()
+
+ stc_source_power = dics_source_power(epochs.info, forward, noise_csd,
+ data_csd, label=label)
+
+ max_source_idx = np.argmax(stc_source_power.data)
+ max_source_power = np.max(stc_source_power.data)
+
+ # TODO: Maybe these could be more directly compared to dics() results?
+ assert_true(max_source_idx == 18)
+ assert_true(1.05 < max_source_power < 1.15)
+
+ # Test picking normal orientation and using a list of CSD matrices
+ stc_normal = dics_source_power(epochs.info, forward_surf_ori,
+ [noise_csd] * 2, [data_csd] * 2,
+ pick_ori="normal", label=label)
+
+ assert_true(stc_normal.data.shape == (stc_source_power.data.shape[0], 2))
+
+ # The normal orientation results should always be smaller than free
+ # orientation results
+ assert_true((np.abs(stc_normal.data[:, 0]) <=
+ stc_source_power.data[:, 0]).all())
+
+ # Test if fixed forward operator is detected when picking normal
+ # orientation
+ assert_raises(ValueError, dics_source_power, raw.info, forward_fixed,
+ noise_csd, data_csd, pick_ori="normal")
+
+ # Test if non-surface oriented forward operator is detected when picking
+ # normal orientation
+ assert_raises(ValueError, dics_source_power, raw.info, forward, noise_csd,
+ data_csd, pick_ori="normal")
+
+ # Test if volume forward operator is detected when picking normal
+ # orientation
+ assert_raises(ValueError, dics_source_power, epochs.info, forward_vol,
+ noise_csd, data_csd, pick_ori="normal")
+
+ # Test detection of different number of CSD matrices provided
+ assert_raises(ValueError, dics_source_power, epochs.info, forward,
+ [noise_csd] * 2, [data_csd] * 3)
+
+ # Test detection of different frequencies in noise and data CSD objects
+ noise_csd.frequencies = [1, 2]
+ data_csd.frequencies = [1, 2, 3]
+ assert_raises(ValueError, dics_source_power, epochs.info, forward,
+ noise_csd, data_csd)
+
+ # Test detection of uneven frequency spacing
+ data_csds = [cp.deepcopy(data_csd) for i in range(3)]
+ frequencies = [1, 3, 4]
+ for freq, data_csd in zip(frequencies, data_csds):
+ data_csd.frequencies = [freq]
+ noise_csds = data_csds
+ with warnings.catch_warnings(True) as w:
+ dics_source_power(epochs.info, forward, noise_csds, data_csds)
+ assert len(w) == 1
+
+
+ at sample.requires_sample_data
+def test_tf_dics():
+ """Test TF beamforming based on DICS
+ """
+ tmin, tmax, tstep = -0.2, 0.2, 0.1
+ raw, epochs, _, _, _, label, forward, _, _, _ =\
+ _get_data(tmin, tmax, read_all_forward=False, compute_csds=False)
+
+ freq_bins = [(4, 20), (30, 55)]
+ win_lengths = [0.2, 0.2]
+ reg = 0.001
+
+ noise_csds = []
+ for freq_bin, win_length in zip(freq_bins, win_lengths):
+ noise_csd = compute_epochs_csd(epochs, mode='fourier',
+ fmin=freq_bin[0], fmax=freq_bin[1],
+ fsum=True, tmin=tmin,
+ tmax=tmin + win_length)
+ noise_csds.append(noise_csd)
+
+ stcs = tf_dics(epochs, forward, noise_csds, tmin, tmax, tstep, win_lengths,
+ freq_bins, reg=reg, label=label)
+
+ assert_true(len(stcs) == len(freq_bins))
+ print stcs[0].shape
+ assert_true(stcs[0].shape[1] == 4)
+
+ # Manually calculating source power in several time windows to compare
+ # results and test overlapping
+ source_power = []
+ time_windows = [(-0.1, 0.1), (0.0, 0.2)]
+ for time_window in time_windows:
+ data_csd = compute_epochs_csd(epochs, mode='fourier',
+ fmin=freq_bins[0][0],
+ fmax=freq_bins[0][1], fsum=True,
+ tmin=time_window[0], tmax=time_window[1])
+ noise_csd = compute_epochs_csd(epochs, mode='fourier',
+ fmin=freq_bins[0][0],
+ fmax=freq_bins[0][1], fsum=True,
+ tmin=-0.2, tmax=0.0)
+ data_csd.data /= data_csd.n_fft
+ noise_csd.data /= noise_csd.n_fft
+ stc_source_power = dics_source_power(epochs.info, forward, noise_csd,
+ data_csd, reg=reg, label=label)
+ source_power.append(stc_source_power.data)
+
+ # Averaging all time windows that overlap the time period 0 to 100 ms
+ source_power = np.mean(source_power, axis=0)
+
+ # Selecting the first frequency bin in tf_dics results
+ stc = stcs[0]
+
+ # Comparing tf_dics results with dics_source_power results
+ assert_array_almost_equal(stc.data[:, 2], source_power[:, 0])
+
+ # Test if using unsupported max-power orientation is detected
+ assert_raises(ValueError, tf_dics, epochs, forward, noise_csds, tmin, tmax,
+ tstep, win_lengths, freq_bins=freq_bins,
+ pick_ori='max-power')
+
+ # Test if incorrect number of noise CSDs is detected
+ assert_raises(ValueError, tf_dics, epochs, forward, [noise_csds[0]], tmin,
+ tmax, tstep, win_lengths, freq_bins=freq_bins)
+
+ # Test if freq_bins and win_lengths incompatibility is detected
+ assert_raises(ValueError, tf_dics, epochs, forward, noise_csds, tmin, tmax,
+ tstep, win_lengths=[0, 1, 2], freq_bins=freq_bins)
+
+ # Test if time step exceeding window lengths is detected
+ assert_raises(ValueError, tf_dics, epochs, forward, noise_csds, tmin, tmax,
+ tstep=0.15, win_lengths=[0.2, 0.1], freq_bins=freq_bins)
+
+ # Test if incorrect number of mt_bandwidths is detected
+ assert_raises(ValueError, tf_dics, epochs, forward, noise_csds, tmin, tmax,
+ tstep, win_lengths, freq_bins, mode='multitaper',
+ mt_bandwidths=[20])
+
+ # Pass only one epoch to test if subtracting evoked responses yields zeros
+ stcs = tf_dics(epochs[0], forward, noise_csds, tmin, tmax, tstep,
+ win_lengths, freq_bins, subtract_evoked=True, reg=reg,
+ label=label)
+
+ assert_array_almost_equal(stcs[0].data, np.zeros_like(stcs[0].data))
diff --git a/mne/beamformer/tests/test_lcmv.py b/mne/beamformer/tests/test_lcmv.py
index 56c41ec..99825c5 100644
--- a/mne/beamformer/tests/test_lcmv.py
+++ b/mne/beamformer/tests/test_lcmv.py
@@ -3,88 +3,160 @@ import os.path as op
from nose.tools import assert_true, assert_raises
import numpy as np
from numpy.testing import assert_array_almost_equal, assert_array_equal
+import warnings
import mne
+from mne import compute_covariance
from mne.datasets import sample
-from mne.beamformer import lcmv, lcmv_epochs, lcmv_raw
+from mne.beamformer import lcmv, lcmv_epochs, lcmv_raw, tf_lcmv
+from mne.beamformer._lcmv import _lcmv_source_power
+from mne.source_estimate import SourceEstimate, VolSourceEstimate
-data_path = sample.data_path()
-fname_data = op.join(data_path, 'MEG', 'sample',
- 'sample_audvis-ave.fif')
-fname_raw = op.join(data_path, 'MEG', 'sample',
- 'sample_audvis_raw.fif')
-fname_cov = op.join(data_path, 'MEG', 'sample',
- 'sample_audvis-cov.fif')
+data_path = sample.data_path(download=False)
+fname_data = op.join(data_path, 'MEG', 'sample', 'sample_audvis-ave.fif')
+fname_raw = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw.fif')
+fname_cov = op.join(data_path, 'MEG', 'sample', 'sample_audvis-cov.fif')
fname_fwd = op.join(data_path, 'MEG', 'sample',
- 'sample_audvis-meg-oct-6-fwd.fif')
+ 'sample_audvis-meg-oct-6-fwd.fif')
fname_fwd_vol = op.join(data_path, 'MEG', 'sample',
- 'sample_audvis-meg-vol-7-fwd.fif')
-fname_event = op.join(data_path, 'MEG', 'sample',
- 'sample_audvis_raw-eve.fif')
+ 'sample_audvis-meg-vol-7-fwd.fif')
+fname_event = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw-eve.fif')
label = 'Aud-lh'
fname_label = op.join(data_path, 'MEG', 'sample', 'labels', '%s.label' % label)
-label = mne.read_label(fname_label)
-noise_cov = mne.read_cov(fname_cov)
-# preloading raw here increases mem requirements by 400 mb for all nosetests
-# that include this file's parent directory :(
-raw = mne.fiff.Raw(fname_raw, preload=False)
-forward = mne.read_forward_solution(fname_fwd)
-forward_surf_ori = mne.read_forward_solution(fname_fwd, surf_ori=True)
-forward_fixed = mne.read_forward_solution(fname_fwd, force_fixed=True,
- surf_ori=True)
-forward_vol = mne.read_forward_solution(fname_fwd_vol, surf_ori=True)
-events = mne.read_events(fname_event)
+warnings.simplefilter('always') # enable b/c these tests throw warnings
-def test_lcmv():
- """Test LCMV with evoked data and single trials
+def _get_data(tmin=-0.1, tmax=0.15, all_forward=True, epochs=True,
+ epochs_preload=True, data_cov=True):
+ """Read in data used in tests
"""
- event_id, tmin, tmax = 1, -0.1, 0.15
+ label = mne.read_label(fname_label)
+ events = mne.read_events(fname_event)
+ raw = mne.fiff.Raw(fname_raw, preload=True)
+ forward = mne.read_forward_solution(fname_fwd)
+ if all_forward:
+ forward_surf_ori = mne.read_forward_solution(fname_fwd, surf_ori=True)
+ forward_fixed = mne.read_forward_solution(fname_fwd, force_fixed=True,
+ surf_ori=True)
+ forward_vol = mne.read_forward_solution(fname_fwd_vol, surf_ori=True)
+ else:
+ forward_surf_ori = None
+ forward_fixed = None
+ forward_vol = None
+
+ event_id, tmin, tmax = 1, tmin, tmax
# Setup for reading the raw data
raw.info['bads'] = ['MEG 2443', 'EEG 053'] # 2 bads channels
- # Set up pick list: EEG + MEG - bad channels (modify to your needs)
- left_temporal_channels = mne.read_selection('Left-temporal')
- picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False,
- stim=True, eog=True, exclude='bads',
- selection=left_temporal_channels)
-
- # Read epochs
- epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
- picks=picks, baseline=(None, 0), preload=True,
- reject=dict(grad=4000e-13, mag=4e-12, eog=150e-6))
- epochs.resample(200, npad=0, n_jobs=2)
- evoked = epochs.average()
+ if epochs:
+ # Set up pick list: MEG - bad channels
+ left_temporal_channels = mne.read_selection('Left-temporal')
+ picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False,
+ stim=True, eog=True, ref_meg=False,
+ exclude='bads',
+ selection=left_temporal_channels)
+
+ # Read epochs
+ epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ picks=picks, baseline=(None, 0),
+ preload=epochs_preload,
+ reject=dict(grad=4000e-13, mag=4e-12, eog=150e-6))
+ if epochs_preload:
+ epochs.resample(200, npad=0, n_jobs=2)
+ evoked = epochs.average()
+ info = evoked.info
+ else:
+ epochs = None
+ evoked = None
+ info = raw.info
noise_cov = mne.read_cov(fname_cov)
- noise_cov = mne.cov.regularize(noise_cov, evoked.info,
+ noise_cov = mne.cov.regularize(noise_cov, info,
mag=0.05, grad=0.05, eeg=0.1, proj=True)
+ if data_cov:
+ data_cov = mne.compute_covariance(epochs, tmin=0.04, tmax=0.15)
+ else:
+ data_cov = None
- data_cov = mne.compute_covariance(epochs, tmin=0.04, tmax=0.15)
- stc = lcmv(evoked, forward, noise_cov, data_cov, reg=0.01)
-
- stc_pow = np.sum(stc.data, axis=1)
- idx = np.argmax(stc_pow)
- max_stc = stc.data[idx]
- tmax = stc.times[np.argmax(max_stc)]
-
- assert_true(0.09 < tmax < 0.1)
- assert_true(2. < np.max(max_stc) < 3.)
+ return raw, epochs, evoked, data_cov, noise_cov, label, forward,\
+ forward_surf_ori, forward_fixed, forward_vol
- # Test picking source orientation maximizing output source power
- stc_max_power = lcmv(evoked, forward, noise_cov, data_cov, reg=0.01,
- pick_ori="max-power")
- assert_true((np.abs(stc_max_power.data) <= stc.data + 1).all())
-
- # Test if fixed forward operator is detected when picking
+ at sample.requires_sample_data
+def test_lcmv():
+ """Test LCMV with evoked data and single trials
+ """
+ raw, epochs, evoked, data_cov, noise_cov, label, forward,\
+ forward_surf_ori, forward_fixed, forward_vol = _get_data()
+
+ for fwd in [forward, forward_vol]:
+ stc = lcmv(evoked, fwd, noise_cov, data_cov, reg=0.01)
+
+ if fwd is forward:
+ assert_true(isinstance(stc, SourceEstimate))
+ else:
+ assert_true(isinstance(stc, VolSourceEstimate))
+
+ stc_pow = np.sum(stc.data, axis=1)
+ idx = np.argmax(stc_pow)
+ max_stc = stc.data[idx]
+ tmax = stc.times[np.argmax(max_stc)]
+
+ assert_true(0.09 < tmax < 0.105)
+ assert_true(1.9 < np.max(max_stc) < 3.)
+
+ if fwd is forward:
+ # Test picking normal orientation (surface source space only)
+ stc_normal = lcmv(evoked, forward_surf_ori, noise_cov, data_cov,
+ reg=0.01, pick_ori="normal")
+
+ stc_pow = np.sum(np.abs(stc_normal.data), axis=1)
+ idx = np.argmax(stc_pow)
+ max_stc = stc_normal.data[idx]
+ tmax = stc_normal.times[np.argmax(max_stc)]
+
+ assert_true(0.09 < tmax < 0.11)
+ assert_true(1. < np.max(max_stc) < 2.)
+
+ # The amplitude of normal orientation results should always be
+ # smaller than free orientation results
+ assert_true((np.abs(stc_normal.data) <= stc.data).all())
+
+ # Test picking source orientation maximizing output source power
+ stc_max_power = lcmv(evoked, fwd, noise_cov, data_cov, reg=0.01,
+ pick_ori="max-power")
+ stc_pow = np.sum(stc_max_power.data, axis=1)
+ idx = np.argmax(stc_pow)
+ max_stc = stc_max_power.data[idx]
+ tmax = stc.times[np.argmax(max_stc)]
+
+ assert_true(0.09 < tmax < 0.1)
+ assert_true(2. < np.max(max_stc) < 3.)
+
+ # Maximum output source power orientation results should be similar to
+ # free orientation results
+ assert_true((stc_max_power.data - stc.data < 0.5).all())
+
+ # Test if fixed forward operator is detected when picking normal or
# max-power orientation
assert_raises(ValueError, lcmv, evoked, forward_fixed, noise_cov, data_cov,
+ reg=0.01, pick_ori="normal")
+ assert_raises(ValueError, lcmv, evoked, forward_fixed, noise_cov, data_cov,
reg=0.01, pick_ori="max-power")
+ # Test if non-surface oriented forward operator is detected when picking
+ # normal orientation
+ assert_raises(ValueError, lcmv, evoked, forward, noise_cov, data_cov,
+ reg=0.01, pick_ori="normal")
+
+ # Test if volume forward operator is detected when picking normal
+ # orientation
+ assert_raises(ValueError, lcmv, evoked, forward_vol, noise_cov, data_cov,
+ reg=0.01, pick_ori="normal")
+
# Now test single trial using fixed orientation forward solution
# so we can compare it to the evoked solution
stcs = lcmv_epochs(epochs, forward_fixed, noise_cov, data_cov, reg=0.01)
@@ -96,7 +168,7 @@ def test_lcmv():
assert_true(len(epochs.events) == len(stcs))
# average the single trial estimates
- stc_avg = np.zeros_like(stc.data)
+ stc_avg = np.zeros_like(stcs[0].data)
for this_stc in stcs:
stc_avg += this_stc.data
stc_avg /= len(stcs)
@@ -113,26 +185,18 @@ def test_lcmv():
assert_array_almost_equal(stcs_label[0].data, stcs[0].in_label(label).data)
+ at sample.requires_sample_data
def test_lcmv_raw():
"""Test LCMV with raw data
"""
- tmin, tmax = 0, 20
- # Setup for reading the raw data
- raw.info['bads'] = ['MEG 2443', 'EEG 053'] # 2 bads channels
-
- # Set up pick list: EEG + MEG - bad channels (modify to your needs)
- left_temporal_channels = mne.read_selection('Left-temporal')
- picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False, stim=True,
- eog=True, exclude='bads',
- selection=left_temporal_channels)
-
- noise_cov = mne.read_cov(fname_cov)
- noise_cov = mne.cov.regularize(noise_cov, raw.info,
- mag=0.05, grad=0.05, eeg=0.1, proj=True)
+ raw, _, _, _, noise_cov, label, forward, _, _, _ =\
+ _get_data(all_forward=False, epochs=False, data_cov=False)
+ tmin, tmax = 0, 20
start, stop = raw.time_as_index([tmin, tmax])
# use only the left-temporal MEG channels for LCMV
+ left_temporal_channels = mne.read_selection('Left-temporal')
picks = mne.fiff.pick_types(raw.info, meg=True, exclude='bads',
selection=left_temporal_channels)
@@ -150,4 +214,157 @@ def test_lcmv_raw():
assert_true(len(stc.vertno[0]) == len(np.intersect1d(vertno[0],
label.vertices)))
assert_true(len(stc.vertno[1]) == 0)
- # TODO: test more things
+
+
+ at sample.requires_sample_data
+def test_lcmv_source_power():
+ """Test LCMV source power computation
+ """
+ raw, epochs, evoked, data_cov, noise_cov, label, forward,\
+ forward_surf_ori, forward_fixed, forward_vol = _get_data()
+
+ stc_source_power = _lcmv_source_power(epochs.info, forward, noise_cov,
+ data_cov, label=label)
+
+ max_source_idx = np.argmax(stc_source_power.data)
+ max_source_power = np.max(stc_source_power.data)
+
+ assert_true(max_source_idx == 24)
+ assert_true(2.2 < max_source_power < 2.4)
+
+ # Test picking normal orientation and using a list of CSD matrices
+ stc_normal = _lcmv_source_power(epochs.info, forward_surf_ori, noise_cov,
+ data_cov, pick_ori="normal", label=label)
+
+ # The normal orientation results should always be smaller than free
+ # orientation results
+ assert_true((np.abs(stc_normal.data[:, 0]) <=
+ stc_source_power.data[:, 0]).all())
+
+ # Test if fixed forward operator is detected when picking normal
+ # orientation
+ assert_raises(ValueError, _lcmv_source_power, raw.info, forward_fixed,
+ noise_cov, data_cov, pick_ori="normal")
+
+ # Test if non-surface oriented forward operator is detected when picking
+ # normal orientation
+ assert_raises(ValueError, _lcmv_source_power, raw.info, forward, noise_cov,
+ data_cov, pick_ori="normal")
+
+ # Test if volume forward operator is detected when picking normal
+ # orientation
+ assert_raises(ValueError, _lcmv_source_power, epochs.info, forward_vol,
+ noise_cov, data_cov, pick_ori="normal")
+
+
+ at sample.requires_sample_data
+def test_tf_lcmv():
+ """Test TF beamforming based on LCMV
+ """
+ fname_raw = op.join(data_path, 'MEG', 'sample',
+ 'sample_audvis_filt-0-40_raw.fif')
+ label = mne.read_label(fname_label)
+ events = mne.read_events(fname_event)
+ raw = mne.fiff.Raw(fname_raw, preload=True)
+ forward = mne.read_forward_solution(fname_fwd)
+
+ event_id, tmin, tmax = 1, -0.2, 0.2
+
+ # Setup for reading the raw data
+ raw.info['bads'] = ['MEG 2443', 'EEG 053'] # 2 bads channels
+
+ # Set up pick list: MEG - bad channels
+ left_temporal_channels = mne.read_selection('Left-temporal')
+ picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False,
+ stim=True, eog=True, exclude='bads',
+ selection=left_temporal_channels)
+
+ # Read epochs
+ epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ picks=picks, baseline=(None, 0),
+ preload=False,
+ reject=dict(grad=4000e-13, mag=4e-12, eog=150e-6))
+ epochs.drop_bad_epochs()
+
+ freq_bins = [(4, 12), (15, 40)]
+ time_windows = [(-0.1, 0.1), (0.0, 0.2)]
+ win_lengths = [0.2, 0.2]
+ tstep = 0.1
+ reg = 0.05
+
+ source_power = []
+ noise_covs = []
+ for (l_freq, h_freq), win_length in zip(freq_bins, win_lengths):
+ raw_band = raw.copy()
+ raw_band.filter(l_freq, h_freq, method='iir', n_jobs=1, picks=picks)
+ epochs_band = mne.Epochs(raw_band, epochs.events, epochs.event_id,
+ tmin=tmin, tmax=tmax, proj=True)
+ with warnings.catch_warnings(True): # not enough samples
+ noise_cov = compute_covariance(epochs_band, tmin=tmin, tmax=tmin +
+ win_length)
+ noise_cov = mne.cov.regularize(noise_cov, epochs_band.info, mag=reg,
+ grad=reg, eeg=reg, proj=True)
+ noise_covs.append(noise_cov)
+ del raw_band # to save memory
+
+ # Manually calculating source power in on frequency band and several
+ # time windows to compare to tf_lcmv results and test overlapping
+ if (l_freq, h_freq) == freq_bins[0]:
+ for time_window in time_windows:
+ with warnings.catch_warnings(True):
+ data_cov = compute_covariance(epochs_band,
+ tmin=time_window[0],
+ tmax=time_window[1])
+ stc_source_power = _lcmv_source_power(epochs.info, forward,
+ noise_cov, data_cov,
+ reg=reg, label=label)
+ source_power.append(stc_source_power.data)
+
+ stcs = tf_lcmv(epochs, forward, noise_covs, tmin, tmax, tstep, win_lengths,
+ freq_bins, reg=reg, label=label)
+
+ assert_true(len(stcs) == len(freq_bins))
+ assert_true(stcs[0].shape[1] == 4)
+
+ # Averaging all time windows that overlap the time period 0 to 100 ms
+ source_power = np.mean(source_power, axis=0)
+
+ # Selecting the first frequency bin in tf_lcmv results
+ stc = stcs[0]
+
+ # Comparing tf_lcmv results with _lcmv_source_power results
+ assert_array_almost_equal(stc.data[:, 2], source_power[:, 0])
+
+ # Test if using unsupported max-power orientation is detected
+ assert_raises(ValueError, tf_lcmv, epochs, forward, noise_covs, tmin, tmax,
+ tstep, win_lengths, freq_bins=freq_bins,
+ pick_ori='max-power')
+
+ # Test if incorrect number of noise CSDs is detected
+ # Test if incorrect number of noise covariances is detected
+ assert_raises(ValueError, tf_lcmv, epochs, forward, [noise_covs[0]], tmin,
+ tmax, tstep, win_lengths, freq_bins)
+
+ # Test if freq_bins and win_lengths incompatibility is detected
+ assert_raises(ValueError, tf_lcmv, epochs, forward, noise_covs, tmin, tmax,
+ tstep, win_lengths=[0, 1, 2], freq_bins=freq_bins)
+
+ # Test if time step exceeding window lengths is detected
+ assert_raises(ValueError, tf_lcmv, epochs, forward, noise_covs, tmin, tmax,
+ tstep=0.15, win_lengths=[0.2, 0.1], freq_bins=freq_bins)
+
+ # Test correct detection of preloaded epochs objects that do not contain
+ # the underlying raw object
+ epochs_preloaded = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ baseline=(None, 0), preload=True)
+ assert_raises(ValueError, tf_lcmv, epochs_preloaded, forward, noise_covs,
+ tmin, tmax, tstep, win_lengths, freq_bins)
+
+ with warnings.catch_warnings(True): # not enough samples
+ # Pass only one epoch to test if subtracting evoked
+ # responses yields zeros
+ stcs = tf_lcmv(epochs[0], forward, noise_covs, tmin, tmax, tstep,
+ win_lengths, freq_bins, subtract_evoked=True, reg=reg,
+ label=label)
+
+ assert_array_almost_equal(stcs[0].data, np.zeros_like(stcs[0].data))
diff --git a/mne/transforms/tests/__init__.py b/mne/commands/__init__.py
similarity index 100%
rename from mne/transforms/tests/__init__.py
rename to mne/commands/__init__.py
diff --git a/bin/mne_browse_raw.py b/mne/commands/mne_browse_raw.py
similarity index 81%
rename from bin/mne_browse_raw.py
rename to mne/commands/mne_browse_raw.py
index be19708..81c4dab 100755
--- a/bin/mne_browse_raw.py
+++ b/mne/commands/mne_browse_raw.py
@@ -3,7 +3,7 @@
You can do for example:
-$mne_browse_raw.py --raw sample_audvis_raw.fif --proj sample_audvis_ecg_proj.fif --eve sample_audvis_raw-eve.fif
+$ mne browse_raw --raw sample_audvis_raw.fif --proj sample_audvis_ecg_proj.fif --eve sample_audvis_raw-eve.fif
"""
# Authors : Eric Larson, PhD
@@ -14,10 +14,12 @@ import mne
if __name__ == '__main__':
- from optparse import OptionParser
- import pylab as pl
+ import matplotlib.pyplot as plt
+
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
- parser = OptionParser()
parser.add_option("--raw", dest="raw_in",
help="Input raw FIF file", metavar="FILE")
parser.add_option("--proj", dest="proj_in",
@@ -39,11 +41,12 @@ if __name__ == '__main__':
help="Order for plotting ('type' or 'original')",
default='type')
parser.add_option("-p", "--preload", dest="preload",
- help="Preload raw data (for faster navigaton)",
- default=False)
+ help="Preload raw data (for faster navigaton)",
+ default=False)
parser.add_option("-s", "--show_options", dest="show_options",
- help="Show projection options dialog",
- default=False)
+ help="Show projection options dialog",
+ default=False)
+
options, args = parser.parse_args()
raw_in = options.raw_in
@@ -58,7 +61,7 @@ if __name__ == '__main__':
if raw_in is None:
parser.print_help()
- sys.exit(-1)
+ sys.exit(1)
raw = mne.fiff.Raw(raw_in, preload=preload)
if len(proj_in) > 0:
@@ -70,4 +73,4 @@ if __name__ == '__main__':
events = None
fig = raw.plot(duration=duration, start=start, n_channels=n_channels,
order=order, show_options=show_options, events=events)
- pl.show(block=True)
+ plt.show(block=True)
diff --git a/bin/mne_bti2fiff.py b/mne/commands/mne_bti2fiff.py
similarity index 94%
rename from bin/mne_bti2fiff.py
rename to mne/commands/mne_bti2fiff.py
index 25bb625..4eefcac 100755
--- a/bin/mne_bti2fiff.py
+++ b/mne/commands/mne_bti2fiff.py
@@ -1,18 +1,8 @@
#!/usr/bin/env python
-
-# Authors: Denis A. Engemann <d.engemann at fz-juelich.de>
-# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
-# Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
-# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
-# Yuval Harpaz <yuvharpaz at gmail.com>
-#
-# simplified bsd-3 license
-
"""
-
Import BTi / 4D MagnesWH3600 data to fif file.
-example usage: mne_bti2fiff.py -pdf C,rfDC -o my_raw.fif
+example usage: mne bti2fiff -pdf C,rfDC -o my_raw.fif
Note.
1) Currently direct inclusion of reference channel weights
@@ -25,15 +15,26 @@ are present in your dataset but 'ECG 01' and 'EOG 01', 'EOG 02' don't
appear in the channel names of the raw object.
"""
-from mne.fiff.bti import read_raw_bti
-# from mne import verbose
+# Authors: Denis A. Engemann <d.engemann at fz-juelich.de>
+# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
+# Yuval Harpaz <yuvharpaz at gmail.com>
+#
+# simplified bsd-3 license
+
+
import sys
+from mne.fiff.bti import read_raw_bti
+
+
if __name__ == '__main__':
- from optparse import OptionParser
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
- parser = OptionParser()
parser.add_option('-p', '--pdf', dest='pdf_fname',
help='Input data file name', metavar='FILE')
parser.add_option('-c', '--config', dest='config_fname',
@@ -62,7 +63,7 @@ if __name__ == '__main__':
pdf_fname = options.pdf_fname
if pdf_fname is None:
parser.print_help()
- sys.exit(-1)
+ sys.exit(1)
config_fname = options.config_fname
head_shape_fname = options.head_shape_fname
diff --git a/bin/mne_clean_eog_ecg.py b/mne/commands/mne_clean_eog_ecg.py
similarity index 95%
rename from bin/mne_clean_eog_ecg.py
rename to mne/commands/mne_clean_eog_ecg.py
index 624cc56..9d91595 100755
--- a/bin/mne_clean_eog_ecg.py
+++ b/mne/commands/mne_clean_eog_ecg.py
@@ -8,6 +8,8 @@
import os
+import sys
+
import mne
@@ -116,9 +118,10 @@ def clean_ecg_eog(in_fif_fname, out_fif_fname=None, eog=True, ecg=True,
if __name__ == '__main__':
- from optparse import OptionParser
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
- parser = OptionParser()
parser.add_option("-i", "--in", dest="raw_in",
help="Input raw FIF file", metavar="FILE")
parser.add_option("-o", "--out", dest="raw_out",
@@ -129,7 +132,11 @@ if __name__ == '__main__':
parser.add_option("-c", "--no-ecg", dest="ecg", action="store_false",
help="Remove ECG", default=True)
- (options, args) = parser.parse_args()
+ options, args = parser.parse_args()
+
+ if options.raw_in is None:
+ parser.print_help()
+ sys.exit(1)
raw_in = options.raw_in
raw_out = options.raw_out
diff --git a/bin/mne_compute_proj_ecg.py b/mne/commands/mne_compute_proj_ecg.py
similarity index 50%
rename from bin/mne_compute_proj_ecg.py
rename to mne/commands/mne_compute_proj_ecg.py
index 10cc1a8..3407686 100755
--- a/bin/mne_compute_proj_ecg.py
+++ b/mne/commands/mne_compute_proj_ecg.py
@@ -3,7 +3,7 @@
You can do for example:
-$mne_compute_proj_ecg.py -i sample_audvis_raw.fif -c "MEG 1531" --l-freq 1 --h-freq 100 --rej-grad 3000 --rej-mag 4000 --rej-eeg 100
+$ mne compute_proj_ecg -i sample_audvis_raw.fif -c "MEG 1531" --l-freq 1 --h-freq 100 --rej-grad 3000 --rej-mag 4000 --rej-eeg 100
"""
# Authors : Alexandre Gramfort, Ph.D.
@@ -16,85 +16,101 @@ import mne
if __name__ == '__main__':
- from optparse import OptionParser
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
- parser = OptionParser()
parser.add_option("-i", "--in", dest="raw_in",
- help="Input raw FIF file", metavar="FILE")
+ help="Input raw FIF file", metavar="FILE")
parser.add_option("--tmin", dest="tmin", type="float",
- help="Time before event in seconds",
- default=-0.2)
+ help="Time before event in seconds",
+ default=-0.2)
parser.add_option("--tmax", dest="tmax", type="float",
- help="Time after event in seconds",
- default=0.4)
+ help="Time after event in seconds",
+ default=0.4)
parser.add_option("-g", "--n-grad", dest="n_grad", type="int",
- help="Number of SSP vectors for gradiometers",
- default=2)
+ help="Number of SSP vectors for gradiometers",
+ default=2)
parser.add_option("-m", "--n-mag", dest="n_mag", type="int",
- help="Number of SSP vectors for magnetometers",
- default=2)
+ help="Number of SSP vectors for magnetometers",
+ default=2)
parser.add_option("-e", "--n-eeg", dest="n_eeg", type="int",
- help="Number of SSP vectors for EEG",
- default=2)
+ help="Number of SSP vectors for EEG",
+ default=2)
parser.add_option("--l-freq", dest="l_freq", type="float",
- help="Filter low cut-off frequency in Hz",
- default=1)
+ help="Filter low cut-off frequency in Hz",
+ default=1)
parser.add_option("--h-freq", dest="h_freq", type="float",
- help="Filter high cut-off frequency in Hz",
- default=100)
+ help="Filter high cut-off frequency in Hz",
+ default=100)
parser.add_option("--ecg-l-freq", dest="ecg_l_freq", type="float",
- help="Filter low cut-off frequency in Hz used for ECG event detection",
- default=5)
+ help="Filter low cut-off frequency in Hz used "
+ "for ECG event detection",
+ default=5)
parser.add_option("--ecg-h-freq", dest="ecg_h_freq", type="float",
- help="Filter high cut-off frequency in Hz used for ECG event detection",
- default=35)
+ help="Filter high cut-off frequency in Hz used "
+ "for ECG event detection",
+ default=35)
parser.add_option("-p", "--preload", dest="preload",
- help="Temporary file used during computation (to save memory)",
- default=True)
+ help="Temporary file used during computation "
+ "(to save memory)",
+ default=True)
parser.add_option("-a", "--average", dest="average", action="store_true",
- help="Compute SSP after averaging",
- default=False)
+ help="Compute SSP after averaging",
+ default=False)
parser.add_option("--proj", dest="proj",
- help="Use SSP projections from a fif file.",
- default=None)
+ help="Use SSP projections from a fif file.",
+ default=None)
parser.add_option("--filtersize", dest="filter_length", type="int",
- help="Number of taps to use for filtering",
- default=2048)
+ help="Number of taps to use for filtering",
+ default=2048)
parser.add_option("-j", "--n-jobs", dest="n_jobs", type="int",
- help="Number of jobs to run in parallel",
- default=1)
+ help="Number of jobs to run in parallel",
+ default=1)
parser.add_option("-c", "--channel", dest="ch_name",
- help="Channel to use for ECG detection (Required if no ECG found)",
- default=None)
+ help="Channel to use for ECG detection "
+ "(Required if no ECG found)",
+ default=None)
parser.add_option("--rej-grad", dest="rej_grad", type="float",
- help="Gradiometers rejection parameter in fT/cm (peak to peak amplitude)",
- default=2000)
+ help="Gradiometers rejection parameter "
+ "in fT/cm (peak to peak amplitude)",
+ default=2000)
parser.add_option("--rej-mag", dest="rej_mag", type="float",
- help="Magnetometers rejection parameter in fT (peak to peak amplitude)",
- default=3000)
+ help="Magnetometers rejection parameter "
+ "in fT (peak to peak amplitude)",
+ default=3000)
parser.add_option("--rej-eeg", dest="rej_eeg", type="float",
- help="EEG rejection parameter in uV (peak to peak amplitude)",
- default=50)
+ help="EEG rejection parameter in uV "
+ "(peak to peak amplitude)",
+ default=50)
parser.add_option("--rej-eog", dest="rej_eog", type="float",
- help="EOG rejection parameter in uV (peak to peak amplitude)",
- default=250)
+ help="EOG rejection parameter in uV "
+ "(peak to peak amplitude)",
+ default=250)
parser.add_option("--avg-ref", dest="avg_ref", action="store_true",
- help="Add EEG average reference proj",
- default=False)
+ help="Add EEG average reference proj",
+ default=False)
parser.add_option("--no-proj", dest="no_proj", action="store_true",
- help="Exclude the SSP projectors currently in the fiff file",
- default=False)
+ help="Exclude the SSP projectors currently "
+ "in the fiff file",
+ default=False)
parser.add_option("--bad", dest="bad_fname",
- help="Text file containing bad channels list (one per line)",
- default=None)
+ help="Text file containing bad channels list "
+ "(one per line)",
+ default=None)
parser.add_option("--event-id", dest="event_id", type="int",
- help="ID to use for events", default=999)
+ help="ID to use for events",
+ default=999)
parser.add_option("--event-raw", dest="raw_event_fname",
- help="raw file to use for event detection", default=None)
+ help="raw file to use for event detection",
+ default=None)
parser.add_option("--tstart", dest="tstart", type="float",
- help="Start artifact detection after tstart seconds", default=0.)
- parser.add_option("--qrsthr", dest="qrs_threshold", type="float",
- help="QRS detection threshold. Between 0 and 1.", default=0.6)
+ help="Start artifact detection after tstart seconds",
+ default=0.)
+ parser.add_option("--qrsthr", dest="qrs_threshold", type="string",
+ help="QRS detection threshold. Between 0 and 1. Can "
+ "also be 'auto' for automatic selection",
+ default='auto')
options, args = parser.parse_args()
@@ -102,7 +118,7 @@ if __name__ == '__main__':
if raw_in is None:
parser.print_help()
- sys.exit(-1)
+ sys.exit(1)
tmin = options.tmin
tmax = options.tmax
@@ -130,6 +146,11 @@ if __name__ == '__main__':
raw_event_fname = options.raw_event_fname
tstart = options.tstart
qrs_threshold = options.qrs_threshold
+ if qrs_threshold != 'auto':
+ try:
+ qrs_threshold = float(qrs_threshold)
+ except ValueError:
+ raise ValueError('qrsthr must be "auto" or a float')
if bad_fname is not None:
bads = [w.rstrip().split()[0] for w in open(bad_fname).readlines()]
@@ -157,12 +178,12 @@ if __name__ == '__main__':
raw_event = raw
flat = None # XXX : not exposed to the user
- projs, events = mne.preprocessing.compute_proj_ecg(raw, raw_event,
- tmin, tmax, n_grad, n_mag, n_eeg,
- l_freq, h_freq, average, filter_length,
- n_jobs, ch_name, reject, flat,
- bads, avg_ref, no_proj, event_id,
- ecg_l_freq, ecg_h_freq, tstart, qrs_threshold)
+ cpe = mne.preprocessing.compute_proj_ecg
+ projs, events = cpe(raw, raw_event, tmin, tmax, n_grad, n_mag, n_eeg,
+ l_freq, h_freq, average, filter_length, n_jobs,
+ ch_name, reject, flat, bads, avg_ref, no_proj,
+ event_id, ecg_l_freq, ecg_h_freq, tstart,
+ qrs_threshold, copy=False)
raw.close()
diff --git a/bin/mne_compute_proj_eog.py b/mne/commands/mne_compute_proj_eog.py
similarity index 93%
rename from bin/mne_compute_proj_eog.py
rename to mne/commands/mne_compute_proj_eog.py
index 2a67081..f20c7a2 100755
--- a/bin/mne_compute_proj_eog.py
+++ b/mne/commands/mne_compute_proj_eog.py
@@ -3,11 +3,11 @@
You can do for example:
-$mne_compute_proj_eog.py -i sample_audvis_raw.fif --l-freq 1 --h-freq 35 --rej-grad 3000 --rej-mag 4000 --rej-eeg 100
+$ mne compute_proj_eog -i sample_audvis_raw.fif --l-freq 1 --h-freq 35 --rej-grad 3000 --rej-mag 4000 --rej-eeg 100
or
-$mne_compute_proj_eog.py -i sample_audvis_raw.fif --l-freq 1 --h-freq 35 --rej-grad 3000 --rej-mag 4000 --rej-eeg 100 --proj sample_audvis_ecg_proj.fif
+$ mne compute_proj_eog -i sample_audvis_raw.fif --l-freq 1 --h-freq 35 --rej-grad 3000 --rej-mag 4000 --rej-eeg 100 --proj sample_audvis_ecg_proj.fif
to exclude ECG artifacts from projection computation.
"""
@@ -22,9 +22,10 @@ import mne
if __name__ == '__main__':
- from optparse import OptionParser
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
- parser = OptionParser()
parser.add_option("-i", "--in", dest="raw_in",
help="Input raw FIF file", metavar="FILE")
parser.add_option("--tmin", dest="tmin", type="float",
@@ -106,7 +107,7 @@ if __name__ == '__main__':
if raw_in is None:
parser.print_help()
- sys.exit(-1)
+ sys.exit(1)
tmin = options.tmin
tmax = options.tmax
@@ -167,7 +168,7 @@ if __name__ == '__main__':
n_jobs=n_jobs, reject=reject, flat=flat, bads=bads,
avg_ref=avg_ref, no_proj=no_proj, event_id=event_id,
eog_l_freq=eog_l_freq, eog_h_freq=eog_h_freq,
- tstart=tstart, ch_name=ch_name)
+ tstart=tstart, ch_name=ch_name, copy=False)
raw.close()
@@ -186,4 +187,4 @@ if __name__ == '__main__':
mne.write_proj(eog_proj_fname, projs)
print "Writing EOG events in %s" % eog_event_fname
- mne.write_events(eog_event_fname, events)
\ No newline at end of file
+ mne.write_events(eog_event_fname, events)
diff --git a/bin/mne_flash_bem_model.py b/mne/commands/mne_flash_bem_model.py
similarity index 97%
rename from bin/mne_flash_bem_model.py
rename to mne/commands/mne_flash_bem_model.py
index b8584be..7a49b8e 100755
--- a/bin/mne_flash_bem_model.py
+++ b/mne/commands/mne_flash_bem_model.py
@@ -101,12 +101,13 @@ def make_flash_bem(subject, subjects_dir, flash05, flash30, show=False):
if __name__ == '__main__':
- from optparse import OptionParser
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
subject = os.environ.get('SUBJECT')
subjects_dir = os.environ.get('SUBJECTS_DIR')
- parser = OptionParser()
parser.add_option("-s", "--subject", dest="subject",
help="Subject name", default=subject)
parser.add_option("-d", "--subjects-dir", dest="subjects_dir",
@@ -121,7 +122,7 @@ if __name__ == '__main__':
help="Show BEM model in 3D for visual inspection",
default=False)
- (options, args) = parser.parse_args()
+ options, args = parser.parse_args()
subject = options.subject
subjects_dir = options.subjects_dir
diff --git a/bin/mne_kit2fiff.py b/mne/commands/mne_kit2fiff.py
similarity index 62%
rename from bin/mne_kit2fiff.py
rename to mne/commands/mne_kit2fiff.py
index eb64dcc..90eb785 100755
--- a/bin/mne_kit2fiff.py
+++ b/mne/commands/mne_kit2fiff.py
@@ -3,32 +3,34 @@
""" Import KIT / NYU data to fif file.
-example usage: mne_kit2fiff.py --input input.sqd --output output.fif
+example usage: mne kit2fiff --input input.sqd --output output.fif
"""
import sys
+
from mne.fiff.kit import read_raw_kit
if __name__ == '__main__':
- from optparse import OptionParser
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
- parser = OptionParser()
parser.add_option('--input', dest='input_fname',
- help='Input data file name', metavar='filename')
+ help='Input data file name', metavar='filename')
parser.add_option('--mrk', dest='mrk_fname',
- help='MEG Marker file name', metavar='filename')
+ help='MEG Marker file name', metavar='filename')
parser.add_option('--elp', dest='elp_fname',
- help='Headshape file name', metavar='filename')
+ help='Headshape points file name', metavar='filename')
parser.add_option('--hsp', dest='hsp_fname',
- help='Headshape file name', metavar='filename')
- parser.add_option('--sns', dest='sns_fname',
- help='Sensor info file name', metavar='filename')
+ help='Headshape file name', metavar='filename')
parser.add_option('--stim', dest='stim',
help='Colon Separated Stimulus Trigger Channels',
metavar='chs')
- parser.add_option('--stimthresh', dest='stimthresh', default=3.5,
+ parser.add_option('--slope', dest='slope', help='Slope direction',
+ metavar='slope')
+ parser.add_option('--stimthresh', dest='stimthresh', default=1,
help='Threshold value for trigger channels',
metavar='value')
parser.add_option('--output', dest='out_fname',
@@ -40,22 +42,22 @@ if __name__ == '__main__':
input_fname = options.input_fname
if input_fname is None:
parser.print_help()
- sys.exit(-1)
+ sys.exit(1)
- sns_fname = options.sns_fname
hsp_fname = options.hsp_fname
elp_fname = options.elp_fname
mrk_fname = options.mrk_fname
stim = options.stim
+ slope = options.slope
stimthresh = options.stimthresh
out_fname = options.out_fname
if isinstance(stim, str):
stim = stim.split(':')
- raw = read_raw_kit(input_fname=input_fname, mrk_fname=mrk_fname,
- elp_fname=elp_fname, hsp_fname=hsp_fname,
- sns_fname=sns_fname, stim=stim, stimthresh=stimthresh)
+ raw = read_raw_kit(input_fname=input_fname, mrk=mrk_fname, elp=elp_fname,
+ hsp=hsp_fname, stim=stim, slope=slope,
+ stimthresh=stimthresh)
raw.save(out_fname)
raw.close()
diff --git a/mne/commands/mne_make_scalp_surfaces.py b/mne/commands/mne_make_scalp_surfaces.py
new file mode 100755
index 0000000..45f550e
--- /dev/null
+++ b/mne/commands/mne_make_scalp_surfaces.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+# Authors: Denis A. Engemann <d.engemann at fz-juelich.de>
+# Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
+#
+# simplified bsd-3 license
+
+"""
+Create high-resolution head surfaces for coordinate alignment.
+
+example usage: mne make_scalp_surfaces --overwrite --subject sample
+"""
+import os
+import os.path as op
+import sys
+from commands import getstatusoutput
+import mne
+
+if __name__ == '__main__':
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
+
+ parser.add_option('-o', '--overwrite', dest='overwrite',
+ action='store_true',
+ help='Overwrite previously computed surface')
+ parser.add_option('-s', '--subject', dest='subject',
+ help='The name of the subject', type='str')
+ parser.add_option('-f', '--force', dest='force', action='store_true',
+ help='Force transformation of surface into bem.')
+ parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
+ help='Print the debug messages.')
+
+ options, args = parser.parse_args()
+
+ env = os.environ
+ subject = vars(options).get('subject', env.get('SUBJECT'))
+ if subject is None:
+ parser.print_help()
+ sys.exit(1)
+
+ overwrite = options.overwrite
+ verbose = options.verbose
+ force = '--force' if options.force else '--check'
+
+ def my_run_cmd(cmd, err_msg):
+ sig, out = getstatusoutput(cmd)
+ if verbose:
+ print out
+ if sig != 0:
+ print err_msg
+ sys.exit(1)
+
+ if not 'SUBJECTS_DIR' in env:
+ print 'The environment variable SUBJECTS_DIR should be set'
+ sys.exit(1)
+
+ if not op.isabs(env['SUBJECTS_DIR']):
+ env['SUBJECTS_DIR'] = op.abspath(env['SUBJECTS_DIR'])
+ subj_dir = env['SUBJECTS_DIR']
+
+ if not 'MNE_ROOT' in env:
+ print 'MNE_ROOT environment variable is not set'
+ sys.exit(1)
+
+ if not 'FREESURFER_HOME' in env:
+ print 'The FreeSurfer environment needs to be set up for this script'
+ sys.exit(1)
+
+ subj_path = op.join(subj_dir, subject)
+ if not op.exists(subj_path):
+ print ('%s does not exits. Please check your subject directory '
+ 'path.' % subj_path)
+ sys.exit(1)
+
+ if op.exists(op.join(subj_path, 'mri', 'T1.mgz')):
+ mri = 'T1.mgz'
+ else:
+ mri = 'T1'
+
+ print '1. Creating a dense scalp tessellation with mkheadsurf...'
+
+ def check_seghead(surf_path=op.join(subj_path, 'surf')):
+ for k in ['/lh.seghead', '/lh.smseghead']:
+ surf = surf_path + k if op.exists(surf_path + k) else None
+ if surf is not None:
+ break
+ return surf
+
+ my_seghead = check_seghead()
+ if my_seghead is None:
+ cmd = 'mkheadsurf -subjid %s -srcvol %s >/dev/null' % (subject, mri)
+ my_run_cmd(cmd, 'mkheadsurf failed')
+ else:
+ print '%s/surf/%s already there' % (subj_path, my_seghead)
+ if not overwrite:
+ print 'Use the --overwrite option to replace exisiting surfaces.'
+ sys.exit()
+
+ surf = check_seghead()
+ if surf is None:
+ print 'mkheadsurf did not produce the standard output file.'
+ sys.exit(1)
+
+ fif = '{0}/{1}/bem/{1}-head-dense.fif'.format(subj_dir, subject)
+ print '2. Creating %s ...' % fif
+ cmd = 'mne_surf2bem --surf %s --id 4 %s --fif %s' % (surf, force, fif)
+ my_run_cmd(cmd, 'Failed to create %s, see above' % fif)
+ levels = 'medium', 'sparse'
+ for ii, (n_tri, level) in enumerate(zip([30000, 2500], levels), 3):
+ my_surf = mne.read_bem_surfaces(fif)[0]
+ print '%i. Creating medium grade tessellation...' % ii
+ print '%i.1 Decimating the dense tessellation...' % ii
+ points, tris = mne.decimate_surface(points=my_surf['rr'],
+ triangles=my_surf['tris'],
+ n_triangles=n_tri)
+ out_fif = fif.replace('dense', level)
+ print '%i.2 Creating %s' % (ii, out_fif)
+ surf_fname = '/tmp/tmp-surf.surf'
+ # convert points to meters, make mne_analyze happy
+ mne.write_surface(surf_fname, points * 1e3, tris)
+ # XXX for some reason --check does not work here.
+ cmd = 'mne_surf2bem --surf %s --id 4 --force --fif %s'
+ cmd %= (surf_fname, out_fif)
+ my_run_cmd(cmd, 'Failed to create %s, see above' % out_fif)
+ os.remove(surf_fname)
+
+ sys.exit(0)
diff --git a/bin/mne_maxfilter.py b/mne/commands/mne_maxfilter.py
similarity index 97%
rename from bin/mne_maxfilter.py
rename to mne/commands/mne_maxfilter.py
index ad89a07..e727c7c 100755
--- a/bin/mne_maxfilter.py
+++ b/mne/commands/mne_maxfilter.py
@@ -3,7 +3,7 @@
Example usage:
-$mne_maxfilter.py -i sample_audvis_raw.fif --st
+$ mne maxfilter -i sample_audvis_raw.fif --st
This will apply MaxFilter with the MaxSt extension. The origin used
by MaxFilter is computed by mne-python by fitting a sphere to the
@@ -19,9 +19,10 @@ import mne
if __name__ == '__main__':
- from optparse import OptionParser
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
- parser = OptionParser()
parser.add_option("-i", "--in", dest="in_fname",
help="Input raw FIF file", metavar="FILE")
parser.add_option("-o", dest="out_fname",
@@ -94,7 +95,7 @@ if __name__ == '__main__':
if in_fname is None:
parser.print_help()
- sys.exit(-1)
+ sys.exit(1)
out_fname = options.out_fname
origin = options.origin
diff --git a/bin/mne_surf2bem.py b/mne/commands/mne_surf2bem.py
similarity index 67%
rename from bin/mne_surf2bem.py
rename to mne/commands/mne_surf2bem.py
index 368b9f4..6036f12 100755
--- a/bin/mne_surf2bem.py
+++ b/mne/commands/mne_surf2bem.py
@@ -1,21 +1,26 @@
#!/usr/bin/env python
-"""Example usage
+"""Convert surface to BEM FIF file
-mne_surf2bem.py --surf ${SUBJECTS_DIR}/${SUBJECT}/surf/lh.seghead --fif \
- ${SUBJECTS_DIR}/${SUBJECT}/bem/${SUBJECT}-head.fif --id=4
+Example usage
+
+mne surf2bem --surf ${SUBJECTS_DIR}/${SUBJECT}/surf/lh.seghead --fif \
+${SUBJECTS_DIR}/${SUBJECT}/bem/${SUBJECT}-head.fif --id=4
"""
# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
#
# License: BSD (3-clause)
+import sys
+
import mne
if __name__ == '__main__':
- from optparse import OptionParser
+ from mne.commands.utils import get_optparser
+
+ parser = get_optparser(__file__)
- parser = OptionParser()
parser.add_option("-s", "--surf", dest="surf",
help="Surface in Freesurfer format", metavar="FILE")
parser.add_option("-f", "--fif", dest="fif",
@@ -23,7 +28,11 @@ if __name__ == '__main__':
parser.add_option("-i", "--id", dest="id", default=4,
help=("Surface Id (e.g. 4 sur head surface)"))
- (options, args) = parser.parse_args()
+ options, args = parser.parse_args()
+
+ if options.surf is None:
+ parser.print_help()
+ sys.exit(1)
print "Converting %s to BEM FIF file." % options.surf
diff --git a/mne/commands/utils.py b/mne/commands/utils.py
new file mode 100644
index 0000000..233a586
--- /dev/null
+++ b/mne/commands/utils.py
@@ -0,0 +1,39 @@
+#emacs: -*- mode: python-mode; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
+#ex: set sts=4 ts=4 sw=4 noet:
+"""Some utility functions for commands (e.g. for cmdline handling)
+"""
+
+# Authors: Yaroslav Halchenko <debian at onerussian.com>
+#
+# License: BSD (3-clause)
+
+import imp, os, re
+from optparse import OptionParser
+
+import mne
+
+def get_optparser(cmdpath):
+ """Create OptionParser with cmdsource specific settings (e.g. prog value)
+ """
+ command = os.path.basename(cmdpath)
+ if re.match('mne_(.*).py', command):
+ command = command[4:-3]
+
+ # Fetch description
+ mod = imp.load_source('__temp', cmdpath)
+ if mod.__doc__:
+ doc, description, epilog = mod.__doc__, None, None
+
+ doc_lines = doc.split('\n')
+ description = doc_lines[0]
+ if len(doc_lines) > 1:
+ epilog = '\n'.join(doc_lines[1:])
+
+ # monkey patch OptionParser to not wrap epilog
+ OptionParser.format_epilog = lambda self, formatter: self.epilog
+ parser = OptionParser(prog="mne %s" % command,
+ version=mne.__version__,
+ description=description,
+ epilog=epilog)
+
+ return parser
diff --git a/mne/connectivity/effective.py b/mne/connectivity/effective.py
index 12a94bf..247b4fc 100644
--- a/mne/connectivity/effective.py
+++ b/mne/connectivity/effective.py
@@ -2,12 +2,10 @@
#
# License: BSD (3-clause)
import copy
-import logging
-logger = logging.getLogger('mne')
import numpy as np
-from .. import verbose
+from ..utils import logger, verbose
from .spectral import spectral_connectivity
diff --git a/mne/connectivity/spectral.py b/mne/connectivity/spectral.py
index 968e2d8..bad4cbb 100644
--- a/mne/connectivity/spectral.py
+++ b/mne/connectivity/spectral.py
@@ -8,19 +8,16 @@ from inspect import getargspec, getmembers
import numpy as np
from scipy.fftpack import fftfreq
-import logging
-logger = logging.getLogger('mne')
-
-
from .utils import check_indices
from ..fixes import tril_indices
from ..parallel import parallel_func
-from .. import Epochs, SourceEstimate
-from ..time_frequency.multitaper import dpss_windows, _mt_spectra,\
- _psd_from_mt, _csd_from_mt,\
- _psd_from_mt_adaptive
+from ..source_estimate import _BaseSourceEstimate
+from .. import Epochs
+from ..time_frequency.multitaper import (dpss_windows, _mt_spectra,
+ _psd_from_mt, _csd_from_mt,
+ _psd_from_mt_adaptive)
from ..time_frequency.tfr import morlet, cwt
-from .. import verbose
+from ..utils import logger, verbose
########################################################################
# Various connectivity estimators
@@ -327,7 +324,7 @@ def _epoch_spectral_connectivity(data, sig_idx, tmin_idx, tmax_idx, sfreq,
& (sig_idx < sig_pos_end)] - sig_pos_start
else:
this_sig_idx = sig_idx
- if isinstance(this_data, SourceEstimate):
+ if isinstance(this_data, _BaseSourceEstimate):
this_x_mt = this_data.transform_data(_mt_spectra,
fun_args=(window_fun, sfreq),
idx=this_sig_idx, tmin_idx=tmin_idx,
@@ -380,7 +377,7 @@ def _epoch_spectral_connectivity(data, sig_idx, tmin_idx, tmax_idx, sfreq,
& (sig_idx < sig_pos_end)] - sig_pos_start
else:
this_sig_idx = sig_idx
- if isinstance(this_data, SourceEstimate):
+ if isinstance(this_data, _BaseSourceEstimate):
this_x_cwt = this_data.transform_data(cwt,
fun_args=(wavelets,), idx=this_sig_idx, tmin_idx=tmin_idx,
tmax_idx=tmax_idx, use_fft=True, mode='same')
@@ -618,7 +615,7 @@ def spectral_connectivity(data, method='coh', indices=None, sfreq=2 * np.pi,
----------
data : array, shape=(n_epochs, n_signals, n_times)
or list/generator of array, shape =(n_signals, n_times)
- or list/generator of SourceEstimate
+ or list/generator of SourceEstimate or VolSourceEstimate
or Epochs
The data from which to compute connectivity. Note that it is also
possible to combine multiple signals by providing a list of tuples,
diff --git a/mne/connectivity/tests/test_effective.py b/mne/connectivity/tests/test_effective.py
index 6d2731d..13f5072 100644
--- a/mne/connectivity/tests/test_effective.py
+++ b/mne/connectivity/tests/test_effective.py
@@ -5,22 +5,19 @@ from nose.tools import assert_true
from mne.connectivity import phase_slope_index
-sfreq = 50.
-n_signals = 3
-n_epochs = 10
-n_times = 500
-
-rng = np.random.RandomState(42)
-data = rng.randn(n_epochs, n_signals, n_times)
-
-# simulate time shifts
-for i in range(n_epochs):
- data[i, 1, 10:] = data[i, 0, :-10] # signal 0 is ahead
- data[i, 2, :-10] = data[i, 0, 10:] # signal 2 is ahead
-
-
def test_psi():
"""Test Phase Slope Index (PSI) estimation"""
+ sfreq = 50.
+ n_signals = 3
+ n_epochs = 10
+ n_times = 500
+ rng = np.random.RandomState(42)
+ data = rng.randn(n_epochs, n_signals, n_times)
+
+ # simulate time shifts
+ for i in range(n_epochs):
+ data[i, 1, 10:] = data[i, 0, :-10] # signal 0 is ahead
+ data[i, 2, :-10] = data[i, 0, 10:] # signal 2 is ahead
psi, freqs, times, n_epochs, n_tapers = phase_slope_index(data,
mode='fourier', sfreq=sfreq)
diff --git a/mne/connectivity/tests/test_spectral.py b/mne/connectivity/tests/test_spectral.py
index de6162a..680c27e 100644
--- a/mne/connectivity/tests/test_spectral.py
+++ b/mne/connectivity/tests/test_spectral.py
@@ -9,26 +9,6 @@ from mne.connectivity.spectral import _CohEst
from mne import SourceEstimate
from mne.filter import band_pass_filter
-sfreq = 50.
-n_signals = 3
-n_epochs = 10
-n_times = 500
-
-tmin = 0.
-tmax = (n_times - 1) / sfreq
-# Use a case known to have no spurious correlations (it would bad if nosetests
-# could randomly fail):
-np.random.seed(0)
-data = np.random.randn(n_epochs, n_signals, n_times)
-times_data = np.linspace(tmin, tmax, n_times)
-
-# simulate connectivity from 5Hz..15Hz
-fstart, fend = 5.0, 15.0
-for i in xrange(n_epochs):
- data[i, 1, :] = band_pass_filter(data[i, 0, :], sfreq, fstart, fend)
- # add some noise, so the spectrum is not exactly zero
- data[i, 1, :] += 1e-2 * np.random.randn(n_times)
-
def _stc_gen(data, sfreq, tmin, combo=False):
"""Simulate a SourceEstimate generator"""
@@ -48,6 +28,25 @@ def _stc_gen(data, sfreq, tmin, combo=False):
def test_spectral_connectivity():
"""Test frequency-domain connectivity methods"""
+ # Use a case known to have no spurious correlations (it would bad if
+ # nosetests could randomly fail):
+ np.random.seed(0)
+
+ sfreq = 50.
+ n_signals = 3
+ n_epochs = 10
+ n_times = 500
+
+ tmin = 0.
+ tmax = (n_times - 1) / sfreq
+ data = np.random.randn(n_epochs, n_signals, n_times)
+ times_data = np.linspace(tmin, tmax, n_times)
+ # simulate connectivity from 5Hz..15Hz
+ fstart, fend = 5.0, 15.0
+ for i in xrange(n_epochs):
+ data[i, 1, :] = band_pass_filter(data[i, 0, :], sfreq, fstart, fend)
+ # add some noise, so the spectrum is not exactly zero
+ data[i, 1, :] += 1e-2 * np.random.randn(n_times)
# First we test some invalid parameters:
assert_raises(ValueError, spectral_connectivity, data, method='notamethod')
diff --git a/mne/coreg.py b/mne/coreg.py
new file mode 100644
index 0000000..48fb3ad
--- /dev/null
+++ b/mne/coreg.py
@@ -0,0 +1,1041 @@
+"""Coregistration between different coordinate frames"""
+
+# Authors: Christian Brodbeck <christianbrodbeck at nyu.edu>
+#
+# License: BSD (3-clause)
+
+from ConfigParser import RawConfigParser
+import fnmatch
+from glob import glob, iglob
+import os
+import re
+import shutil
+from warnings import warn
+
+import numpy as np
+from numpy import dot
+from scipy.optimize import leastsq
+from scipy.spatial.distance import cdist
+from scipy.linalg import norm
+
+from .fiff.meas_info import read_fiducials, write_fiducials
+from .label import read_label, Label
+from .source_space import read_source_spaces, write_source_spaces
+from .surface import (read_surface, write_surface, read_bem_surfaces,
+ write_bem_surface)
+from .transforms import rotation, rotation3d, scaling, translation
+from .utils import get_config, get_subjects_dir, logger, pformat
+
+
+# some path templates
+trans_fname = os.path.join('{raw_dir}', '{subject}-trans.fif')
+subject_dirname = os.path.join('{subjects_dir}', '{subject}')
+bem_dirname = os.path.join(subject_dirname, 'bem')
+surf_dirname = os.path.join(subject_dirname, 'surf')
+bem_fname = os.path.join(bem_dirname, "{subject}-{name}-bem.fif")
+fid_fname = os.path.join(bem_dirname, "{subject}-fiducials.fif")
+fid_fname_general = os.path.join(bem_dirname, "{head}-fiducials.fif")
+head_bem_fname = os.path.join(bem_dirname, "{subject}-head.fif")
+src_fname = os.path.join(bem_dirname, '{subject}-{spacing}-src.fif')
+
+
+
+def create_default_subject(mne_root=None, fs_home=None, update=False,
+ subjects_dir=None):
+ """Create an average brain subject for subjects without structural MRI
+
+ Create a copy of fsaverage from the Freesurfer directory in subjects_dir
+ and add auxiliary files from the mne package.
+
+ Parameters
+ ----------
+ mne_root : None | str
+ The mne root directory (only needed if MNE_ROOT is not specified as
+ environment variable).
+ fs_home : None | str
+ The freesurfer home directory (only needed if FREESURFER_HOME is not
+ specified as environment variable).
+ update : bool
+ In cases where a copy of the fsaverage brain already exists in the
+ subjects_dir, this option allows to only copy files that don't already
+ exist in the fsaverage directory.
+ subjects_dir : None | str
+ Override the SUBJECTS_DIR environment variable
+ (os.environ['SUBJECTS_DIR']) as destination for the new subject.
+
+ Notes
+ -----
+ When no structural MRI is available for a subject, an average brain can be
+ substituted. Freesurfer comes with such an average brain model, and MNE
+ comes with some auxiliary files which make coregistration easier.
+ :py:func:`create_default_subject` copies the relevant files from Freesurfer
+ into the current subjects_dir, and also adds the auxiliary files provided
+ by MNE.
+
+ The files provided by MNE are listed below and can be found under
+ ``share/mne/mne_analyze/fsaverage`` in the MNE directory (see MNE manual
+ section 7.19 Working with the average brain):
+
+ fsaverage_head.fif:
+ The approximate head surface triangulation for fsaverage.
+ fsaverage_inner_skull-bem.fif:
+ The approximate inner skull surface for fsaverage.
+ fsaverage-fiducials.fif:
+ The locations of the fiducial points (LPA, RPA, and nasion).
+ fsaverage-trans.fif:
+ Contains a default MEG-MRI coordinate transformation suitable for
+ fsaverage.
+ """
+ subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
+ if fs_home is None:
+ fs_home = get_config('FREESURFER_HOME', fs_home)
+ if fs_home is None:
+ err = ("FREESURFER_HOME environment variable not found. Please "
+ "specify the fs_home parameter in your call to "
+ "create_default_subject().")
+ raise ValueError(err)
+ if mne_root is None:
+ mne_root = get_config('MNE_ROOT', mne_root)
+ if mne_root is None:
+ err = ("MNE_ROOT environment variable not found. Please "
+ "specify the mne_root parameter in your call to "
+ "create_default_subject().")
+ raise ValueError(err)
+
+ # make sure freesurfer files exist
+ fs_src = os.path.join(fs_home, 'subjects', 'fsaverage')
+ if not os.path.exists(fs_src):
+ err = ('fsaverage not found at %r. Is fs_home specified '
+ 'correctly?' % fs_src)
+ raise IOError(err)
+ for name in ('label', 'mri', 'surf'):
+ dirname = os.path.join(fs_src, name)
+ if not os.path.isdir(dirname):
+ err = ("Freesurfer fsaverage seems to be incomplete: No directory "
+ "named %s found in %s" % (name, fs_src))
+ raise IOError(err)
+
+ # make sure destination does not already exist
+ dest = os.path.join(subjects_dir, 'fsaverage')
+ if dest == fs_src:
+ err = ("Your subjects_dir points to the freesurfer subjects_dir (%r). "
+ "The default subject can not be created in the freesurfer "
+ "installation directory; please specify a different "
+ "subjects_dir." % subjects_dir)
+ raise IOError(err)
+ elif (not update) and os.path.exists(dest):
+ err = ("Can not create fsaverage because %r already exists in "
+ "subjects_dir %r. Delete or rename the existing fsaverage "
+ "subject folder." % ('fsaverage', subjects_dir))
+ raise IOError(err)
+
+ # make sure mne files exist
+ mne_fname = os.path.join(mne_root, 'share', 'mne', 'mne_analyze',
+ 'fsaverage', 'fsaverage-%s.fif')
+ mne_files = ('fiducials', 'head', 'inner_skull-bem', 'trans')
+ for name in mne_files:
+ fname = mne_fname % name
+ if not os.path.isfile(fname):
+ err = ("MNE fsaverage incomplete: %s file not found at "
+ "%s" % (name, fname))
+ raise IOError(err)
+
+ # copy fsaverage from freesurfer
+ logger.info("Copying fsaverage subject from freesurfer directory...")
+ if (not update) or not os.path.exists(dest):
+ shutil.copytree(fs_src, dest)
+
+ # add files from mne
+ dest_bem = os.path.join(dest, 'bem')
+ if not os.path.exists(dest_bem):
+ os.mkdir(dest_bem)
+ logger.info("Copying auxiliary fsaverage files from mne directory...")
+ dest_fname = os.path.join(dest_bem, 'fsaverage-%s.fif')
+ for name in mne_files:
+ if not os.path.exists(dest_fname % name):
+ shutil.copy(mne_fname % name, dest_bem)
+
+
+def _decimate_points(pts, res=10):
+ """Decimate the number of points using a voxel grid
+
+ Create a voxel grid with a specified resolution and retain at most one
+ point per voxel. For each voxel, the point closest to its center is
+ retained.
+
+ Parameters
+ ----------
+ pts : array, shape = (n_points, 3)
+ The points making up the head shape.
+ res : scalar
+ The resolution of the voxel space (side length of each voxel).
+
+ Returns
+ -------
+ pts : array, shape = (n_points, 3)
+ The decimated points.
+ """
+ pts = np.asarray(pts)
+
+ # find the bin edges for the voxel space
+ xmin, ymin, zmin = pts.min(0) - res / 2.
+ xmax, ymax, zmax = pts.max(0) + res
+ xax = np.arange(xmin, xmax, res)
+ yax = np.arange(ymin, ymax, res)
+ zax = np.arange(zmin, zmax, res)
+
+ # find voxels containing one or more point
+ H, _ = np.histogramdd(pts, bins=(xax, yax, zax), normed=False)
+
+ # for each voxel, select one point
+ X, Y, Z = pts.T
+ out = np.empty((np.sum(H > 0), 3))
+ for i, (xbin, ybin, zbin) in enumerate(zip(*np.nonzero(H))):
+ x = xax[xbin]
+ y = yax[ybin]
+ z = zax[zbin]
+ xi = np.logical_and(X >= x, X < x + res)
+ yi = np.logical_and(Y >= y, Y < y + res)
+ zi = np.logical_and(Z >= z, Z < z + res)
+ idx = np.logical_and(zi, np.logical_and(yi, xi))
+ ipts = pts[idx]
+
+ mid = np.array([x, y, z]) + res / 2.
+ dist = cdist(ipts, [mid])
+ i_min = np.argmin(dist)
+ ipt = ipts[i_min]
+ out[i] = ipt
+
+ return out
+
+
+def _trans_from_params(param_info, params):
+ """Convert transformation parameters into a transformation matrix
+
+ Parameters
+ ----------
+ param_info : tuple, len = 3
+ Tuple describing the parameters in x (do_translate, do_rotate,
+ do_scale).
+ params : tuple
+ The transformation parameters.
+
+ Returns
+ -------
+ trans : array, shape = (4, 4)
+ Transformation matrix.
+ """
+ do_rotate, do_translate, do_scale = param_info
+ i = 0
+ trans = []
+
+ if do_rotate:
+ x, y, z = params[:3]
+ trans.append(rotation(x, y, z))
+ i += 3
+
+ if do_translate:
+ x, y, z = params[i:i + 3]
+ trans.insert(0, translation(x, y, z))
+ i += 3
+
+ if do_scale == 1:
+ s = params[i]
+ trans.append(scaling(s, s, s))
+ elif do_scale == 3:
+ x, y, z = params[i:i + 3]
+ trans.append(scaling(x, y, z))
+
+ trans = reduce(dot, trans)
+ return trans
+
+
+def fit_matched_points(src_pts, tgt_pts, rotate=True, translate=True,
+ scale=False, tol=None, x0=None, out='trans'):
+ """Find a transform that minimizes the squared distance between two
+ matching sets of points.
+
+ Uses :func:`scipy.optimize.leastsq` to find a transformation involving
+ a combination of rotation, translation, and scaling (in that order).
+
+ Parameters
+ ----------
+ src_pts : array, shape = (n, 3)
+ Points to which the transform should be applied.
+ tgt_pts : array, shape = (n, 3)
+ Points to which src_pts should be fitted. Each point in tgt_pts should
+ correspond to the point in src_pts with the same index.
+ rotate : bool
+ Allow rotation of the ``src_pts``.
+ translate : bool
+ Allow translation of the ``src_pts``.
+ scale : bool
+ Number of scaling parameters. With False, points are not scaled. With
+ True, points are scaled by the same factor along all axes.
+ tol : scalar | None
+ The error tolerance. If the distance between any of the matched points
+ exceeds this value in the solution, a RuntimeError is raised. With
+ None, no error check is performed.
+ x0 : None | tuple
+ Initial values for the fit parameters.
+ out : 'params' | 'trans'
+ In what format to return the estimate: 'params' returns a tuple with
+ the fit parameters; 'trans' returns a transformation matrix of shape
+ (4, 4).
+
+
+ Returns
+ -------
+ One of the following, depending on the ``out`` parameter:
+
+ trans : array, shape = (4, 4)
+ Transformation that, if applied to src_pts, minimizes the squared
+ distance to tgt_pts.
+ params : array, shape = (n_params, )
+ A single tuple containing the translation, rotation and scaling
+ parameters in that order.
+ """
+ src_pts = np.atleast_2d(src_pts)
+ tgt_pts = np.atleast_2d(tgt_pts)
+ if src_pts.shape != tgt_pts.shape:
+ err = ("src_pts and tgt_pts must have same shape "
+ "(got {0}, {1})".format(src_pts.shape, tgt_pts.shape))
+ raise ValueError(err)
+
+ rotate = bool(rotate)
+ translate = bool(translate)
+ scale = int(scale)
+ if translate:
+ src_pts = np.hstack((src_pts, np.ones((len(src_pts), 1))))
+
+ param_info = (rotate, translate, scale)
+ if param_info == (True, False, 0):
+ def error(x):
+ rx, ry, rz = x
+ trans = rotation3d(rx, ry, rz)
+ est = dot(src_pts, trans.T)
+ return (tgt_pts - est).ravel()
+ if x0 is None:
+ x0 = (0, 0, 0)
+ elif param_info == (True, False, 1):
+ def error(x):
+ rx, ry, rz, s = x
+ trans = rotation3d(rx, ry, rz) * s
+ est = dot(src_pts, trans.T)
+ return (tgt_pts - est).ravel()
+ if x0 is None:
+ x0 = (0, 0, 0, 1)
+ elif param_info == (True, True, 0):
+ def error(x):
+ rx, ry, rz, tx, ty, tz = x
+ trans = dot(translation(tx, ty, tz), rotation(rx, ry, rz))
+ est = dot(src_pts, trans.T)
+ return (tgt_pts - est[:, :3]).ravel()
+ if x0 is None:
+ x0 = (0, 0, 0, 0, 0, 0)
+ elif param_info == (True, True, 1):
+ def error(x):
+ rx, ry, rz, tx, ty, tz, s = x
+ trans = reduce(dot, (translation(tx, ty, tz), rotation(rx, ry, rz),
+ scaling(s, s, s)))
+ est = dot(src_pts, trans.T)
+ return (tgt_pts - est[:, :3]).ravel()
+ if x0 is None:
+ x0 = (0, 0, 0, 0, 0, 0, 1)
+ else:
+ err = ("The specified parameter combination is not implemented: "
+ "rotate=%r, translate=%r, scale=%r" % param_info)
+ raise NotImplementedError(err)
+
+ x, _, _, _, _ = leastsq(error, x0, full_output=True)
+
+ # re-create the final transformation matrix
+ if (tol is not None) or (out == 'trans'):
+ trans = _trans_from_params(param_info, x)
+
+ # assess the error of the solution
+ if tol is not None:
+ if not translate:
+ src_pts = np.hstack((src_pts, np.ones((len(src_pts), 1))))
+ est_pts = dot(src_pts, trans.T)[:, :3]
+ err = np.sqrt(np.sum((est_pts - tgt_pts) ** 2, axis=1))
+ if np.any(err > tol):
+ raise RuntimeError("Error exceeds tolerance. Error = %r" % err)
+
+ if out == 'params':
+ return x
+ elif out == 'trans':
+ return trans
+ else:
+ err = ("Invalid out parameter: %r. Needs to be 'params' or "
+ "'trans'." % out)
+ raise ValueError(err)
+
+
+def get_ras_to_neuromag_trans(nasion, lpa, rpa):
+ """Construct a transformation matrix to the MNE head coordinate system
+
+ Construct a transformation matrix from an arbitrary RAS coordinate system
+ to the MNE head coordinate system, in which the x axis passes through the
+ two preauricular points, and the y axis passes through the nasion and is
+ normal to the x axis. (see mne manual, pg. 97)
+
+ Parameters
+ ----------
+ nasion : array_like, shape = (3,)
+ Nasion point coordinate.
+ lpa : array_like, shape = (3,)
+ Left peri-auricular point coordinate.
+ rpa : array_like, shape = (3,)
+ Right peri-auricular point coordinate.
+
+ Returns
+ -------
+ trans : numpy.array, shape = (4, 4)
+ Transformation matrix to MNE head space.
+ """
+ # check input args
+ nasion = np.asarray(nasion)
+ lpa = np.asarray(lpa)
+ rpa = np.asarray(rpa)
+ for pt in (nasion, lpa, rpa):
+ if pt.ndim != 1 or len(pt) != 3:
+ err = ("Points have to be provided as one dimensional arrays of "
+ "length 3.")
+ raise ValueError(err)
+
+ right = rpa - lpa
+ right_unit = right / norm(right)
+
+ origin = lpa + np.dot(nasion - lpa, right_unit) * right_unit
+
+ anterior = nasion - origin
+ anterior_unit = anterior / norm(anterior)
+
+ superior_unit = np.cross(right_unit, anterior_unit)
+
+ x, y, z = -origin
+ origin_trans = translation(x, y, z)
+
+ trans_l = np.vstack((right_unit, anterior_unit, superior_unit, [0, 0, 0]))
+ trans_r = np.reshape([0, 0, 0, 1], (4, 1))
+ rot_trans = np.hstack((trans_l, trans_r))
+
+ trans = np.dot(rot_trans, origin_trans)
+ return trans
+
+
+def _point_cloud_error(src_pts, tgt_pts):
+ """Find the distance from each source point to its closest target point
+
+ Parameters
+ ----------
+ src_pts : array, shape = (n, 3)
+ Source points.
+ tgt_pts : array, shape = (m, 3)
+ Target points.
+
+ Returns
+ -------
+ dist : array, shape = (n, )
+ For each point in ``src_pts``, the distance to the closest point in
+ ``tgt_pts``.
+ """
+ Y = cdist(src_pts, tgt_pts, 'euclidean')
+ dist = Y.min(axis=1)
+ return dist
+
+
+def _point_cloud_error_balltree(src_pts, tgt_tree):
+ """Find the distance from each source point to its closest target point
+
+ Uses sklearn.neighbors.BallTree for greater efficiency
+
+ Parameters
+ ----------
+ src_pts : array, shape = (n, 3)
+ Source points.
+ tgt_tree : sklearn.neighbors.BallTree
+ BallTree of the target points.
+
+ Returns
+ -------
+ dist : array, shape = (n, )
+ For each point in ``src_pts``, the distance to the closest point in
+ ``tgt_pts``.
+ """
+ dist, _ = tgt_tree.query(src_pts)
+ return dist.ravel()
+
+
+def fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=True,
+ scale=0, x0=None, leastsq_args={}, out='params'):
+ """Find a transform that minimizes the squared distance from each source
+ point to its closest target point
+
+ Uses :func:`scipy.optimize.leastsq` to find a transformation involving
+ a combination of rotation, translation, and scaling (in that order).
+
+ Parameters
+ ----------
+ src_pts : array, shape = (n, 3)
+ Points to which the transform should be applied.
+ tgt_pts : array, shape = (m, 3)
+ Points to which src_pts should be fitted. Each point in tgt_pts should
+ correspond to the point in src_pts with the same index.
+ rotate : bool
+ Allow rotation of the ``src_pts``.
+ translate : bool
+ Allow translation of the ``src_pts``.
+ scale : 0 | 1 | 3
+ Number of scaling parameters. With 0, points are not scaled. With 1,
+ points are scaled by the same factor along all axes. With 3, points are
+ scaled by a separate factor along each axis.
+ x0 : None | tuple
+ Initial values for the fit parameters.
+ leastsq_args : dict
+ Additional parameters to submit to :func:`scipy.optimize.leastsq`.
+ out : 'params' | 'trans'
+ In what format to return the estimate: 'params' returns a tuple with
+ the fit parameters; 'trans' returns a transformation matrix of shape
+ (4, 4).
+
+ Returns
+ -------
+ x : array, shape = (n_params, )
+ Estimated parameters for the transformation.
+
+ Notes
+ -----
+ Assumes that the target points form a dense enough point cloud so that
+ the distance of each src_pt to the closest tgt_pt can be used as an
+ estimate of the distance of src_pt to tgt_pts.
+ """
+ kwargs = {'epsfcn': 0.01}
+ kwargs.update(leastsq_args)
+
+ # assert correct argument types
+ src_pts = np.atleast_2d(src_pts)
+ tgt_pts = np.atleast_2d(tgt_pts)
+ translate = bool(translate)
+ rotate = bool(rotate)
+ scale = int(scale)
+
+ if translate:
+ src_pts = np.hstack((src_pts, np.ones((len(src_pts), 1))))
+
+ try:
+ from sklearn.neighbors import BallTree
+ tgt_pts = BallTree(tgt_pts)
+ errfunc = _point_cloud_error_balltree
+ except ImportError:
+ warn("Sklearn could not be imported. Fitting points will be slower. "
+ "To improve performance, install the sklearn module.")
+ errfunc = _point_cloud_error
+
+
+ # for efficiency, define parameter specific error function
+ param_info = (rotate, translate, scale)
+ if param_info == (True, False, 0):
+ x0 = x0 or (0, 0, 0)
+ def error(x):
+ rx, ry, rz = x
+ trans = rotation3d(rx, ry, rz)
+ est = dot(src_pts, trans.T)
+ err = errfunc(est, tgt_pts)
+ return err
+ elif param_info == (True, False, 1):
+ x0 = x0 or (0, 0, 0, 1)
+ def error(x):
+ rx, ry, rz, s = x
+ trans = rotation3d(rx, ry, rz) * s
+ est = dot(src_pts, trans.T)
+ err = errfunc(est, tgt_pts)
+ return err
+ elif param_info == (True, False, 3):
+ x0 = x0 or (0, 0, 0, 1, 1, 1)
+ def error(x):
+ rx, ry, rz, sx, sy, sz = x
+ trans = rotation3d(rx, ry, rz) * [sx, sy, sz]
+ est = dot(src_pts, trans.T)
+ err = errfunc(est, tgt_pts)
+ return err
+ elif param_info == (True, True, 0):
+ x0 = x0 or (0, 0, 0, 0, 0, 0)
+ def error(x):
+ rx, ry, rz, tx, ty, tz = x
+ trans = dot(translation(tx, ty, tz), rotation(rx, ry, rz))
+ est = dot(src_pts, trans.T)
+ err = errfunc(est[:, :3], tgt_pts)
+ return err
+ else:
+ err = ("The specified parameter combination is not implemented: "
+ "rotate=%r, translate=%r, scale=%r" % param_info)
+ raise NotImplementedError(err)
+
+ est, _, info, msg, _ = leastsq(error, x0, full_output=True, **kwargs)
+ logger.debug("fit_point_cloud leastsq (%i calls) info: %s", info['nfev'],
+ msg)
+
+ if out == 'params':
+ return est
+ elif out == 'trans':
+ return _trans_from_params(param_info, est)
+ else:
+ err = ("Invalid out parameter: %r. Needs to be 'params' or "
+ "'trans'." % out)
+ raise ValueError(err)
+
+
+def _find_label_paths(subject='fsaverage', pattern=None, subjects_dir=None):
+ """Find paths to label files in a subject's label directory
+
+ Parameters
+ ----------
+ subject : str
+ Name of the mri subject.
+ pattern : str | None
+ Pattern for finding the labels relative to the label directory in the
+ MRI subject directory (e.g., "aparc/*.label" will find all labels
+ in the "subject/label/aparc" directory). With None, find all labels.
+ subjects_dir : None | str
+ Override the SUBJECTS_DIR environment variable
+ (sys.environ['SUBJECTS_DIR'])
+
+ Returns
+ ------
+ paths : list
+ List of paths relative to the subject's label directory
+ """
+ subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
+ subject_dir = os.path.join(subjects_dir, subject)
+ lbl_dir = os.path.join(subject_dir, 'label')
+
+ if pattern is None:
+ paths = []
+ for dirpath, _, filenames in os.walk(lbl_dir):
+ rel_dir = os.path.relpath(dirpath, lbl_dir)
+ for filename in fnmatch.filter(filenames, '*.label'):
+ path = os.path.join(rel_dir, filename)
+ paths.append(path)
+ else:
+ paths = [os.path.relpath(path, lbl_dir) for path in iglob(pattern)]
+
+ return paths
+
+
+def _find_mri_paths(subject='fsaverage', subjects_dir=None):
+ """Find all files of an mri relevant for source transformation
+
+ Parameters
+ ----------
+ subject : str
+ Name of the mri subject.
+ subjects_dir : None | str
+ Override the SUBJECTS_DIR environment variable
+ (sys.environ['SUBJECTS_DIR'])
+
+ Returns
+ -------
+ paths | dict
+ Dictionary whose keys are relevant file type names (str), and whose
+ values are lists of paths.
+ """
+ subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
+ paths = {}
+
+ # directories to create
+ paths['dirs'] = [bem_dirname, surf_dirname]
+
+ # surf/ files
+ paths['surf'] = surf = []
+ surf_fname = os.path.join(surf_dirname, '{name}')
+ surf_names = ('orig', 'orig_avg',
+ 'inflated', 'inflated_avg', 'inflated_pre',
+ 'pial', 'pial_avg',
+ 'smoothwm',
+ 'white', 'white_avg',
+ 'sphere', 'sphere.reg', 'sphere.reg.avg')
+ for name in surf_names:
+ for hemi in ('lh.', 'rh.'):
+ fname = pformat(surf_fname, name=hemi + name)
+ surf.append(fname)
+
+ # BEM files
+ paths['bem'] = bem = []
+ bem.append(head_bem_fname)
+ bem_file = pformat(bem_fname, name='inner_skull')
+ bem.append(bem_file)
+
+ # fiducials
+ paths['fid'] = [fid_fname]
+
+ # duplicate curvature files
+ paths['duplicate'] = dup = []
+ path = os.path.join(surf_dirname, '{name}')
+ for name in ['lh.curv', 'rh.curv']:
+ fname = pformat(path, name=name)
+ dup.append(fname)
+
+ # check presence of required files
+ for ftype in ['surf', 'bem', 'fid', 'duplicate']:
+ for fname in paths[ftype]:
+ path = fname.format(subjects_dir=subjects_dir, subject=subject)
+ path = os.path.realpath(path)
+ if not os.path.exists(path):
+ raise IOError("Required file not found: %r" % path)
+
+ # find source space files
+ paths['src'] = src = []
+ bem_dir = bem_dirname.format(subjects_dir=subjects_dir, subject=subject)
+ fnames = fnmatch.filter(os.listdir(bem_dir), '*-src.fif')
+ prefix = subject + '-'
+ for fname in fnames:
+ if fname.startswith(prefix):
+ fname = "{subject}-%s" % fname[len(prefix):]
+ path = os.path.join(bem_dirname, fname)
+ src.append(path)
+
+ return paths
+
+
+def _is_mri_subject(subject, subjects_dir=None):
+ """Check whether a directory in subjects_dir is an mri subject directory
+
+ Parameters
+ ----------
+ subject : str
+ Name of the potential subject/directory.
+ subjects_dir : None | str
+ Override the SUBJECTS_DIR environment variable.
+
+ Returns
+ -------
+ is_mri_subject : bool
+ Whether ``subject`` is an mri subject.
+ """
+ subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
+ sdir = os.path.join(subjects_dir, subject)
+
+ fname = os.path.join(sdir, 'bem', '%s-head.fif' % subject)
+ if not os.path.exists(fname):
+ return False
+
+ fname = os.path.join(sdir, 'bem', '%s-*-bem.fif' % subject)
+ if len(glob(fname)) == 0:
+ return False
+
+ return True
+
+
+def read_mri_cfg(subject, subjects_dir=None):
+ """Read information from the cfg file of a scaled MRI brain
+
+ Parameters
+ ----------
+ subject : str
+ Name of the scaled MRI subject.
+ subjects_dir : None | str
+ Override the SUBJECTS_DIR environment variable.
+
+ Returns
+ -------
+ cfg : dict
+ Dictionary with entries from the MRI's cfg file.
+ """
+ subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
+ fname = os.path.join(subjects_dir, subject, 'MRI scaling parameters.cfg')
+
+ if not os.path.exists(fname):
+ err = ("%r does not seem to be a scaled mri subject: %r does not "
+ "exist." % (subject, fname))
+ raise IOError(err)
+
+ logger.info("Reading MRI cfg file %s" % fname)
+ config = RawConfigParser()
+ config.read(fname)
+ n_params = config.getint("MRI Scaling", 'n_params')
+ if n_params == 1:
+ scale = config.getfloat("MRI Scaling", 'scale')
+ elif n_params == 3:
+ scale_str = config.get("MRI Scaling", 'scale')
+ scale = np.array(map(float, scale_str.split()))
+ else:
+ raise ValueError("Invalid n_params value in MRI cfg: %i" % n_params)
+
+ out = {'subject_from': config.get("MRI Scaling", 'subject_from'),
+ 'n_params': n_params, 'scale': scale}
+ return out
+
+
+def _write_mri_config(fname, subject_from, subject_to, scale):
+ """Write the cfg file describing a scaled MRI subject
+
+ Parameters
+ ----------
+ fname : str
+ Target file.
+ subject_from : str
+ Name of the source MRI subject.
+ subject_to : str
+ Name of the scaled MRI subject.
+ scale : float | array_like, shape = (3,)
+ The scaling parameter.
+ """
+ scale = np.asarray(scale)
+ if np.isscalar(scale) or scale.shape == ():
+ n_params = 1
+ else:
+ n_params = 3
+
+ config = RawConfigParser()
+ config.add_section("MRI Scaling")
+ config.set("MRI Scaling", 'subject_from', subject_from)
+ config.set("MRI Scaling", 'subject_to', subject_to)
+ config.set("MRI Scaling", 'n_params', str(n_params))
+ if n_params == 1:
+ config.set("MRI Scaling", 'scale', str(scale))
+ else:
+ config.set("MRI Scaling", 'scale', ' '.join(map(str, scale)))
+ config.set("MRI Scaling", 'version', '1')
+ with open(fname, 'wb') as fid:
+ config.write(fid)
+
+
+def scale_labels(subject_to, pattern=None, overwrite=False, subject_from=None,
+ scale=None, subjects_dir=None):
+ """Scale labels to match a brain that was previously created by scaling
+
+ Parameters
+ ----------
+ subject_to : str
+ Name of the scaled MRI subject (the destination brain).
+ pattern : str | None
+ Pattern for finding the labels relative to the label directory in the
+ MRI subject directory (e.g., "lh.BA3a.label" will scale
+ "fsaverage/label/lh.BA3a.label"; "aparc/*.label" will find all labels
+ in the "fsaverage/label/aparc" directory). With None, scale all labels.
+ overwrite : bool
+ Overwrite any label file that already exists for subject_to (otherwise
+ existsing labels are skipped).
+ subject_from : None | str
+ Name of the original MRI subject (the brain that was scaled to create
+ subject_to). If None, the value is read from subject_to's cfg file.
+ scale : None | float | array_like, shape = (3,)
+ Scaling parameter. If None, the value is read from subject_to's cfg
+ file.
+ subjects_dir : None | str
+ Override the SUBJECTS_DIR environment variable.
+ """
+ # read parameters from cfg
+ if scale is None or subject_from is None:
+ cfg = read_mri_cfg(subject_to, subjects_dir)
+ if subject_from is None:
+ subject_from = cfg['subject_from']
+ if scale is None:
+ scale = cfg['scale']
+
+ # find labels
+ paths = _find_label_paths(subject_from, pattern, subjects_dir)
+ if not paths:
+ return
+
+ subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
+ src_root = os.path.join(subjects_dir, subject_from, 'label')
+ dst_root = os.path.join(subjects_dir, subject_to, 'label')
+
+ # scale labels
+ for fname in paths:
+ dst = os.path.join(dst_root, fname)
+ if not overwrite and os.path.exists(dst):
+ continue
+
+ dirname = os.path.dirname(dst)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
+ src = os.path.join(src_root, fname)
+ l_old = read_label(src)
+ pos = l_old.pos * scale
+ l_new = Label(l_old.vertices, pos, l_old.values, l_old.hemi,
+ l_old.comment, subject=subject_to)
+ l_new.save(dst)
+
+
+def scale_mri(subject_from, subject_to, scale, overwrite=False,
+ subjects_dir=None):
+ """Create a scaled copy of an MRI subject
+
+ Parameters
+ ----------
+ subject_from : str
+ Name of the subject providing the MRI.
+ subject_to : str
+ New subject name for which to save the scaled MRI.
+ scale : float | array_like, shape = (3,)
+ The scaling factor (one or 3 parameters).
+ overwrite : bool
+ If an MRI already exists for subject_to, overwrite it.
+ subjects_dir : None | str
+ Override the SUBJECTS_DIR environment variable.
+ """
+ subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
+ paths = _find_mri_paths(subject_from, subjects_dir=subjects_dir)
+ scale = np.asarray(scale)
+
+ # make sure we have an empty target directory
+ dest = subject_dirname.format(subject=subject_to,
+ subjects_dir=subjects_dir)
+ if os.path.exists(dest):
+ if overwrite:
+ shutil.rmtree(dest)
+ else:
+ err = ("Subject directory for %s already exists: "
+ "%r" % (subject_to, dest))
+ raise IOError(err)
+
+ for dirname in paths['dirs']:
+ dir_ = dirname.format(subject=subject_to, subjects_dir=subjects_dir)
+ os.makedirs(dir_)
+
+ # save MRI scaling parameters
+ fname = os.path.join(dest, 'MRI scaling parameters.cfg')
+ _write_mri_config(fname, subject_from, subject_to, scale)
+
+ # surf files [in mm]
+ for fname in paths['surf']:
+ src = fname.format(subject=subject_from, subjects_dir=subjects_dir)
+ src = os.path.realpath(src)
+ dest = fname.format(subject=subject_to, subjects_dir=subjects_dir)
+ pts, tri = read_surface(src)
+ write_surface(dest, pts * scale, tri)
+
+ # BEM files [in m]
+ for fname in paths['bem']:
+ src = fname.format(subject=subject_from, subjects_dir=subjects_dir)
+ src = os.path.realpath(src)
+ surfs = read_bem_surfaces(src)
+ if len(surfs) != 1:
+ err = ("BEM file with more than one surface: %r" % src)
+ raise NotImplementedError(err)
+ surf0 = surfs[0]
+ surf0['rr'] = surf0['rr'] * scale
+ dest = fname.format(subject=subject_to, subjects_dir=subjects_dir)
+ write_bem_surface(dest, surf0)
+
+ # fiducials [in m]
+ for fname in paths['fid']:
+ src = fname.format(subject=subject_from, subjects_dir=subjects_dir)
+ src = os.path.realpath(src)
+ pts, cframe = read_fiducials(src)
+ for pt in pts:
+ pt['r'] = pt['r'] * scale
+ dest = fname.format(subject=subject_to, subjects_dir=subjects_dir)
+ write_fiducials(dest, pts, cframe)
+
+ # duplicate files
+ for fname in paths['duplicate']:
+ src = fname.format(subject=subject_from, subjects_dir=subjects_dir)
+ dest = fname.format(subject=subject_to, subjects_dir=subjects_dir)
+ shutil.copyfile(src, dest)
+
+ # source spaces
+ for fname in paths['src']:
+ src_name = os.path.basename(fname)
+ scale_source_space(subject_to, src_name, subject_from, scale,
+ subjects_dir)
+
+ # labels [in m]
+ scale_labels(subject_to, subject_from=subject_from, scale=scale,
+ subjects_dir=subjects_dir)
+
+
+def scale_source_space(subject_to, src_name, subject_from=None, scale=None,
+ subjects_dir=None):
+ """Scale a source space for an mri created with scale_mri()
+
+ Parameters
+ ----------
+ subject_to : str
+ Name of the scaled MRI subject (the destination mri subject).
+ src_name : str
+ Source space name. Can be a spacing parameter (e.g., ``'7'``,
+ ``'ico4'``, ``'oct6'``) or a file name of a source space file relative
+ to the bem directory; if the file name contains the subject name, it
+ should be indicated as "{subject}" in ``src_name`` (e.g.,
+ ``"{subject}-my_source_space-src.fif"``).
+ subject_from : None | str
+ The subject from which to read the source space. If None, subject_from
+ is read from subject_to's config file.
+ scale : None | float | array, shape = (3,)
+ Scaling factor. Has to be specified if subjects_from is specified,
+ otherwise it is read from subject_to's config file.
+ subjects_dir : None | str
+ Override the SUBJECTS_DIR environment variable.
+ """
+ subjects_dir = get_subjects_dir(subjects_dir, True)
+ if (subject_from is None) != (scale is None):
+ err = ("Need to provide either both subject_from and scale "
+ "parameters, or neither.")
+ raise TypeError(err)
+
+ if subject_from is None:
+ cfg = read_mri_cfg(subject_to, subjects_dir)
+ subject_from = cfg['subject_from']
+ n_params = cfg['n_params']
+ scale = cfg['scale']
+ else:
+ scale = np.asarray(scale)
+ if scale.ndim == 0:
+ n_params = 1
+ elif scale.shape == (3,):
+ n_params = 3
+ else:
+ err = ("Invalid shape for scale parameer. Need scalar or array of "
+ "length 3. Got %s." % str(scale))
+ raise ValueError(err)
+
+ # find the source space file names
+ if src_name.isdigit():
+ spacing = src_name # spacing in mm
+ src_pattern = src_fname
+ else:
+ match = re.match("(oct|ico)-?(\d+)$", src_name)
+ if match:
+ spacing = '-'.join(match.groups())
+ src_pattern = src_fname
+ else:
+ spacing = None
+ src_pattern = os.path.join(bem_dirname, src_name)
+
+ src = src_pattern.format(subjects_dir=subjects_dir, subject=subject_from,
+ spacing=spacing)
+ dst = src_pattern.format(subjects_dir=subjects_dir, subject=subject_to,
+ spacing=spacing)
+
+ # prepare scaling parameters
+ if n_params == 1:
+ norm_scale = None
+ elif n_params == 3:
+ norm_scale = 1. / scale
+ else:
+ err = ("Invalid n_params entry in MRI cfg file: %s" % str(n_params))
+ raise RuntimeError(err)
+
+ # read and scale the source space [in m]
+ sss = read_source_spaces(src)
+ logger.info("scaling source space %s: %s -> %s", spacing, subject_from,
+ subject_to)
+ logger.info("Scale factor: %s", scale)
+ for ss in sss:
+ ss['rr'] = ss['rr'] * scale
+ if norm_scale is not None:
+ nn = ss['nn'] * norm_scale
+ norm = np.sqrt(np.sum(nn ** 2, 1))
+ nn /= norm[:, np.newaxis]
+ ss['nn'] = nn
+
+ ss['dist'] = None
+ ss['dist_limit'] = None
+ ss['nearest_dist'] = None
+ write_source_spaces(dst, sss)
diff --git a/mne/cov.py b/mne/cov.py
index 2fa6077..af6c6b3 100644
--- a/mne/cov.py
+++ b/mne/cov.py
@@ -11,15 +11,14 @@ import warnings
import numpy as np
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
-from . import fiff, verbose
+from . import fiff
+from .utils import logger, verbose
from .fiff.write import start_file, end_file
-from .fiff.proj import make_projector, proj_equal, activate_proj
+from .fiff.proj import (make_projector, proj_equal, activate_proj,
+ _has_eeg_average_ref_proj)
from .fiff import fiff_open
-from .fiff.pick import pick_types, channel_indices_by_type, pick_channels_cov,\
- pick_channels
+from .fiff.pick import (pick_types, channel_indices_by_type, pick_channels_cov,
+ pick_channels)
from .fiff.constants import FIFF
from .epochs import _is_good
@@ -45,7 +44,7 @@ class Covariance(dict):
----------
data : array of shape (n_channels, n_channels)
The covariance.
- `ch_names` : list of string
+ ch_names : list of string
List of channels' names.
nfree : int
Number of degrees of freedom i.e. number of time points used.
@@ -123,9 +122,9 @@ class Covariance(dict):
"""Add Covariance taking into account number of degrees of freedom"""
_check_covs_algebra(self, cov)
this_cov = cp.deepcopy(cov)
- this_cov['data'] = ((this_cov['data'] * this_cov['nfree']) +
- (self['data'] * self['nfree'])) / \
- (self['nfree'] + this_cov['nfree'])
+ this_cov['data'] = (((this_cov['data'] * this_cov['nfree']) +
+ (self['data'] * self['nfree'])) /
+ (self['nfree'] + this_cov['nfree']))
this_cov['nfree'] += self['nfree']
this_cov['bads'] = list(set(this_cov['bads']).union(self['bads']))
@@ -135,9 +134,9 @@ class Covariance(dict):
def __iadd__(self, cov):
"""Add Covariance taking into account number of degrees of freedom"""
_check_covs_algebra(self, cov)
- self['data'][:] = ((self['data'] * self['nfree']) + \
- (cov['data'] * cov['nfree'])) / \
- (self['nfree'] + cov['nfree'])
+ self['data'][:] = (((self['data'] * self['nfree']) +
+ (cov['data'] * cov['nfree'])) /
+ (self['nfree'] + cov['nfree']))
self['nfree'] += cov['nfree']
self['bads'] = list(set(self['bads']).union(cov['bads']))
@@ -201,7 +200,7 @@ def compute_raw_data_covariance(raw, tmin=None, tmax=None, tstep=0.2,
tmax : float
End of time interval in seconds
tstep : float
- Size of data chunks for artefact rejection.
+ Length of data chunks for artefact rejection in seconds.
reject : dict
Rejection parameters based on peak to peak amplitude.
Valid keys are 'grad' | 'mag' | 'eeg' | 'eog' | 'ecg'.
@@ -241,7 +240,7 @@ def compute_raw_data_covariance(raw, tmin=None, tmax=None, tstep=0.2,
# don't exclude any bad channels, inverses expect all channels present
if picks is None:
picks = pick_types(raw.info, meg=True, eeg=True, eog=False,
- exclude=[])
+ ref_meg=False, exclude=[])
data = 0
n_samples = 0
@@ -380,7 +379,7 @@ def compute_covariance(epochs, keep_sample_mean=True, tmin=None, tmax=None,
n_epochs = np.zeros(n_epoch_types, dtype=np.int)
picks_meeg = pick_types(epochs[0].info, meg=True, eeg=True, eog=False,
- exclude=[])
+ ref_meg=False, exclude=[])
ch_names = [epochs[0].ch_names[k] for k in picks_meeg]
for i, epochs_t in enumerate(epochs):
@@ -439,7 +438,6 @@ def write_cov(fname, cov):
----------
fname : string
The name of the file
-
cov : Covariance
The noise covariance matrix
"""
@@ -510,8 +508,10 @@ def prepare_noise_cov(noise_cov, info, ch_names, verbose=None):
% ncomp)
C = np.dot(proj, np.dot(C, proj.T))
- pick_meg = pick_types(info, meg=True, eeg=False, exclude='bads')
- pick_eeg = pick_types(info, meg=False, eeg=True, exclude='bads')
+ pick_meg = pick_types(info, meg=True, eeg=False, ref_meg=False,
+ exclude='bads')
+ pick_eeg = pick_types(info, meg=False, eeg=True, ref_meg=False,
+ exclude='bads')
meg_names = [info['chs'][k]['ch_name'] for k in pick_meg]
C_meg_idx = [k for k in range(len(C)) if ch_names[k] in meg_names]
eeg_names = [info['chs'][k]['ch_name'] for k in pick_eeg]
@@ -527,6 +527,11 @@ def prepare_noise_cov(noise_cov, info, ch_names, verbose=None):
if has_eeg:
C_eeg = C[C_eeg_idx][:, C_eeg_idx]
C_eeg_eig, C_eeg_eigvec = _get_whitener(C_eeg, False, 'EEG')
+ if not _has_eeg_average_ref_proj(info['projs']):
+ warnings.warn('No average EEG reference present in info["projs"], '
+ 'covariance may be adversely affected. Consider '
+ 'recomputing covariance using a raw file with an '
+ 'average eeg reference projector added.')
n_chan = len(ch_names)
eigvec = np.zeros((n_chan, n_chan), dtype=np.float)
@@ -585,9 +590,12 @@ def regularize(cov, info, mag=0.1, grad=0.1, eeg=0.1, exclude=None,
if exclude is None:
exclude = info['bads'] + cov['bads']
- sel_eeg = pick_types(info, meg=False, eeg=True, exclude=exclude)
- sel_mag = pick_types(info, meg='mag', eeg=False, exclude=exclude)
- sel_grad = pick_types(info, meg='grad', eeg=False, exclude=exclude)
+ sel_eeg = pick_types(info, meg=False, eeg=True, ref_meg=False,
+ exclude=exclude)
+ sel_mag = pick_types(info, meg='mag', eeg=False, ref_meg=False,
+ exclude=exclude)
+ sel_grad = pick_types(info, meg='grad', eeg=False, ref_meg=False,
+ exclude=exclude)
info_ch_names = info['ch_names']
ch_names_eeg = [info_ch_names[i] for i in sel_eeg]
@@ -673,7 +681,8 @@ def compute_whitener(noise_cov, info, picks=None, verbose=None):
The channel names.
"""
if picks is None:
- picks = pick_types(info, meg=True, eeg=True, exclude='bads')
+ picks = pick_types(info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
ch_names = [info['chs'][k]['ch_name'] for k in picks]
diff --git a/mne/cuda.py b/mne/cuda.py
index bbcef0f..a299463 100644
--- a/mne/cuda.py
+++ b/mne/cuda.py
@@ -8,13 +8,11 @@ try:
import pycuda.gpuarray as gpuarray
from pycuda.driver import mem_get_info
from scikits.cuda import fft as cudafft
-except ImportError:
+except (ImportError, OSError):
+ # need OSError because scikits.cuda throws it if cufft not found
pass
-import logging
-logger = logging.getLogger('mne')
-
-from .utils import sizeof_fmt
+from .utils import sizeof_fmt, logger
# Support CUDA for FFTs; requires scikits.cuda and pycuda
@@ -86,7 +84,7 @@ def init_cuda():
try:
from scikits.cuda import fft as cudafft
except ImportError:
- logger.warn('modudle scikits.cuda not found, CUDA not '
+ logger.warn('module scikits.cuda not found, CUDA not '
'enabled')
else:
# Make sure we can use 64-bit FFTs
diff --git a/mne/data/coil_def.dat b/mne/data/coil_def.dat
new file mode 100644
index 0000000..61eea53
--- /dev/null
+++ b/mne/data/coil_def.dat
@@ -0,0 +1,416 @@
+#
+# MEG coil definition file
+#
+# Copyright 2005 - 2009
+#
+# Matti Hamalainen
+# Athinoula A. Martinos Center for Biomedical Imaging
+# Charlestown, MA, USA
+#
+#
+# <class> <id> <accuracy> <np> <size> <baseline> "<description>"
+#
+# struct class id accuracy num_points size baseline description
+# format '%d %d %d %d %e %e %s'
+#
+# <w_1> <x_1/m> <y_1/m> <z_1/m> <nx_1> <ny_1> <nz_1>
+#
+# struct w x y z nx ny nz
+# format '%f %e %e %e %e %e %e'
+#
+# ....
+#
+# <w_np> <x_np/m> <y_np/m> <z_np/m> <nx_np> <ny_np> <nz_np>
+#
+# <class> 1 magnetometer
+# 2 axial gradiometer
+# 3 planar gradiometer
+# 4 axial second-order gradiometer
+#
+# <accuracy> 0 point approximation
+# 1 normal
+# 2 accurate
+#
+# Produced with:
+#
+# mne_list_coil_def version 1.12 compiled at Feb 4 2013 04:18:14
+#
+3 2 0 2 2.789e-02 1.620e-02 "Neuromag-122 planar gradiometer size = 27.89 mm base = 16.20 mm"
+ 61.7284 8.100e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+-61.7284 -8.100e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+3 2 1 2 2.789e-02 1.620e-02 "Neuromag-122 planar gradiometer size = 27.89 mm base = 16.20 mm"
+ 61.7284 8.100e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+-61.7284 -8.100e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+3 2 2 8 2.789e-02 1.620e-02 "Neuromag-122 planar gradiometer size = 27.89 mm base = 16.20 mm"
+ 15.1057 1.111e-02 7.680e-03 0.000e+00 0.000 0.000 1.000
+ 15.1057 5.440e-03 7.680e-03 0.000e+00 0.000 0.000 1.000
+ 15.1057 5.440e-03 -7.680e-03 0.000e+00 0.000 0.000 1.000
+ 15.1057 1.111e-02 -7.680e-03 0.000e+00 0.000 0.000 1.000
+-15.1057 -1.111e-02 7.680e-03 0.000e+00 0.000 0.000 1.000
+-15.1057 -5.440e-03 7.680e-03 0.000e+00 0.000 0.000 1.000
+-15.1057 -5.440e-03 -7.680e-03 0.000e+00 0.000 0.000 1.000
+-15.1057 -1.111e-02 -7.680e-03 0.000e+00 0.000 0.000 1.000
+1 2000 0 1 0.000e+00 0.000e+00 "Point magnetometer"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+1 2000 1 1 0.000e+00 0.000e+00 "Point magnetometer"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+1 2000 2 1 0.000e+00 0.000e+00 "Point magnetometer"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+3 3012 0 2 2.639e-02 1.680e-02 "Vectorview planar gradiometer T1 size = 26.39 mm base = 16.80 mm"
+ 59.5238 8.400e-03 0.000e+00 3.000e-04 0.000 0.000 1.000
+-59.5238 -8.400e-03 0.000e+00 3.000e-04 0.000 0.000 1.000
+3 3012 1 4 2.639e-02 1.680e-02 "Vectorview planar gradiometer T1 size = 26.39 mm base = 16.80 mm"
+ 29.7619 8.400e-03 6.713e-03 3.000e-04 0.000 0.000 1.000
+ 29.7619 8.400e-03 -6.713e-03 3.000e-04 0.000 0.000 1.000
+-29.7619 -8.400e-03 6.713e-03 3.000e-04 0.000 0.000 1.000
+-29.7619 -8.400e-03 -6.713e-03 3.000e-04 0.000 0.000 1.000
+3 3012 2 8 2.639e-02 1.680e-02 "Vectorview planar gradiometer T1 size = 26.39 mm base = 16.80 mm"
+ 14.9858 1.079e-02 6.713e-03 3.000e-04 0.000 0.000 1.000
+ 14.9858 5.891e-03 6.713e-03 3.000e-04 0.000 0.000 1.000
+ 14.9858 5.891e-03 -6.713e-03 3.000e-04 0.000 0.000 1.000
+ 14.9858 1.079e-02 -6.713e-03 3.000e-04 0.000 0.000 1.000
+-14.9858 -1.079e-02 6.713e-03 3.000e-04 0.000 0.000 1.000
+-14.9858 -5.891e-03 6.713e-03 3.000e-04 0.000 0.000 1.000
+-14.9858 -5.891e-03 -6.713e-03 3.000e-04 0.000 0.000 1.000
+-14.9858 -1.079e-02 -6.713e-03 3.000e-04 0.000 0.000 1.000
+3 3013 0 2 2.639e-02 1.680e-02 "Vectorview planar gradiometer T2 size = 26.39 mm base = 16.80 mm"
+ 59.5238 8.400e-03 0.000e+00 3.000e-04 0.000 0.000 1.000
+-59.5238 -8.400e-03 0.000e+00 3.000e-04 0.000 0.000 1.000
+3 3013 1 4 2.639e-02 1.680e-02 "Vectorview planar gradiometer T2 size = 26.39 mm base = 16.80 mm"
+ 29.7619 8.400e-03 6.713e-03 3.000e-04 0.000 0.000 1.000
+ 29.7619 8.400e-03 -6.713e-03 3.000e-04 0.000 0.000 1.000
+-29.7619 -8.400e-03 6.713e-03 3.000e-04 0.000 0.000 1.000
+-29.7619 -8.400e-03 -6.713e-03 3.000e-04 0.000 0.000 1.000
+3 3013 2 8 2.639e-02 1.680e-02 "Vectorview planar gradiometer T2 size = 26.39 mm base = 16.80 mm"
+ 14.9858 1.079e-02 6.713e-03 3.000e-04 0.000 0.000 1.000
+ 14.9858 5.891e-03 6.713e-03 3.000e-04 0.000 0.000 1.000
+ 14.9858 5.891e-03 -6.713e-03 3.000e-04 0.000 0.000 1.000
+ 14.9858 1.079e-02 -6.713e-03 3.000e-04 0.000 0.000 1.000
+-14.9858 -1.079e-02 6.713e-03 3.000e-04 0.000 0.000 1.000
+-14.9858 -5.891e-03 6.713e-03 3.000e-04 0.000 0.000 1.000
+-14.9858 -5.891e-03 -6.713e-03 3.000e-04 0.000 0.000 1.000
+-14.9858 -1.079e-02 -6.713e-03 3.000e-04 0.000 0.000 1.000
+1 3022 0 1 2.580e-02 0.000e+00 "Vectorview magnetometer T1 size = 25.80 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+1 3022 1 4 2.580e-02 0.000e+00 "Vectorview magnetometer T1 size = 25.80 mm"
+ 0.2500 -6.450e-03 -6.450e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 -6.450e-03 6.450e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 6.450e-03 -6.450e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 6.450e-03 6.450e-03 3.000e-04 0.000 0.000 1.000
+1 3022 2 16 2.580e-02 0.000e+00 "Vectorview magnetometer T1 size = 25.80 mm"
+ 0.0625 -9.675e-03 -9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -9.675e-03 -3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -9.675e-03 3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -9.675e-03 9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -3.225e-03 -9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -3.225e-03 -3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -3.225e-03 3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -3.225e-03 9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 3.225e-03 -9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 3.225e-03 -3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 3.225e-03 3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 3.225e-03 9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 9.675e-03 -9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 9.675e-03 -3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 9.675e-03 3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 9.675e-03 9.675e-03 3.000e-04 0.000 0.000 1.000
+1 3023 0 1 2.580e-02 0.000e+00 "Vectorview magnetometer T2 size = 25.80 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+1 3023 1 4 2.580e-02 0.000e+00 "Vectorview magnetometer T2 size = 25.80 mm"
+ 0.2500 -6.450e-03 -6.450e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 -6.450e-03 6.450e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 6.450e-03 -6.450e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 6.450e-03 6.450e-03 3.000e-04 0.000 0.000 1.000
+1 3023 2 16 2.580e-02 0.000e+00 "Vectorview magnetometer T2 size = 25.80 mm"
+ 0.0625 -9.675e-03 -9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -9.675e-03 -3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -9.675e-03 3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -9.675e-03 9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -3.225e-03 -9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -3.225e-03 -3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -3.225e-03 3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -3.225e-03 9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 3.225e-03 -9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 3.225e-03 -3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 3.225e-03 3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 3.225e-03 9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 9.675e-03 -9.675e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 9.675e-03 -3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 9.675e-03 3.225e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 9.675e-03 9.675e-03 3.000e-04 0.000 0.000 1.000
+1 3024 0 1 2.100e-02 0.000e+00 "Vectorview magnetometer T3 size = 21.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+1 3024 1 4 2.100e-02 0.000e+00 "Vectorview magnetometer T3 size = 21.00 mm"
+ 0.2500 -5.250e-03 -5.250e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 -5.250e-03 5.250e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 5.250e-03 -5.250e-03 3.000e-04 0.000 0.000 1.000
+ 0.2500 5.250e-03 5.250e-03 3.000e-04 0.000 0.000 1.000
+1 3024 2 16 2.100e-02 0.000e+00 "Vectorview magnetometer T3 size = 21.00 mm"
+ 0.0625 -7.875e-03 -7.875e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -7.875e-03 -2.625e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -7.875e-03 2.625e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -7.875e-03 7.875e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -2.625e-03 -7.875e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -2.625e-03 -2.625e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -2.625e-03 2.625e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 -2.625e-03 7.875e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 2.625e-03 -7.875e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 2.625e-03 -2.625e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 2.625e-03 2.625e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 2.625e-03 7.875e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 7.875e-03 -7.875e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 7.875e-03 -2.625e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 7.875e-03 2.625e-03 3.000e-04 0.000 0.000 1.000
+ 0.0625 7.875e-03 7.875e-03 3.000e-04 0.000 0.000 1.000
+1 4001 0 1 2.300e-02 0.000e+00 "Magnes WH2500 magnetometer size = 23.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+1 4001 1 4 2.300e-02 0.000e+00 "Magnes WH2500 magnetometer size = 23.00 mm"
+ 0.2500 5.750e-03 5.750e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -5.750e-03 5.750e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -5.750e-03 -5.750e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 5.750e-03 -5.750e-03 0.000e+00 0.000 0.000 1.000
+1 4001 2 7 2.300e-02 0.000e+00 "Magnes WH2500 magnetometer size = 23.00 mm"
+ 0.2500 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 9.390e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 -9.390e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 4.695e-03 8.132e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 4.695e-03 -8.132e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 -4.695e-03 8.132e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 -4.695e-03 -8.132e-03 0.000e+00 0.000 0.000 1.000
+2 4002 0 2 1.800e-02 5.000e-02 "Magnes WH3600 gradiometer size = 18.00 mm base = 50.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 0.000e+00 0.000e+00 5.000e-02 0.000 0.000 1.000
+2 4002 1 8 1.800e-02 5.000e-02 "Magnes WH3600 gradiometer size = 18.00 mm base = 50.00 mm"
+ 0.2500 4.500e-03 4.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -4.500e-03 4.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -4.500e-03 -4.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.500e-03 -4.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 4.500e-03 4.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 -4.500e-03 4.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 -4.500e-03 -4.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 4.500e-03 -4.500e-03 5.000e-02 0.000 0.000 1.000
+2 4002 2 14 1.800e-02 5.000e-02 "Magnes WH3600 gradiometer size = 18.00 mm base = 50.00 mm"
+ 0.2500 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 7.348e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 -7.348e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 3.674e-03 6.364e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 3.674e-03 -6.364e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 -3.674e-03 6.364e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 -3.674e-03 -6.364e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 0.000e+00 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 7.348e-03 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 -7.348e-03 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 3.674e-03 6.364e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 3.674e-03 -6.364e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 -3.674e-03 6.364e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 -3.674e-03 -6.364e-03 5.000e-02 0.000 0.000 1.000
+1 4003 0 1 3.000e-02 0.000e+00 "Magnes reference magnetometer size = 30.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+1 4003 1 4 3.000e-02 0.000e+00 "Magnes reference magnetometer size = 30.00 mm"
+ 0.2500 7.500e-03 7.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -7.500e-03 7.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -7.500e-03 -7.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 7.500e-03 -7.500e-03 0.000e+00 0.000 0.000 1.000
+1 4003 2 4 3.000e-02 0.000e+00 "Magnes reference magnetometer size = 30.00 mm"
+ 0.2500 7.500e-03 7.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -7.500e-03 7.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -7.500e-03 -7.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 7.500e-03 -7.500e-03 0.000e+00 0.000 0.000 1.000
+2 4004 0 2 8.000e-02 1.350e-01 "Magnes reference gradiometer (diag) size = 80.00 mm base = 135.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 0.000e+00 0.000e+00 1.350e-01 0.000 0.000 1.000
+2 4004 1 8 8.000e-02 1.350e-01 "Magnes reference gradiometer (diag) size = 80.00 mm base = 135.00 mm"
+ 0.2500 2.000e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 -2.000e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 -2.000e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 2.000e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 2.000e-02 2.000e-02 1.350e-01 0.000 0.000 1.000
+ -0.2500 -2.000e-02 2.000e-02 1.350e-01 0.000 0.000 1.000
+ -0.2500 -2.000e-02 -2.000e-02 1.350e-01 0.000 0.000 1.000
+ -0.2500 2.000e-02 -2.000e-02 1.350e-01 0.000 0.000 1.000
+2 4004 2 8 8.000e-02 1.350e-01 "Magnes reference gradiometer (diag) size = 80.00 mm base = 135.00 mm"
+ 0.2500 2.000e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 -2.000e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 -2.000e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 2.000e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 2.000e-02 2.000e-02 1.350e-01 0.000 0.000 1.000
+ -0.2500 -2.000e-02 2.000e-02 1.350e-01 0.000 0.000 1.000
+ -0.2500 -2.000e-02 -2.000e-02 1.350e-01 0.000 0.000 1.000
+ -0.2500 2.000e-02 -2.000e-02 1.350e-01 0.000 0.000 1.000
+2 4005 0 2 8.000e-02 1.350e-01 "Magnes reference gradiometer (offdiag) size = 80.00 mm base = 135.00 mm"
+ 1.0000 6.750e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 -6.750e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+2 4005 1 8 8.000e-02 1.350e-01 "Magnes reference gradiometer (offdiag) size = 80.00 mm base = 135.00 mm"
+ 0.2500 8.750e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.750e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.750e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 8.750e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 -4.750e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 -8.750e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 -8.750e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 -4.750e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+2 4005 2 8 8.000e-02 1.350e-01 "Magnes reference gradiometer (offdiag) size = 80.00 mm base = 135.00 mm"
+ 0.2500 8.750e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.750e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.750e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ 0.2500 8.750e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 -4.750e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 -8.750e-02 2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 -8.750e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+ -0.2500 -4.750e-02 -2.000e-02 0.000e+00 0.000 0.000 1.000
+2 5001 0 2 1.800e-02 5.000e-02 "CTF axial gradiometer size = 18.00 mm base = 50.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 0.000e+00 0.000e+00 5.000e-02 0.000 0.000 1.000
+2 5001 1 8 1.800e-02 5.000e-02 "CTF axial gradiometer size = 18.00 mm base = 50.00 mm"
+ 0.2500 4.500e-03 4.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -4.500e-03 4.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -4.500e-03 -4.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.500e-03 -4.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 4.500e-03 4.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 -4.500e-03 4.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 -4.500e-03 -4.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 4.500e-03 -4.500e-03 5.000e-02 0.000 0.000 1.000
+2 5001 2 14 1.800e-02 5.000e-02 "CTF axial gradiometer size = 18.00 mm base = 50.00 mm"
+ 0.2500 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 7.348e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 -7.348e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 3.674e-03 6.364e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 3.674e-03 -6.364e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 -3.674e-03 6.364e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 -3.674e-03 -6.364e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 0.000e+00 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 7.348e-03 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 -7.348e-03 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 3.674e-03 6.364e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 3.674e-03 -6.364e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 -3.674e-03 6.364e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 -3.674e-03 -6.364e-03 5.000e-02 0.000 0.000 1.000
+1 5002 0 1 1.600e-02 0.000e+00 "CTF reference magnetometer size = 16.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+1 5002 1 4 1.600e-02 0.000e+00 "CTF reference magnetometer size = 16.00 mm"
+ 0.2500 4.000e-03 4.000e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -4.000e-03 4.000e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -4.000e-03 -4.000e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.000e-03 -4.000e-03 0.000e+00 0.000 0.000 1.000
+1 5002 2 4 1.600e-02 0.000e+00 "CTF reference magnetometer size = 16.00 mm"
+ 0.2500 4.000e-03 4.000e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -4.000e-03 4.000e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -4.000e-03 -4.000e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.000e-03 -4.000e-03 0.000e+00 0.000 0.000 1.000
+2 5003 0 2 3.440e-02 7.860e-02 "CTF reference gradiometer (diag) size = 34.40 mm base = 78.60 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 0.000e+00 0.000e+00 7.860e-02 0.000 0.000 1.000
+2 5003 1 8 3.440e-02 7.860e-02 "CTF reference gradiometer (diag) size = 34.40 mm base = 78.60 mm"
+ 0.2500 8.600e-03 8.600e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -8.600e-03 8.600e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -8.600e-03 -8.600e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 8.600e-03 -8.600e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 8.600e-03 8.600e-03 7.860e-02 0.000 0.000 1.000
+ -0.2500 -8.600e-03 8.600e-03 7.860e-02 0.000 0.000 1.000
+ -0.2500 -8.600e-03 -8.600e-03 7.860e-02 0.000 0.000 1.000
+ -0.2500 8.600e-03 -8.600e-03 7.860e-02 0.000 0.000 1.000
+2 5003 2 8 3.440e-02 7.860e-02 "CTF reference gradiometer (diag) size = 34.40 mm base = 78.60 mm"
+ 0.2500 8.600e-03 8.600e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -8.600e-03 8.600e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -8.600e-03 -8.600e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 8.600e-03 -8.600e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 8.600e-03 8.600e-03 7.860e-02 0.000 0.000 1.000
+ -0.2500 -8.600e-03 8.600e-03 7.860e-02 0.000 0.000 1.000
+ -0.2500 -8.600e-03 -8.600e-03 7.860e-02 0.000 0.000 1.000
+ -0.2500 8.600e-03 -8.600e-03 7.860e-02 0.000 0.000 1.000
+2 5004 0 2 3.440e-02 7.860e-02 "CTF reference gradiometer (offdiag) size = 34.40 mm base = 78.60 mm"
+ 1.0000 3.930e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 -3.930e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+2 5004 1 8 3.440e-02 7.860e-02 "CTF reference gradiometer (offdiag) size = 34.40 mm base = 78.60 mm"
+ 0.2500 4.780e-02 8.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 3.080e-02 8.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 3.080e-02 -8.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.780e-02 -8.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 -3.080e-02 8.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 -4.780e-02 8.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 -4.780e-02 -8.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 -3.080e-02 -8.500e-03 0.000e+00 0.000 0.000 1.000
+2 5004 2 8 3.440e-02 7.860e-02 "CTF reference gradiometer (offdiag) size = 34.40 mm base = 78.60 mm"
+ 0.2500 4.780e-02 8.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 3.080e-02 8.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 3.080e-02 -8.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 4.780e-02 -8.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 -3.080e-02 8.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 -4.780e-02 8.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 -4.780e-02 -8.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 -3.080e-02 -8.500e-03 0.000e+00 0.000 0.000 1.000
+2 6001 0 2 1.550e-02 5.000e-02 "MIT KIT system gradiometer size = 15.50 mm base = 50.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 0.000e+00 0.000e+00 5.000e-02 0.000 0.000 1.000
+2 6001 1 8 1.550e-02 5.000e-02 "MIT KIT system gradiometer size = 15.50 mm base = 50.00 mm"
+ 0.2500 3.875e-03 3.875e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -3.875e-03 3.875e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -3.875e-03 -3.875e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 3.875e-03 -3.875e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 3.875e-03 3.875e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 -3.875e-03 3.875e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 -3.875e-03 -3.875e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 3.875e-03 -3.875e-03 5.000e-02 0.000 0.000 1.000
+2 6001 2 14 1.550e-02 5.000e-02 "MIT KIT system gradiometer size = 15.50 mm base = 50.00 mm"
+ 0.2500 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 6.328e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 -6.328e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 0.1250 3.164e-03 5.480e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 3.164e-03 -5.480e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 -3.164e-03 5.480e-03 0.000e+00 0.000 0.000 1.000
+ 0.1250 -3.164e-03 -5.480e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 0.000e+00 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 6.328e-03 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 -6.328e-03 0.000e+00 5.000e-02 0.000 0.000 1.000
+ -0.1250 3.164e-03 5.480e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 3.164e-03 -5.480e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 -3.164e-03 5.480e-03 5.000e-02 0.000 0.000 1.000
+ -0.1250 -3.164e-03 -5.480e-03 5.000e-02 0.000 0.000 1.000
+2 7001 0 2 6.000e-03 5.000e-02 "BabySQUID system gradiometer size = 6.00 mm base = 50.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 0.000e+00 0.000e+00 5.000e-02 0.000 0.000 1.000
+2 7001 1 2 6.000e-03 5.000e-02 "BabySQUID system gradiometer size = 6.00 mm base = 50.00 mm"
+ 1.0000 0.000e+00 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.0000 0.000e+00 0.000e+00 5.000e-02 0.000 0.000 1.000
+2 7001 2 8 6.000e-03 5.000e-02 "BabySQUID system gradiometer size = 6.00 mm base = 50.00 mm"
+ 0.2500 1.500e-03 1.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -1.500e-03 1.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 -1.500e-03 -1.500e-03 0.000e+00 0.000 0.000 1.000
+ 0.2500 1.500e-03 -1.500e-03 0.000e+00 0.000 0.000 1.000
+ -0.2500 1.500e-03 1.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 -1.500e-03 1.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 -1.500e-03 -1.500e-03 5.000e-02 0.000 0.000 1.000
+ -0.2500 1.500e-03 -1.500e-03 5.000e-02 0.000 0.000 1.000
+3 8001 0 2 7.000e-02 7.500e-02 "Sample TMS figure-of-eight coil size = 70.00 mm base = 75.00 mm"
+ 13.3333 3.750e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+-13.3333 -3.750e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+3 8001 1 14 7.000e-02 7.500e-02 "Sample TMS figure-of-eight coil size = 70.00 mm base = 75.00 mm"
+ 3.3333 3.750e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 1.6667 6.608e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 1.6667 8.923e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 1.6667 5.179e-02 2.475e-02 0.000e+00 0.000 0.000 1.000
+ 1.6667 5.179e-02 -2.475e-02 0.000e+00 0.000 0.000 1.000
+ 1.6667 2.321e-02 2.475e-02 0.000e+00 0.000 0.000 1.000
+ 1.6667 2.321e-02 -2.475e-02 0.000e+00 0.000 0.000 1.000
+ -3.3333 -3.750e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.6667 -8.923e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.6667 -6.608e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.6667 -2.321e-02 2.475e-02 0.000e+00 0.000 0.000 1.000
+ -1.6667 -2.321e-02 -2.475e-02 0.000e+00 0.000 0.000 1.000
+ -1.6667 -5.179e-02 2.475e-02 0.000e+00 0.000 0.000 1.000
+ -1.6667 -5.179e-02 -2.475e-02 0.000e+00 0.000 0.000 1.000
+3 8001 2 14 7.000e-02 7.500e-02 "Sample TMS figure-of-eight coil size = 70.00 mm base = 75.00 mm"
+ 3.3333 3.750e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 1.6667 6.608e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 1.6667 8.923e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ 1.6667 5.179e-02 2.475e-02 0.000e+00 0.000 0.000 1.000
+ 1.6667 5.179e-02 -2.475e-02 0.000e+00 0.000 0.000 1.000
+ 1.6667 2.321e-02 2.475e-02 0.000e+00 0.000 0.000 1.000
+ 1.6667 2.321e-02 -2.475e-02 0.000e+00 0.000 0.000 1.000
+ -3.3333 -3.750e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.6667 -8.923e-03 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.6667 -6.608e-02 0.000e+00 0.000e+00 0.000 0.000 1.000
+ -1.6667 -2.321e-02 2.475e-02 0.000e+00 0.000 0.000 1.000
+ -1.6667 -2.321e-02 -2.475e-02 0.000e+00 0.000 0.000 1.000
+ -1.6667 -5.179e-02 2.475e-02 0.000e+00 0.000 0.000 1.000
+ -1.6667 -5.179e-02 -2.475e-02 0.000e+00 0.000 0.000 1.000
diff --git a/mne/datasets/__init__.py b/mne/datasets/__init__.py
index 263dfb2..015d34c 100644
--- a/mne/datasets/__init__.py
+++ b/mne/datasets/__init__.py
@@ -3,3 +3,4 @@
from . import sample
from . import megsim
+from . import spm_face
\ No newline at end of file
diff --git a/mne/datasets/megsim/megsim.py b/mne/datasets/megsim/megsim.py
index 2fc0f79..f7b86ed 100644
--- a/mne/datasets/megsim/megsim.py
+++ b/mne/datasets/megsim/megsim.py
@@ -6,12 +6,9 @@ from os import path as op
import zipfile
from sys import stdout
-import logging
-logger = logging.getLogger('mne')
-
from ...utils import _fetch_file, get_config, set_config, _url_to_local_path
-from .urls import url_match, valid_data_types, valid_data_formats, \
- valid_conditions
+from .urls import (url_match, valid_data_types, valid_data_formats,
+ valid_conditions)
def data_path(url, path=None, force_update=False, update_path=None):
diff --git a/mne/datasets/sample/__init__.py b/mne/datasets/sample/__init__.py
index c727c82..1f06c2d 100644
--- a/mne/datasets/sample/__init__.py
+++ b/mne/datasets/sample/__init__.py
@@ -1,4 +1,4 @@
"""MNE sample dataset
"""
-from .sample import data_path
+from .sample import data_path, has_sample_data, requires_sample_data
diff --git a/mne/datasets/sample/sample.py b/mne/datasets/sample/sample.py
index 708dcec..8a2eb30 100644
--- a/mne/datasets/sample/sample.py
+++ b/mne/datasets/sample/sample.py
@@ -3,133 +3,29 @@
# Eric Larson <larson.eric.d at gmail.com>
# License: BSD Style.
-import os
-import os.path as op
-import shutil
-from warnings import warn
-
-import logging
-logger = logging.getLogger('mne')
-
-from ... import __version__ as mne_version
-from ...utils import get_config, set_config, _fetch_file
-
-
-def _sample_version(path):
- """Get the version of the Sample dataset"""
- ver_fname = op.join(path, 'version.txt')
- if op.exists(ver_fname):
- fid = open(ver_fname, 'r')
- version = fid.readline().strip() # version is on first line
- fid.close()
- else:
- # Sample dataset versioning was introduced after 0.3
- version = '0.3'
-
- return version
-
-
-def data_path(path=None, force_update=False, update_path=True):
- """Get path to local copy of Sample dataset
-
- Parameters
- ----------
- path : None | str
- Location of where to look for the sample dataset.
- If None, the environment variable or config parameter
- MNE_DATASETS_SAMPLE_PATH is used. If it doesn't exist, the
- "mne-python/examples" directory is used. If the sample dataset
- is not found under the given path (e.g., as
- "mne-python/examples/MNE-sample-data"), the data
- will be automatically downloaded to the specified folder.
- force_update : bool
- Force update of the sample dataset even if a local copy exists.
- update_path : bool | None
- If True, set the MNE_DATASETS_SAMPLE_PATH in mne-python
- config to the given path. If None, the user is prompted.
- """
- if path is None:
- # use an intelligent guess if it's not defined
- def_path = op.abspath(op.join(op.dirname(__file__), '..', '..',
- '..', 'examples'))
- path = get_config('MNE_DATASETS_SAMPLE_PATH', def_path)
-
- if not isinstance(path, basestring):
- raise ValueError('path must be a string or None')
-
- archive_name = "MNE-sample-data-processed.tar.gz"
- url = "ftp://surfer.nmr.mgh.harvard.edu/pub/data/" + archive_name
- folder_name = "MNE-sample-data"
- folder_path = op.join(path, folder_name)
- rm_archive = False
-
- martinos_path = '/cluster/fusion/sample_data/' + archive_name
- neurospin_path = '/neurospin/tmp/gramfort/' + archive_name
-
- if not op.exists(folder_path) or force_update:
- logger.info('Sample data archive %s not found at:\n%s\n'
- 'It will be downloaded and extracted at this location.'
- % (archive_name, folder_path))
-
- if op.exists(martinos_path):
- archive_name = martinos_path
- elif op.exists(neurospin_path):
- archive_name = neurospin_path
- else:
- archive_name = op.join(path, archive_name)
- rm_archive = True
- if op.exists(archive_name):
- msg = ('Archive already exists at %r. Overwrite it '
- '(y/[n])? ' % archive_name)
- answer = raw_input(msg)
- if answer.lower() == 'y':
- os.remove(archive_name)
- else:
- raise IOError('Archive file already exists at target '
- 'location %r.' % archive_name)
-
- _fetch_file(url, archive_name, print_destination=False)
-
- if op.exists(folder_path):
- shutil.rmtree(folder_path)
-
- import tarfile
- # note that we use print statements here because these processes
- # are interactive
- logger.info('Decompressiong the archive: ' + archive_name)
- tarfile.open(archive_name, 'r:gz').extractall(path=path)
- if rm_archive:
- os.remove(archive_name)
-
- path = op.abspath(path)
- if update_path is None:
- if get_config('MNE_DATASETS_SAMPLE_PATH', '') != path:
- update_path = True
- msg = ('Do you want to set the path:\n %s\nas the default '
- 'sample dataset path in the mne-python config [y]/n? '
- % path)
- answer = raw_input(msg)
- if answer.lower() == 'n':
- update_path = False
- else:
- update_path = False
- if update_path is True:
- set_config('MNE_DATASETS_SAMPLE_PATH', path)
-
- path = op.join(path, folder_name)
-
- # compare the version of the Sample dataset and mne
- sample_version = _sample_version(path)
- try:
- from distutils.version import LooseVersion
- except:
- warn('Could not determine sample dataset version; dataset could\n'
- 'be out of date. Please install the "distutils" package.')
- else:
- if LooseVersion(sample_version) < LooseVersion(mne_version):
- warn('Sample dataset (version %s) is older than mne-python '
- '(version %s). If the examples fail, you may need to update '
- 'the sample dataset by using force_update=True'
- % (sample_version, mne_version))
-
- return path
+import numpy as np
+
+from ...utils import get_config, verbose
+from ...fixes import partial
+from ..utils import has_dataset, _data_path, _doc
+
+has_sample_data = partial(has_dataset, name='sample')
+
+ at verbose
+def data_path(path=None, force_update=False, update_path=True,
+ download=True, verbose=None):
+ return _data_path(path=path, force_update=force_update,
+ update_path=update_path, name='sample',
+ download=download,
+ verbose=verbose)
+
+data_path.__doc__ = _doc.format(name='sample',
+ conf='MNE_DATASETS_SAMPLE_PATH')
+
+# Allow forcing of sample dataset skip (for tests) using:
+# `make test-no-sample`
+has_sample_data = has_dataset('sample')
+skip_sample = get_config('MNE_SKIP_SAMPLE_DATASET_TESTS', 'false') == 'true'
+requires_sample_data = np.testing.dec.skipif(not has_sample_data
+ or skip_sample,
+ 'Requires sample dataset')
diff --git a/mne/datasets/spm_face/__init__.py b/mne/datasets/spm_face/__init__.py
new file mode 100644
index 0000000..3a44b6e
--- /dev/null
+++ b/mne/datasets/spm_face/__init__.py
@@ -0,0 +1,4 @@
+"""MNE sample dataset
+"""
+
+from .spm_data import data_path, has_spm_data, requires_spm_data
diff --git a/mne/datasets/spm_face/spm_data.py b/mne/datasets/spm_face/spm_data.py
new file mode 100644
index 0000000..c744026
--- /dev/null
+++ b/mne/datasets/spm_face/spm_data.py
@@ -0,0 +1,30 @@
+# Authors: Denis Engemann <d.engemann at fz-juelich.de>
+#
+# License: BSD Style.
+
+import numpy as np
+
+from ...utils import get_config, verbose
+from ...fixes import partial
+from ..utils import has_dataset, _data_path, _doc
+
+has_spm_data = partial(has_dataset, name='spm')
+
+ at verbose
+def data_path(path=None, force_update=False, update_path=True,
+ download=True, verbose=None):
+ return _data_path(path=path, force_update=force_update,
+ update_path=update_path, name='spm',
+ download=download,
+ verbose=verbose)
+
+data_path.__doc__ = _doc.format(name='spm',
+ conf='MNE_DATASETS_SPM_DATA_PATH')
+
+# Allow forcing of sample dataset skip (for tests) using:
+# `make test-no-sample`
+skip_spm = get_config('MNE_SKIP_SPM_DATASET_TESTS', 'false') == 'true'
+has_spm_data = has_dataset('spm')
+requires_spm_data = np.testing.dec.skipif(not has_spm_data
+ or skip_spm,
+ 'Requires spm dataset')
diff --git a/mne/datasets/sample/sample.py b/mne/datasets/utils.py
similarity index 53%
copy from mne/datasets/sample/sample.py
copy to mne/datasets/utils.py
index 708dcec..6b24081 100644
--- a/mne/datasets/sample/sample.py
+++ b/mne/datasets/utils.py
@@ -1,71 +1,107 @@
# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
# Eric Larson <larson.eric.d at gmail.com>
+# Denis Egnemann <d.engemann at fz-juelich.de>
# License: BSD Style.
import os
import os.path as op
import shutil
+import tarfile
from warnings import warn
-import logging
-logger = logging.getLogger('mne')
+from .. import __version__ as mne_version
+from ..utils import get_config, set_config, _fetch_file, logger
-from ... import __version__ as mne_version
-from ...utils import get_config, set_config, _fetch_file
-
-def _sample_version(path):
- """Get the version of the Sample dataset"""
- ver_fname = op.join(path, 'version.txt')
- if op.exists(ver_fname):
- fid = open(ver_fname, 'r')
- version = fid.readline().strip() # version is on first line
- fid.close()
- else:
- # Sample dataset versioning was introduced after 0.3
- version = '0.3'
-
- return version
-
-
-def data_path(path=None, force_update=False, update_path=True):
- """Get path to local copy of Sample dataset
+_doc = """Get path to local copy of {name} dataset
Parameters
----------
path : None | str
- Location of where to look for the sample dataset.
+ Location of where to look for the {name} dataset.
If None, the environment variable or config parameter
- MNE_DATASETS_SAMPLE_PATH is used. If it doesn't exist, the
+ {conf} is used. If it doesn't exist, the
"mne-python/examples" directory is used. If the sample dataset
is not found under the given path (e.g., as
- "mne-python/examples/MNE-sample-data"), the data
+ "mne-python/examples/MNE-{name}-data"), the data
will be automatically downloaded to the specified folder.
force_update : bool
Force update of the sample dataset even if a local copy exists.
update_path : bool | None
- If True, set the MNE_DATASETS_SAMPLE_PATH in mne-python
+ If True, set the {conf} in mne-python
config to the given path. If None, the user is prompted.
+ download : bool
+ If False and the {name} dataset has not been downloaded yet,
+ it will not be downloaded and the path will be returned as
+ '' (empty string). This is mostly used for debugging purposes
+ and can be safely ignored by most users.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ path : str
+ Path to {name} dataset directory.
+"""
+
+
+def _dataset_version(path, name):
+ """Get the version of the dataset"""
+ ver_fname = op.join(path, 'version.txt')
+ if op.exists(ver_fname):
+ fid = open(ver_fname, 'r')
+ version = fid.readline().strip() # version is on first line
+ fid.close()
+ else:
+ # Sample dataset versioning was introduced after 0.3
+ # SPM dataset was introduced after 0.6
+ version = '0.3' if name == 'sample' else '0.6'
+
+ return version
+
+
+def _data_path(path=None, force_update=False, update_path=True,
+ download=True, name=None, verbose=None):
+ """Aux function
"""
+ key = {'sample': 'MNE_DATASETS_SAMPLE_PATH',
+ 'spm': 'MNE_DATASETS_SPM_FACE_PATH'}[name]
+
if path is None:
# use an intelligent guess if it's not defined
- def_path = op.abspath(op.join(op.dirname(__file__), '..', '..',
- '..', 'examples'))
- path = get_config('MNE_DATASETS_SAMPLE_PATH', def_path)
+ def_path = op.realpath(op.join(op.dirname(__file__),
+ '..', '..', 'examples'))
+
+ path = get_config(key, def_path)
+ # use the same for all datasets
+ if not os.path.exists(path):
+ path = def_path
if not isinstance(path, basestring):
raise ValueError('path must be a string or None')
- archive_name = "MNE-sample-data-processed.tar.gz"
- url = "ftp://surfer.nmr.mgh.harvard.edu/pub/data/" + archive_name
- folder_name = "MNE-sample-data"
- folder_path = op.join(path, folder_name)
- rm_archive = False
+ if name == 'sample':
+ archive_name = "MNE-sample-data-processed.tar.gz"
+ url = "ftp://surfer.nmr.mgh.harvard.edu/pub/data/" + archive_name
+ folder_name = "MNE-sample-data"
+ folder_path = op.join(path, folder_name)
+ rm_archive = False
+ elif name == 'spm':
+ archive_name = 'MNE-spm-face.tar.bz2'
+ url = 'ftp://surfer.nmr.mgh.harvard.edu/pub/data/MNE/' + archive_name
+ folder_name = "MNE-spm-face"
+ folder_path = op.join(path, folder_name)
+ rm_archive = False
+ else:
+ raise ValueError('Sorry, the dataset "%s" is not known.' % name)
martinos_path = '/cluster/fusion/sample_data/' + archive_name
neurospin_path = '/neurospin/tmp/gramfort/' + archive_name
+ if not op.exists(folder_path) and not download:
+ return ''
+
if not op.exists(folder_path) or force_update:
logger.info('Sample data archive %s not found at:\n%s\n'
'It will be downloaded and extracted at this location.'
@@ -93,17 +129,20 @@ def data_path(path=None, force_update=False, update_path=True):
if op.exists(folder_path):
shutil.rmtree(folder_path)
- import tarfile
- # note that we use print statements here because these processes
- # are interactive
logger.info('Decompressiong the archive: ' + archive_name)
- tarfile.open(archive_name, 'r:gz').extractall(path=path)
+ logger.info('... please be patient, this can take some time')
+ for ext in ['gz', 'bz2']: # informed guess (and the only 2 options).
+ try:
+ tarfile.open(archive_name, 'r:%s' % ext).extractall(path=path)
+ except tarfile.ReadError, err:
+ logger.info('%s is %s trying "bz2"' % (archive_name, err))
+
if rm_archive:
os.remove(archive_name)
path = op.abspath(path)
if update_path is None:
- if get_config('MNE_DATASETS_SAMPLE_PATH', '') != path:
+ if get_config(key, '') != path:
update_path = True
msg = ('Do you want to set the path:\n %s\nas the default '
'sample dataset path in the mne-python config [y]/n? '
@@ -113,23 +152,34 @@ def data_path(path=None, force_update=False, update_path=True):
update_path = False
else:
update_path = False
+
if update_path is True:
- set_config('MNE_DATASETS_SAMPLE_PATH', path)
+ set_config(key, path)
path = op.join(path, folder_name)
# compare the version of the Sample dataset and mne
- sample_version = _sample_version(path)
+ data_version = _dataset_version(path, name)
try:
from distutils.version import LooseVersion
except:
warn('Could not determine sample dataset version; dataset could\n'
'be out of date. Please install the "distutils" package.')
else:
- if LooseVersion(sample_version) < LooseVersion(mne_version):
+ if LooseVersion(data_version) < LooseVersion(mne_version):
warn('Sample dataset (version %s) is older than mne-python '
'(version %s). If the examples fail, you may need to update '
'the sample dataset by using force_update=True'
- % (sample_version, mne_version))
+ % (data_version, mne_version))
return path
+
+
+def has_dataset(name):
+ """Helper for sample dataset presence"""
+ endswith = {'sample': 'MNE-sample-data',
+ 'spm': 'MNE-spm-face'}[name]
+ if _data_path(download=False, name=name).endswith(endswith):
+ return True
+ else:
+ return False
diff --git a/mne/decoding/__init__.py b/mne/decoding/__init__.py
new file mode 100644
index 0000000..0e79ecf
--- /dev/null
+++ b/mne/decoding/__init__.py
@@ -0,0 +1,4 @@
+from .classifier import Scaler, FilterEstimator
+from .classifier import PSDEstimator, ConcatenateChannels
+from .mixin import TransformerMixin
+from .csp import CSP
\ No newline at end of file
diff --git a/mne/decoding/classifier.py b/mne/decoding/classifier.py
new file mode 100644
index 0000000..05c9852
--- /dev/null
+++ b/mne/decoding/classifier.py
@@ -0,0 +1,425 @@
+# Authors: Mainak Jas <mainak at neuro.hut.fi>
+# Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+#
+# License: BSD (3-clause)
+
+import numpy as np
+
+from .mixin import TransformerMixin
+
+from ..filter import (low_pass_filter, high_pass_filter, band_pass_filter,
+ band_stop_filter)
+from ..time_frequency import multitaper_psd
+from ..fiff import pick_types
+
+
+class Scaler(TransformerMixin):
+ """Standardizes data across channels
+
+ Parameters
+ ----------
+ info : dict
+ measurement info
+ with_mean : boolean, True by default
+ If True, center the data before scaling.
+ with_std : boolean, True by default
+ If True, scale the data to unit variance (or equivalently,
+ unit standard deviation).
+
+ Attributes
+ ----------
+ `scale_` : dict
+ The mean value for each channel type
+ `ch_std_` : array
+ The standard deviation for each channel type
+ """
+ def __init__(self, info, with_mean=True, with_std=True):
+ self.info = info
+ self.with_mean = with_mean
+ self.with_std = with_std
+
+ def fit(self, epochs_data, y):
+ """
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data to concatenate channels.
+ y : array
+ The label for each epoch.
+
+ Returns
+ -------
+ self : instance of Scaler
+ Returns the modified instance.
+ """
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+
+ X = np.atleast_3d(epochs_data)
+
+ picks_list = dict()
+ picks_list['mag'] = pick_types(self.info, meg='mag', ref_meg=False,
+ exclude='bads')
+ picks_list['grad'] = pick_types(self.info, meg='grad', ref_meg=False,
+ exclude='bads')
+ picks_list['eeg'] = pick_types(self.info, eeg='grad', ref_meg=False,
+ exclude='bads')
+
+ self.picks_list_ = picks_list
+
+ self.ch_mean_, self.std_ = dict(), dict()
+ for key, this_pick in picks_list.items():
+ if self.with_mean:
+ ch_mean = X[:, this_pick, :].mean(axis=1)[:, None, :]
+ self.ch_mean_[key] = ch_mean
+ if self.with_std:
+ ch_std = X[:, this_pick, :].mean(axis=1)[:, None, :]
+ self.std_[key] = ch_std
+
+ return self
+
+ def transform(self, epochs_data, y=None):
+ """Standardizes data across channels
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data.
+
+ Returns
+ -------
+ X : array of shape (n_epochs, n_channels * n_times)
+ The data concatenated over channels.
+ """
+
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+
+ X = np.atleast_3d(epochs_data)
+
+ for key, this_pick in self.picks_list_.iteritems():
+ if self.with_mean:
+ X[:, this_pick, :] -= self.ch_mean_[key]
+ if self.with_std:
+ X[:, this_pick, :] /= self.std_[key]
+
+ return X
+
+
+class ConcatenateChannels(TransformerMixin):
+ """Concatenates data from different channels into a single feature vector
+
+ Parameters
+ ----------
+ info : dict
+ The measurement info.
+ """
+ def __init__(self, info=None):
+ self.info = info
+
+ def fit(self, epochs_data, y):
+ """Concatenates data from different channels into a single feature
+ vector
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data to concatenate channels.
+ y : array
+ The label for each epoch.
+
+ Returns
+ -------
+ self : instance of ConcatenateChannels
+ returns the modified instance
+ """
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+
+ return self
+
+ def transform(self, epochs_data, y=None):
+ """Concatenates data from different channels into a single feature
+ vector
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data.
+
+ Returns
+ -------
+ X : array, shape (n_epochs, n_channels*n_times)
+ The data concatenated over channels
+ """
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+
+ epochs_data = np.atleast_3d(epochs_data)
+
+ n_epochs, n_channels, n_times = epochs_data.shape
+ X = epochs_data.reshape(n_epochs, n_channels * n_times)
+
+ return X
+
+
+class PSDEstimator(TransformerMixin):
+ """Compute power spectrum density (PSD) using a multi-taper method
+
+ Parameters
+ ----------
+ sfreq : float
+ The sampling frequency.
+ fmin : float
+ The lower frequency of interest.
+ fmax : float
+ The upper frequency of interest.
+ bandwidth : float
+ The bandwidth of the multi taper windowing function in Hz.
+ adaptive : bool
+ Use adaptive weights to combine the tapered spectra into PSD
+ (slow, use n_jobs >> 1 to speed up computation).
+ low_bias : bool
+ Only use tapers with more than 90% spectral concentration within
+ bandwidth.
+ n_jobs : int
+ Number of parallel jobs to use (only used if adaptive=True).
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+ def __init__(self, sfreq=2 * np.pi, fmin=0, fmax=np.inf, bandwidth=None,
+ adaptive=False, low_bias=True, n_jobs=1, verbose=None):
+ self.sfreq = sfreq
+ self.fmin = fmin
+ self.fmax = fmax
+ self.bandwidth = bandwidth
+ self.adaptive = adaptive
+ self.low_bias = low_bias
+ self.n_jobs = n_jobs
+ self.verbose = verbose
+
+ def fit(self, epochs_data, y):
+ """Compute power spectrum density (PSD) using a multi-taper method
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data.
+ y : array
+ The label for each epoch
+
+ Returns
+ -------
+ self : instance of PSDEstimator
+ returns the modified instance
+
+ """
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+
+ return self
+
+ def transform(self, epochs_data, y=None):
+ """Compute power spectrum density (PSD) using a multi-taper method
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data
+
+ Returns
+ -------
+ psd : array, shape=(n_signals, len(freqs)) or (len(freqs),)
+ The computed PSD.
+ """
+
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+
+ epochs_data = np.atleast_3d(epochs_data)
+
+ n_epochs, n_channels, n_times = epochs_data.shape
+ X = epochs_data.reshape(n_epochs * n_channels, n_times)
+
+ psd, _ = multitaper_psd(X, self.sfreq, self.fmin, self.fmax,
+ self.bandwidth, self.adaptive, self.low_bias,
+ self.n_jobs, self.verbose)
+
+ _, n_freqs = psd.shape
+ psd = psd.reshape(n_epochs, n_channels, n_freqs)
+
+ return psd
+
+
+class FilterEstimator(TransformerMixin):
+ """Estimator to filter RtEpochs
+
+ Applies a zero-phase low-pass, high-pass, band-pass, or band-stop
+ filter to the channels selected by "picks".
+
+ l_freq and h_freq are the frequencies below which and above which,
+ respectively, to filter out of the data. Thus the uses are:
+ l_freq < h_freq: band-pass filter
+ l_freq > h_freq: band-stop filter
+ l_freq is not None, h_freq is None: low-pass filter
+ l_freq is None, h_freq is not None: high-pass filter
+
+ Note: If n_jobs > 1, more memory is required as "len(picks) * n_times"
+ additional time points need to be temporarily stored in memory.
+
+ Parameters
+ ----------
+ info : dict
+ Measurement info.
+ l_freq : float | None
+ Low cut-off frequency in Hz. If None the data are only low-passed.
+ h_freq : float | None
+ High cut-off frequency in Hz. If None the data are only
+ high-passed.
+ picks : list of int | None
+ Indices of channels to filter. If None only the data (MEG/EEG)
+ channels will be filtered.
+ filter_length : str (Default: '10s') | int | None
+ Length of the filter to use. If None or "len(x) < filter_length",
+ the filter length used is len(x). Otherwise, if int, overlap-add
+ filtering with a filter of the specified length in samples) is
+ used (faster for long signals). If str, a human-readable time in
+ units of "s" or "ms" (e.g., "10s" or "5500ms") will be converted
+ to the shortest power-of-two length at least that duration.
+ l_trans_bandwidth : float
+ Width of the transition band at the low cut-off frequency in Hz.
+ h_trans_bandwidth : float
+ Width of the transition band at the high cut-off frequency in Hz.
+ n_jobs : int | str
+ Number of jobs to run in parallel. Can be 'cuda' if scikits.cuda
+ is installed properly, CUDA is initialized, and method='fft'.
+ method : str
+ 'fft' will use overlap-add FIR filtering, 'iir' will use IIR
+ forward-backward filtering (via filtfilt).
+ iir_params : dict
+ Dictionary of parameters to use for IIR filtering.
+ See mne.filter.construct_iir_filter for details.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ Defaults to self.verbose.
+ """
+ def __init__(self, info, l_freq, h_freq, picks=None, filter_length='10s',
+ l_trans_bandwidth=0.5, h_trans_bandwidth=0.5, n_jobs=1,
+ method='fft', iir_params=dict(order=4, ftype='butter')):
+ self.info = info
+ self.l_freq = l_freq
+ self.h_freq = h_freq
+ self.picks = picks
+ self.filter_length = filter_length
+ self.l_trans_bandwidth = l_trans_bandwidth
+ self.h_trans_bandwidth = h_trans_bandwidth
+ self.n_jobs = n_jobs
+ self.method = method
+ self.iir_params = iir_params
+
+ def fit(self, epochs_data, y):
+ """Filters data
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data.
+
+ Returns
+ -------
+ self : instance of FilterEstimator
+ Returns the modified instance
+ """
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+
+ if self.picks is None:
+ self.picks = pick_types(self.info, meg=True, eeg=True, ref_meg=False,
+ exclude=[])
+
+ if self.l_freq == 0:
+ self.l_freq = None
+ if self.h_freq > (self.info['sfreq'] / 2.):
+ self.h_freq = None
+
+ if self.h_freq is not None and \
+ (self.l_freq is None or self.l_freq < self.h_freq) and \
+ self.h_freq < self.info['lowpass']:
+ self.info['lowpass'] = self.h_freq
+
+ if self.l_freq is not None and \
+ (self.h_freq is None or self.l_freq < self.h_freq) and \
+ self.l_freq > self.info['highpass']:
+ self.info['highpass'] = self.l_freq
+
+ return self
+
+ def transform(self, epochs_data, y=None):
+ """Filters data
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data.
+
+ Returns
+ -------
+ X : array, shape=(n_epochs, n_channels, n_times)
+ The data after filtering
+ """
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+
+ epochs_data = np.atleast_3d(epochs_data)
+
+ if self.l_freq is None and self.h_freq is not None:
+ epochs_data = \
+ low_pass_filter(epochs_data, self.fs, self.h_freq,
+ filter_length=self.filter_length,
+ trans_bandwidth=self.l_trans_bandwidth,
+ method=self.method, iir_params=self.iir_params,
+ picks=self.picks, n_jobs=self.n_jobs,
+ copy=False, verbose=False)
+
+ if self.l_freq is not None and self.h_freq is None:
+ epochs_data = \
+ high_pass_filter(epochs_data, self.info['sfreq'], self.l_freq,
+ filter_length=self.filter_length,
+ trans_bandwidth=self.h_trans_bandwidth,
+ method=self.method,
+ iir_params=self.iir_params,
+ picks=self.picks, n_jobs=self.n_jobs,
+ copy=False, verbose=False)
+
+ if self.l_freq is not None and self.h_freq is not None:
+ if self.l_freq < self.h_freq:
+ epochs_data = \
+ band_pass_filter(epochs_data, self.info['sfreq'],
+ self.l_freq, self.h_freq,
+ filter_length=self.filter_length,
+ l_trans_bandwidth=self.l_trans_bandwidth,
+ h_trans_bandwidth=self.h_trans_bandwidth,
+ method=self.method,
+ iir_params=self.iir_params,
+ picks=self.picks, n_jobs=self.n_jobs,
+ copy=False, verbose=False)
+ else:
+ epochs_data = \
+ band_stop_filter(epochs_data, self.info['sfreq'],
+ self.h_freq, self.l_freq,
+ filter_length=self.filter_length,
+ l_trans_bandwidth=self.h_trans_bandwidth,
+ h_trans_bandwidth=self.l_trans_bandwidth,
+ method=self.method,
+ iir_params=self.iir_params,
+ picks=self.picks, n_jobs=self.n_jobs,
+ copy=False, verbose=False)
+ return epochs_data
diff --git a/mne/decoding/csp.py b/mne/decoding/csp.py
new file mode 100644
index 0000000..167bf7d
--- /dev/null
+++ b/mne/decoding/csp.py
@@ -0,0 +1,205 @@
+# Authors: Romain Trachel <romain.trachel at inria.fr>
+# Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+#
+# License: BSD (3-clause)
+
+import numpy as np
+from scipy import linalg
+from distutils.version import LooseVersion
+
+from .mixin import TransformerMixin
+
+
+class CSP(TransformerMixin):
+ """M/EEG signal decomposition using the Common Spatial Patterns (CSP)
+
+ This object can be used as a supervised decomposition to estimate
+ spatial filters for feature extraction in a 2 class decoding problem.
+ See [1].
+
+ Parameters
+ ----------
+ n_components : int, default 4
+ The number of components to decompose M/EEG signals.
+ This number should be set by cross-validation.
+ reg : float, str, None
+ if not None, allow regularization for covariance estimation
+ if float, shrinkage covariance is used (0 <= shrinkage <= 1).
+ if str, optimal shrinkage using Ledoit-Wolf Shrinkage ('lws') or
+ Oracle Approximating Shrinkage ('oas')
+
+ Attributes
+ ----------
+ `filters_` : ndarray
+ If fit, the CSP components used to decompose the data, else None.
+ `patterns_` : ndarray
+ If fit, the CSP patterns used to restore M/EEG signals, else None.
+ `mean_` : ndarray
+ If fit, the mean squared power for each component.
+ `std_` : ndarray
+ If fit, the std squared power for each component.
+
+ [1] Zoltan J. Koles. The quantitative extraction and topographic mapping
+ of the abnormal components in the clinical EEG. Electroencephalography
+ and Clinical Neurophysiology, 79(6):440--447, December 1991.
+ """
+ def __init__(self, n_components=4, reg=None):
+ self.n_components = n_components
+ self.reg = reg
+ self.filters_ = None
+ self.patterns_ = None
+ self.mean_ = None
+ self.std_ = None
+
+ def fit(self, epochs_data, y):
+ """Estimate the CSP decomposition on epochs.
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data to estimate the CSP on.
+ y : array
+ The class for each epoch.
+
+ Returns
+ -------
+ self : instance of CSP
+ Returns the modified instance.
+ """
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+ epochs_data = np.atleast_3d(epochs_data)
+ classes = np.unique(y)
+ if len(classes) != 2:
+ raise ValueError("More than two different classes in the data.")
+ # concatenate epochs
+ class_1 = np.transpose(epochs_data[y == classes[0]],
+ [1, 0, 2]).reshape(epochs_data.shape[1], -1)
+ class_2 = np.transpose(epochs_data[y == classes[1]],
+ [1, 0, 2]).reshape(epochs_data.shape[1], -1)
+ if self.reg is None:
+ # compute empirical covariance
+ cov_1 = np.dot(class_1, class_1.T)
+ cov_2 = np.dot(class_2, class_2.T)
+ else:
+ # use sklearn covariance estimators
+ if isinstance(self.reg, float):
+ if (self.reg < 0) or (self.reg > 1):
+ raise ValueError('0 <= shrinkage <= 1 for '
+ 'covariance regularization.')
+ try:
+ import sklearn
+ sklearn_version = LooseVersion(sklearn.__version__)
+ from sklearn.covariance import ShrunkCovariance
+ except ImportError:
+ raise Exception('the scikit-learn package is missing and '
+ 'required for covariance regularization.')
+ if sklearn_version < '0.12':
+ skl_cov = ShrunkCovariance(shrinkage=self.reg,
+ store_precision=False)
+ else:
+ # init sklearn.covariance.ShrunkCovariance estimator
+ skl_cov = ShrunkCovariance(shrinkage=self.reg,
+ store_precision=False,
+ assume_centered=True)
+ elif isinstance(self.reg, str):
+ if self.reg == 'lws':
+ try:
+ from sklearn.covariance import LedoitWolf
+ except ImportError:
+ raise Exception('the scikit-learn package is missing '
+ 'and required for regularization.')
+ # init sklearn.covariance.LedoitWolf estimator
+ skl_cov = LedoitWolf(store_precision=False,
+ assume_centered=True)
+ elif self.reg == 'oas':
+ try:
+ from sklearn.covariance import OAS
+ except ImportError:
+ raise Exception('the scikit-learn package is missing '
+ 'and required for regularization.')
+ # init sklearn.covariance.OAS estimator
+ skl_cov = OAS(store_precision=False,
+ assume_centered=True)
+ else:
+ raise ValueError("regularization parameter should be "
+ "of type str (got %s)." % type(self.reg))
+ else:
+ raise ValueError("regularization parameter should be "
+ "of type str (got %s)." % type(self.reg))
+
+ # compute regularized covariance using sklearn
+ cov_1 = skl_cov.fit(class_1.T).covariance_
+ cov_2 = skl_cov.fit(class_2.T).covariance_
+
+ # then fit on covariance
+ self._fit(cov_1, cov_2)
+
+ pick_filters = self.filters_[:self.n_components]
+ X = np.asarray([np.dot(pick_filters, e) for e in epochs_data])
+
+ # compute features (mean band power)
+ X = (X ** 2).mean(axis=-1)
+
+ # To standardize features
+ self.mean_ = X.mean(axis=0)
+ self.std_ = X.std(axis=0)
+
+ return self
+
+ def _fit(self, cov_a, cov_b):
+ """Aux Function (modifies cov_a and cov_b in-place)"""
+
+ cov_a /= np.trace(cov_a)
+ cov_b /= np.trace(cov_b)
+ # computes the eigen values
+ lambda_, u = linalg.eigh(cov_a + cov_b)
+ # sort them
+ ind = np.argsort(lambda_)[::-1]
+ lambda2_ = lambda_[ind]
+
+ u = u[:, ind]
+ p = np.dot(np.sqrt(linalg.pinv(np.diag(lambda2_))), u.T)
+
+ # Compute the generalized eigen value problem
+ w_a = np.dot(np.dot(p, cov_a), p.T)
+ w_b = np.dot(np.dot(p, cov_b), p.T)
+ # and solve it
+ vals, vecs = linalg.eigh(w_a, w_b)
+ # sort vectors by discriminative power using eigen values
+ ind = np.argsort(np.maximum(vals, 1. / vals))[::-1]
+ vecs = vecs[:, ind]
+ # and project
+ w = np.dot(vecs.T, p)
+
+ self.filters_ = w
+ self.patterns_ = linalg.pinv(w).T
+
+ def transform(self, epochs_data, y=None):
+ """Estimate epochs sources given the CSP filters
+
+ Parameters
+ ----------
+ epochs_data : array, shape=(n_epochs, n_channels, n_times)
+ The data.
+ Returns
+ -------
+ X : ndarray of shape (n_epochs, n_sources)
+ The CSP features averaged over time.
+ """
+ if not isinstance(epochs_data, np.ndarray):
+ raise ValueError("epochs_data should be of type ndarray (got %s)."
+ % type(epochs_data))
+ if self.filters_ is None:
+ raise RuntimeError('No filters available. Please first fit CSP '
+ 'decomposition.')
+
+ pick_filters = self.filters_[:self.n_components]
+ X = np.asarray([np.dot(pick_filters, e) for e in epochs_data])
+
+ # compute features (mean band power)
+ X = (X ** 2).mean(axis=-1)
+ X -= self.mean_
+ X /= self.std_
+ return X
diff --git a/mne/decoding/mixin.py b/mne/decoding/mixin.py
new file mode 100644
index 0000000..2f16db8
--- /dev/null
+++ b/mne/decoding/mixin.py
@@ -0,0 +1,30 @@
+class TransformerMixin(object):
+ """Mixin class for all transformers in scikit-learn"""
+
+ def fit_transform(self, X, y=None, **fit_params):
+ """Fit to data, then transform it
+
+ Fits transformer to X and y with optional parameters fit_params
+ and returns a transformed version of X.
+
+ Parameters
+ ----------
+ X : numpy array of shape [n_samples, n_features]
+ Training set.
+
+ y : numpy array of shape [n_samples]
+ Target values.
+
+ Returns
+ -------
+ X_new : numpy array of shape [n_samples, n_features_new]
+ Transformed array.
+ """
+ # non-optimized default implementation; override when a better
+ # method is possible for a given clustering algorithm
+ if y is None:
+ # fit method of arity 1 (unsupervised transformation)
+ return self.fit(X, **fit_params).transform(X)
+ else:
+ # fit method of arity 2 (supervised transformation)
+ return self.fit(X, y, **fit_params).transform(X)
diff --git a/mne/tests/__init__.py b/mne/decoding/tests/__init__.py
similarity index 100%
copy from mne/tests/__init__.py
copy to mne/decoding/tests/__init__.py
diff --git a/mne/decoding/tests/test_classifier.py b/mne/decoding/tests/test_classifier.py
new file mode 100644
index 0000000..c30b171
--- /dev/null
+++ b/mne/decoding/tests/test_classifier.py
@@ -0,0 +1,127 @@
+# Author: Mainak Jas <mainak at neuro.hut.fi>
+#
+# License: BSD (3-clause)
+
+import warnings
+import os.path as op
+import numpy as np
+
+from nose.tools import assert_true, assert_raises
+from numpy.testing import assert_array_equal
+
+from mne import fiff, read_events, Epochs
+from mne.decoding.classifier import Scaler, FilterEstimator
+from mne.decoding.classifier import PSDEstimator, ConcatenateChannels
+
+warnings.simplefilter('always') # enable b/c these tests throw warnings
+
+tmin, tmax = -0.2, 0.5
+event_id = dict(aud_l=1, vis_l=3)
+start, stop = 0, 8
+
+data_dir = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data')
+raw_fname = op.join(data_dir, 'test_raw.fif')
+event_name = op.join(data_dir, 'test-eve.fif')
+
+
+def test_scaler():
+ """Test methods of Scaler
+ """
+ raw = fiff.Raw(raw_fname, preload=False)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ picks = picks[1:13:3]
+
+ epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
+ epochs_data = epochs.get_data()
+ scaler = Scaler(epochs.info)
+ y = epochs.events[:, -1]
+ with warnings.catch_warnings(True): # np invalid divide value warnings
+ X = scaler.fit_transform(epochs_data, y)
+ assert_true(X.shape == epochs_data.shape)
+ X2 = scaler.fit(epochs_data, y).transform(epochs_data)
+
+ assert_array_equal(X2, X)
+
+ # Test init exception
+ assert_raises(ValueError, scaler.fit, epochs, y)
+ assert_raises(ValueError, scaler.transform, epochs, y)
+
+
+def test_filterestimator():
+ """Test methods of FilterEstimator
+ """
+ raw = fiff.Raw(raw_fname, preload=False)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ picks = picks[1:13:3]
+ epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
+ epochs_data = epochs.get_data()
+ filt = FilterEstimator(epochs.info, 1, 40)
+ y = epochs.events[:, -1]
+ with warnings.catch_warnings(True): # stop freq attenuation warning
+ X = filt.fit_transform(epochs_data, y)
+ assert_true(X.shape == epochs_data.shape)
+ assert_array_equal(filt.fit(epochs_data, y).transform(epochs_data), X)
+
+ # Test init exception
+ assert_raises(ValueError, filt.fit, epochs, y)
+ assert_raises(ValueError, filt.transform, epochs, y)
+
+
+def test_psdestimator():
+ """Test methods of PSDEstimator
+ """
+ raw = fiff.Raw(raw_fname, preload=False)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ picks = picks[1:13:3]
+ epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
+ epochs_data = epochs.get_data()
+ psd = PSDEstimator(2 * np.pi, 0, np.inf)
+ y = epochs.events[:, -1]
+ X = psd.fit_transform(epochs_data, y)
+
+ assert_true(X.shape[0] == epochs_data.shape[0])
+ assert_array_equal(psd.fit(epochs_data, y).transform(epochs_data), X)
+
+ # Test init exception
+ assert_raises(ValueError, psd.fit, epochs, y)
+ assert_raises(ValueError, psd.transform, epochs, y)
+
+
+def test_concatenatechannels():
+ """Test methods of ConcatenateChannels
+ """
+ raw = fiff.Raw(raw_fname, preload=False)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ picks = picks[1:13:3]
+ with warnings.catch_warnings(True) as w:
+ epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
+ epochs_data = epochs.get_data()
+ concat = ConcatenateChannels(epochs.info)
+ y = epochs.events[:, -1]
+ X = concat.fit_transform(epochs_data, y)
+
+ # Check data dimensions
+ assert_true(X.shape[0] == epochs_data.shape[0])
+ assert_true(X.shape[1] == epochs_data.shape[1] * epochs_data.shape[2])
+
+ assert_array_equal(concat.fit(epochs_data, y).transform(epochs_data), X)
+
+ # Check if data is preserved
+ n_times = epochs_data.shape[2]
+ assert_array_equal(epochs_data[0, 0, 0:n_times], X[0, 0:n_times])
+
+ # Test init exception
+ assert_raises(ValueError, concat.fit, epochs, y)
+ assert_raises(ValueError, concat.transform, epochs, y)
diff --git a/mne/decoding/tests/test_csp.py b/mne/decoding/tests/test_csp.py
new file mode 100644
index 0000000..74cb38a
--- /dev/null
+++ b/mne/decoding/tests/test_csp.py
@@ -0,0 +1,97 @@
+# Author: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Romain Trachel <romain.trachel at inria.fr>
+#
+# License: BSD (3-clause)
+
+import os.path as op
+
+from nose.tools import assert_true, assert_raises
+import numpy as np
+from numpy.testing import assert_array_almost_equal
+
+from mne import fiff, Epochs, read_events
+from mne.decoding.csp import CSP
+from mne.utils import _TempDir, requires_sklearn
+
+tempdir = _TempDir()
+
+data_dir = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data')
+raw_fname = op.join(data_dir, 'test_raw.fif')
+event_name = op.join(data_dir, 'test-eve.fif')
+
+tmin, tmax = -0.2, 0.5
+event_id = dict(aud_l=1, vis_l=3)
+start, stop = 0, 8 # if stop is too small pca may fail in some cases, but
+ # we're okay on this file
+
+
+def test_csp():
+ """Test Common Spatial Patterns algorithm on epochs
+ """
+ raw = fiff.Raw(raw_fname, preload=False)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ picks = picks[1:13:3]
+ epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
+ epochs_data = epochs.get_data()
+ n_channels = epochs_data.shape[1]
+
+ n_components = 3
+ csp = CSP(n_components=n_components)
+
+ csp.fit(epochs_data, epochs.events[:, -1])
+ y = epochs.events[:, -1]
+ X = csp.fit_transform(epochs_data, y)
+ assert_true(csp.filters_.shape == (n_channels, n_channels))
+ assert_true(csp.patterns_.shape == (n_channels, n_channels))
+ assert_array_almost_equal(csp.fit(epochs_data, y).transform(epochs_data),
+ X)
+
+ # test init exception
+ assert_raises(ValueError, csp.fit, epochs_data,
+ np.zeros_like(epochs.events))
+ assert_raises(ValueError, csp.fit, epochs, y)
+ assert_raises(ValueError, csp.transform, epochs, y)
+
+ csp.n_components = n_components
+ sources = csp.transform(epochs_data)
+ assert_true(sources.shape[1] == n_components)
+
+
+ at requires_sklearn
+def test_regularized_csp():
+ """Test Common Spatial Patterns algorithm using regularized covariance
+ """
+ raw = fiff.Raw(raw_fname, preload=False)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ picks = picks[1:13:3]
+ epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
+ epochs_data = epochs.get_data()
+ n_channels = epochs_data.shape[1]
+
+ n_components = 3
+ reg_cov = [None, 0.05, 'lws', 'oas']
+ for reg in reg_cov:
+ csp = CSP(n_components=n_components, reg=reg)
+ csp.fit(epochs_data, epochs.events[:, -1])
+ y = epochs.events[:, -1]
+ X = csp.fit_transform(epochs_data, y)
+ assert_true(csp.filters_.shape == (n_channels, n_channels))
+ assert_true(csp.patterns_.shape == (n_channels, n_channels))
+ assert_array_almost_equal(csp.fit(epochs_data, y).
+ transform(epochs_data), X)
+
+ # test init exception
+ assert_raises(ValueError, csp.fit, epochs_data,
+ np.zeros_like(epochs.events))
+ assert_raises(ValueError, csp.fit, epochs, y)
+ assert_raises(ValueError, csp.transform, epochs, y)
+
+ csp.n_components = n_components
+ sources = csp.transform(epochs_data)
+ assert_true(sources.shape[1] == n_components)
diff --git a/mne/dipole.py b/mne/dipole.py
index 244c865..25a5363 100644
--- a/mne/dipole.py
+++ b/mne/dipole.py
@@ -3,10 +3,8 @@
# License: Simplified BSD
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-from . import verbose
+from .utils import logger, verbose
@verbose
diff --git a/mne/epochs.py b/mne/epochs.py
index 25b4343..7b7df23 100644
--- a/mne/epochs.py
+++ b/mne/epochs.py
@@ -4,6 +4,7 @@
# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
# Daniel Strohmeier <daniel.strohmeier at tu-ilmenau.de>
# Denis Engemann <d.engemann at fz-juelich.de>
+# Mainak Jas <mainak at neuro.hut.fi>
#
# License: BSD (3-clause)
@@ -13,32 +14,449 @@ import warnings
import numpy as np
from copy import deepcopy
-import logging
-logger = logging.getLogger('mne')
-
-from .fiff.write import start_file, start_block, end_file, end_block, \
- write_int, write_float_matrix, write_float, \
- write_id, write_string
+from .fiff.write import (start_file, start_block, end_file, end_block,
+ write_int, write_float_matrix, write_float,
+ write_id, write_string)
from .fiff.meas_info import read_meas_info, write_meas_info
from .fiff.open import fiff_open
from .fiff.raw import _time_as_index, _index_as_time
from .fiff.tree import dir_tree_find
from .fiff.tag import read_tag
from .fiff import Evoked, FIFF
-from .fiff.pick import pick_types, channel_indices_by_type, channel_type
+from .fiff.pick import (pick_types, channel_indices_by_type, channel_type,
+ pick_channels)
from .fiff.proj import setup_proj, ProjMixin
from .fiff.evoked import aspect_rev
from .baseline import rescale
-from .utils import check_random_state, _check_pandas_index_arguments, \
- _check_pandas_installed
+from .utils import (check_random_state, _check_pandas_index_arguments,
+ _check_pandas_installed)
from .filter import resample, detrend
from .event import _read_events_fif
-from . import verbose
from .fixes import in1d
-from .viz import _mutable_defaults
+from .viz import _mutable_defaults, plot_epochs
+from .utils import logger, verbose
+
+
+class _BaseEpochs(ProjMixin):
+ """Abstract base class for Epochs-type classes
+
+ This class provides basic functionality and should never be instantiated
+ directly. See Epochs below for an explanation of the parameters.
+ """
+ def __init__(self, info, event_id, tmin, tmax, baseline=(None, 0),
+ picks=None, name='Unknown', keep_comp=False, dest_comp=0,
+ reject=None, flat=None, decim=1, reject_tmin=None,
+ reject_tmax=None, detrend=None, add_eeg_ref=True,
+ verbose=None):
+
+ self.verbose = verbose
+ self.name = name
+
+ if isinstance(event_id, dict):
+ if not all([isinstance(v, int) for v in event_id.values()]):
+ raise ValueError('Event IDs must be of type integer')
+ if not all([isinstance(k, basestring) for k in event_id]):
+ raise ValueError('Event names must be of type str')
+ self.event_id = event_id
+ elif isinstance(event_id, list):
+ if not all([isinstance(v, int) for v in event_id]):
+ raise ValueError('Event IDs must be of type integer')
+ self.event_id = dict(zip((str(i) for i in event_id), event_id))
+ elif isinstance(event_id, int):
+ self.event_id = {str(event_id): event_id}
+ else:
+ raise ValueError('event_id must be dict or int.')
+
+ # check reject_tmin and reject_tmax
+ if (reject_tmin is not None) and (reject_tmin < tmin):
+ raise ValueError("reject_tmin needs to be None or >= tmin")
+ if (reject_tmax is not None) and (reject_tmax > tmax):
+ raise ValueError("reject_tmax needs to be None or <= tmax")
+ if (reject_tmin is not None) and (reject_tmax is not None):
+ if reject_tmin >= reject_tmax:
+ raise ValueError('reject_tmin needs to be < reject_tmax')
+ if not detrend in [None, 0, 1]:
+ raise ValueError('detrend must be None, 0, or 1')
+
+ self.tmin = tmin
+ self.tmax = tmax
+ self.keep_comp = keep_comp
+ self.dest_comp = dest_comp
+ self.baseline = baseline
+ self.reject = reject
+ self.reject_tmin = reject_tmin
+ self.reject_tmax = reject_tmax
+ self.flat = flat
+ self.decim = decim = int(decim)
+ self._bad_dropped = False
+ self.drop_log = None
+ self.detrend = detrend
+
+ # Handle measurement info
+ self.info = info
+ if picks is None:
+ picks = range(len(self.info['ch_names']))
+ else:
+ self.info['chs'] = [self.info['chs'][k] for k in picks]
+ self.info['ch_names'] = [self.info['ch_names'][k] for k in picks]
+ self.info['nchan'] = len(picks)
+ self.picks = picks
+
+ if len(picks) == 0:
+ raise ValueError("Picks cannot be empty.")
+
+ # XXX : deprecate CTF compensator
+ if dest_comp is not None or keep_comp is not None:
+ raise ValueError('current_comp and keep_comp are deprecated.'
+ ' Use the compensation parameter in Raw.')
+
+ # Handle times
+ if tmin >= tmax:
+ raise ValueError('tmin has to be smaller than tmax')
+ sfreq = float(self.info['sfreq'])
+ n_times_min = int(round(tmin * sfreq))
+ n_times_max = int(round(tmax * sfreq))
+ times = np.arange(n_times_min, n_times_max + 1, dtype=np.float) / sfreq
+ self.times = times
+ self._raw_times = times # times before decimation
+ self._epoch_stop = ep_len = len(self.times)
+ if decim > 1:
+ new_sfreq = sfreq / decim
+ lowpass = self.info['lowpass']
+ if new_sfreq < 2.5 * lowpass: # nyquist says 2 but 2.5 is safer
+ msg = ('The measurement information indicates a low-pass '
+ 'frequency of %g Hz. The decim=%i parameter will '
+ 'result in a sampling frequency of %g Hz, which can '
+ 'cause aliasing artifacts.'
+ % (lowpass, decim, new_sfreq))
+ warnings.warn(msg)
+
+ i_start = n_times_min % decim
+ self._decim_idx = slice(i_start, ep_len, decim)
+ self.times = self.times[self._decim_idx]
+ self.info['sfreq'] = new_sfreq
+
+ self.preload = False
+ self._data = None
+ self._offset = None
+
+ # setup epoch rejection
+ self._reject_setup()
+
+ def _reject_setup(self):
+ """Sets self._reject_time and self._channel_type_idx (called from
+ __init__)
+ """
+ if self.reject is None and self.flat is None:
+ return
+
+ idx = channel_indices_by_type(self.info)
+ for key in idx.keys():
+ if (self.reject is not None and key in self.reject) \
+ or (self.flat is not None and key in self.flat):
+ if len(idx[key]) == 0:
+ raise ValueError("No %s channel found. Cannot reject based"
+ " on %s." % (key.upper(), key.upper()))
+
+ self._channel_type_idx = idx
+
+ if (self.reject_tmin is None) and (self.reject_tmax is None):
+ self._reject_time = None
+ else:
+ if self.reject_tmin is None:
+ reject_imin = None
+ else:
+ idxs = np.nonzero(self.times >= self.reject_tmin)[0]
+ reject_imin = idxs[0]
+ if self.reject_tmax is None:
+ reject_imax = None
+ else:
+ idxs = np.nonzero(self.times <= self.reject_tmax)[0]
+ reject_imax = idxs[-1]
+
+ self._reject_time = slice(reject_imin, reject_imax)
+
+ @verbose
+ def _is_good_epoch(self, data, verbose=None):
+ """Determine if epoch is good"""
+ if data is None:
+ return False, ['NO_DATA']
+ n_times = len(self.times)
+ if data.shape[1] < n_times:
+ # epoch is too short ie at the end of the data
+ return False, ['TOO_SHORT']
+ if self.reject is None and self.flat is None:
+ return True, None
+ else:
+ if self._reject_time is not None:
+ data = data[:, self._reject_time]
+
+ return _is_good(data, self.ch_names, self._channel_type_idx,
+ self.reject, self.flat, full_report=True,
+ ignore_chs=self.info['bads'])
+
+ def get_data(self):
+ """Get all epochs as a 3D array
+
+ Returns
+ -------
+ data : array of shape [n_epochs, n_channels, n_times]
+ The epochs data
+ """
+ if self.preload:
+ return self._data
+ else:
+ data = self._get_data_from_disk()
+ return data
+
+ def iter_evoked(self):
+ """Iterate over Evoked objects with nave=1
+ """
+ self._current = 0
+
+ while True:
+ evoked = Evoked(None)
+ evoked.info = cp.deepcopy(self.info)
+
+ evoked.times = self.times.copy()
+ evoked.nave = 1
+ evoked.first = int(self.times[0] * self.info['sfreq'])
+ evoked.last = evoked.first + len(self.times) - 1
+
+ evoked.data, event_id = self.next(True)
+ evoked.comment = str(event_id)
+
+ yield evoked
+
+ def subtract_evoked(self, evoked=None):
+ """Subtract an evoked response from each epoch
+
+ Can be used to exclude the evoked response when analyzing induced
+ activity, see e.g. [1].
+
+ References
+ ----------
+ [1] David et al. "Mechanisms of evoked and induced responses in
+ MEG/EEG", NeuroImage, vol. 31, no. 4, pp. 1580-1591, July 2006.
+
+ Parameters
+ ----------
+ evoked : instance of mne.fiff.Evoked | None
+ The evoked response to subtract. If None, the evoked response
+ is computed from Epochs itself.
+
+ Returns
+ -------
+ self : instance of mne.Epochs
+ The modified instance (instance is also modified inplace).
+ """
+ logger.info('Subtracting Evoked from Epochs')
+ if evoked is None:
+ picks = pick_types(self.info, meg=True, eeg=True,
+ stim=False, eog=False, ecg=False,
+ emg=False, exclude=[])
+ evoked = self.average(picks)
+
+ # find the indices of the channels to use
+ picks = pick_channels(evoked.ch_names, include=self.ch_names)
+
+ # make sure the omitted channels are not data channels
+ if len(picks) < len(self.ch_names):
+ sel_ch = [evoked.ch_names[ii] for ii in picks]
+ diff_ch = list(set(self.ch_names).difference(sel_ch))
+ diff_idx = [self.ch_names.index(ch) for ch in diff_ch]
+ diff_types = [channel_type(self.info, idx) for idx in diff_idx]
+ bad_idx = [diff_types.index(t) for t in diff_types if t in
+ ['grad', 'mag', 'eeg']]
+ if len(bad_idx) > 0:
+ bad_str = ', '.join([diff_ch[ii] for ii in bad_idx])
+ raise ValueError('The following data channels are missing '
+ 'in the evoked response: %s' % bad_str)
+ logger.info(' The following channels are not included in the '
+ 'subtraction: %s' % ', '.join(diff_ch))
+
+ # make sure the times match
+ if (len(self.times) != len(evoked.times) or
+ np.max(np.abs(self.times - evoked.times)) >= 1e-7):
+ raise ValueError('Epochs and Evoked object do not contain '
+ 'the same time points.')
+
+ # handle SSPs
+ if not self.proj and evoked.proj:
+ warnings.warn('Evoked has SSP applied while Epochs has not.')
+ if self.proj and not evoked.proj:
+ evoked = evoked.copy().apply_proj()
+
+ # find the indices of the channels to use in Epochs
+ ep_picks = [self.ch_names.index(evoked.ch_names[ii]) for ii in picks]
+
+ # do the subtraction
+ if self.preload:
+ self._data[:, ep_picks, :] -= evoked.data[picks][None, :, :]
+ else:
+ if self._offset is None:
+ self._offset = np.zeros((len(self.ch_names), len(self.times)),
+ dtype=np.float)
+ self._offset[ep_picks] -= evoked.data[picks]
+ logger.info('[done]')
+
+ return self
+
+ def _get_data_from_disk(self, out=True, verbose=None):
+ raise NotImplementedError('_get_data_from_disk() must be implemented '
+ 'in derived class.')
+
+ def __iter__(self):
+ """To make iteration over epochs easy.
+ """
+ self._current = 0
+ return self
+
+ def next(self, return_event_id=False):
+ raise NotImplementedError('next() must be implemented in derived '
+ 'class.')
+
+ def average(self, picks=None):
+ """Compute average of epochs
+
+ Parameters
+ ----------
+ picks : None | array of int
+ If None only MEG and EEG channels are kept
+ otherwise the channels indices in picks are kept.
+
+ Returns
+ -------
+ evoked : Evoked instance
+ The averaged epochs
+ """
+
+ return self._compute_mean_or_stderr(picks, 'ave')
+
+ def standard_error(self, picks=None):
+ """Compute standard error over epochs
+
+ Parameters
+ ----------
+ picks : None | array of int
+ If None only MEG and EEG channels are kept
+ otherwise the channels indices in picks are kept.
+
+ Returns
+ -------
+ evoked : Evoked instance
+ The standard error over epochs
+ """
+ return self._compute_mean_or_stderr(picks, 'stderr')
+
+ def _compute_mean_or_stderr(self, picks, mode='ave'):
+ """Compute the mean or std over epochs and return Evoked"""
+
+ _do_std = True if mode == 'stderr' else False
+ evoked = Evoked(None)
+ evoked.info = cp.deepcopy(self.info)
+ # make sure projs are really copied.
+ evoked.info['projs'] = [cp.deepcopy(p) for p in self.info['projs']]
+ n_channels = len(self.ch_names)
+ n_times = len(self.times)
+ if self.preload:
+ n_events = len(self.events)
+ if not _do_std:
+ data = np.mean(self._data, axis=0)
+ else:
+ data = np.std(self._data, axis=0)
+ assert len(self.events) == len(self._data)
+ else:
+ data = np.zeros((n_channels, n_times))
+ n_events = 0
+ for e in self:
+ data += e
+ n_events += 1
+ data /= n_events
+ # convert to stderr if requested, could do in one pass but do in
+ # two (slower) in case there are large numbers
+ if _do_std:
+ data_mean = cp.copy(data)
+ data.fill(0.)
+ for e in self:
+ data += (e - data_mean) ** 2
+ data = np.sqrt(data / n_events)
+
+ evoked.data = data
+ evoked.times = self.times.copy()
+ evoked.comment = self.name
+ evoked.nave = n_events
+ evoked.first = int(self.times[0] * self.info['sfreq'])
+ evoked.last = evoked.first + len(self.times) - 1
+ if not _do_std:
+ evoked._aspect_kind = FIFF.FIFFV_ASPECT_AVERAGE
+ else:
+ evoked._aspect_kind = FIFF.FIFFV_ASPECT_STD_ERR
+ evoked.data /= np.sqrt(evoked.nave)
+ evoked.kind = aspect_rev.get(str(evoked._aspect_kind), 'Unknown')
+ # dropping EOG, ECG and STIM channels. Keeping only data
+ if picks is None:
+ picks = pick_types(evoked.info, meg=True, eeg=True, ref_meg=True,
+ stim=False, eog=False, ecg=False,
+ emg=False, exclude=[])
+ if len(picks) == 0:
+ raise ValueError('No data channel found when averaging.')
-class Epochs(ProjMixin):
+ picks = np.sort(picks) # make sure channel order does not change
+ evoked.info['chs'] = [evoked.info['chs'][k] for k in picks]
+ evoked.info['ch_names'] = [evoked.info['ch_names'][k]
+ for k in picks]
+ evoked.info['nchan'] = len(picks)
+ evoked.data = evoked.data[picks]
+ # otherwise the apply_proj will be confused
+ evoked.proj = True if self.proj is True else None
+ evoked.verbose = self.verbose
+
+ return evoked
+
+ @property
+ def ch_names(self):
+ return self.info['ch_names']
+
+ def plot(self, epoch_idx=None, picks=None, scalings=None,
+ title_str='#%003i', show=True, block=False):
+ """ Visualize single trials using Trellis plot.
+
+ Parameters
+ ----------
+ epoch_idx : array-like | int | None
+ The epochs to visualize. If None, the frist 20 epochs are shoen.
+ Defaults to None.
+ picks : array-like | None
+ Channels to be included. If None only good data channels are used.
+ Defaults to None
+ scalings : dict | None
+ scalings : dict | None
+ Scale factors for the traces. If None, defaults to:
+ `dict(mag=1e-12, grad=4e-11, eeg=20e-6, eog=150e-6, ecg=5e-4,
+ emg=1e-3, ref_meg=1e-12, misc=1e-3, stim=1, resp=1,
+ chpi=1e-4)`
+ title_str : None | str
+ The string formatting to use for axes titles. If None, no titles
+ will be shown. Defaults expand to ``#001, #002, ...``
+ show : bool
+ Whether to show the figure or not.
+ block : bool
+ Whether to halt program execution until the figure is closed.
+ Useful for rejecting bad trials on the fly by clicking on a
+ sub plot.
+
+ Returns
+ -------
+ fig : Instance of matplotlib.figure.Figure
+ The figure.
+ """
+ plot_epochs(self, epoch_idx=epoch_idx, picks=picks, scalings=scalings,
+ title_str=title_str, show=show, block=block)
+
+
+class Epochs(_BaseEpochs):
"""List of Epochs
Parameters
@@ -47,11 +465,12 @@ class Epochs(ProjMixin):
An instance of Raw.
events : array, of shape [n_events, 3]
Returned by the read_events function.
- event_id : int | dict | None
+ event_id : int | list of int | dict | None
The id of the event to consider. If dict,
the keys can later be used to acces associated events. Example:
dict(auditory=1, visual=3). If int, a dict will be created with
- the id as string. If None, all events will be used with
+ the id as string. If a list, all events with the IDs specified
+ in the list are used. If None, all events will be used with
and a dict is created with string integer names corresponding
to the event id integers.
tmin : float
@@ -60,7 +479,7 @@ class Epochs(ProjMixin):
End time after event.
name : string
Comment that describes the Evoked data created.
- baseline : None (default) or tuple of length 2
+ baseline : None or tuple of length 2 (default (None, 0))
The time interval to apply baseline correction.
If None do not apply it. If baseline is (a, b)
the interval is between "a (s)" and "b (s)".
@@ -178,121 +597,55 @@ class Epochs(ProjMixin):
if raw is None:
return
- self.raw = raw
- self.verbose = raw.verbose if verbose is None else verbose
- self.name = name
- if isinstance(event_id, dict):
- if not all([isinstance(v, int) for v in event_id.values()]):
- raise ValueError('Event IDs must be of type integer')
- if not all([isinstance(k, basestring) for k in event_id]):
- raise ValueError('Event names must be of type str')
- self.event_id = event_id
- elif isinstance(event_id, int):
- self.event_id = {str(event_id): event_id}
- elif event_id is None:
- self.event_id = dict((str(e), e) for e in np.unique(events[:, 2]))
- else:
- raise ValueError('event_id must be dict or int.')
+ # prepare for calling the base constructor
- # check reject_tmin and reject_tmax
- if (reject_tmin is not None) and (reject_tmin < tmin):
- raise ValueError("reject_tmin needs to be None or >= tmin")
- if (reject_tmax is not None) and (reject_tmax > tmax):
- raise ValueError("reject_tmax needs to be None or <= tmax")
- if (reject_tmin is not None) and (reject_tmax is not None):
- if reject_tmin >= reject_tmax:
- raise ValueError('reject_tmin needs to be < reject_tmax')
- if not detrend in [None, 0, 1]:
- raise ValueError('detrend must be None, 0, or 1')
+ # Handle measurement info
+ info = cp.deepcopy(raw.info)
+ # make sure projs are really copied.
+ info['projs'] = [cp.deepcopy(p) for p in info['projs']]
- self.tmin = tmin
- self.tmax = tmax
- self.keep_comp = keep_comp
- self.dest_comp = dest_comp
- self.baseline = baseline
- self.preload = preload
- self.reject = reject
- self.reject_tmin = reject_tmin
- self.reject_tmax = reject_tmax
- self.flat = flat
+ if event_id is None: # convert to int to make typing-checks happy
+ event_id = dict((str(e), int(e)) for e in np.unique(events[:, 2]))
proj = proj or raw.proj # proj is on when applied in Raw
+
+ # call _BaseEpochs constructor
+ super(Epochs, self).__init__(info, event_id, tmin, tmax,
+ baseline=baseline, picks=picks, name=name,
+ keep_comp=keep_comp, dest_comp=dest_comp,
+ reject=reject, flat=flat, decim=decim,
+ reject_tmin=reject_tmin,
+ reject_tmax=reject_tmax, detrend=detrend,
+ add_eeg_ref=add_eeg_ref, verbose=verbose)
+
+ # do the rest
+ self.raw = raw
+ proj = proj or raw.proj # proj is on when applied in Raw
if proj not in [True, 'delayed', False]:
raise ValueError(r"'proj' must either be 'True', 'False' or "
- "'delayed'")
+ "'delayed'")
self.proj = proj
-
- self.decim = decim = int(decim)
- self._bad_dropped = False
- self.drop_log = None
- self.detrend = detrend
-
- # Handle measurement info
- self.info = cp.deepcopy(raw.info)
- # make sure projs are really copied.
- self.info['projs'] = [cp.deepcopy(p) for p in self.info['projs']]
- if picks is None:
- picks = pick_types(raw.info, meg=True, eeg=True, stim=True,
- ecg=True, eog=True, misc=True, ref_meg=True,
- exclude=[])
- self.info['chs'] = [self.info['chs'][k] for k in picks]
- self.info['ch_names'] = [self.info['ch_names'][k] for k in picks]
- self.info['nchan'] = len(picks)
- self.picks = picks
-
- if len(picks) == 0:
- raise ValueError("Picks cannot be empty.")
-
if self._check_delayed():
logger.info('Entering delayed SSP mode.')
activate = False if self._check_delayed() else self.proj
self._projector, self.info = setup_proj(self.info, add_eeg_ref,
activate=activate)
-
- # XXX : deprecate CTF compensator
- if dest_comp is not None or keep_comp is not None:
- raise ValueError('current_comp and keep_comp are deprecated.'
- ' Use the compensation parameter in Raw.')
-
- # Select the desired events
- self.events = events
+ # Select the desired events
selected = in1d(events[:, 2], self.event_id.values())
self.events = events[selected]
-
+ if len(self.events) > 1:
+ if np.diff(self.events.astype(np.int64)[:, 0]).min() <= 0:
+ warnings.warn('The events passed to the Epochs constructor '
+ 'are not chronologically ordered.',
+ RuntimeWarning)
n_events = len(self.events)
-
if n_events > 0:
logger.info('%d matching events found' % n_events)
else:
raise ValueError('No desired events found.')
- # Handle times
- assert tmin < tmax
- sfreq = float(raw.info['sfreq'])
- n_times_min = int(round(tmin * sfreq))
- n_times_max = int(round(tmax * sfreq))
- times = np.arange(n_times_min, n_times_max + 1, dtype=np.float) / sfreq
- self.times = self._raw_times = times
- self._epoch_stop = ep_len = len(self.times)
- if decim > 1:
- new_sfreq = sfreq / decim
- lowpass = self.info['lowpass']
- if new_sfreq < 2.5 * lowpass: # nyquist says 2 but 2.5 is safer
- msg = ("The raw file indicates a low-pass frequency of %g Hz. "
- "The decim=%i parameter will result in a sampling "
- "frequency of %g Hz, which can cause aliasing "
- "artifacts." % (lowpass, decim, new_sfreq))
- warnings.warn(msg)
-
- i_start = n_times_min % decim
- self._decim_idx = slice(i_start, ep_len, decim)
- self.times = self.times[self._decim_idx]
- self.info['sfreq'] = new_sfreq
-
- # setup epoch rejection
- self._reject_setup()
-
+ self.preload = preload
if self.preload:
self._data = self._get_data_from_disk()
self.raw = None
@@ -338,8 +691,9 @@ class Epochs(ProjMixin):
if self.proj == 'delayed':
if self.reject is None:
raise RuntimeError('The delayed SSP mode was requested '
- 'but no rejection parameters are present. Please add '
- 'rejection parameters before using this option.')
+ 'but no rejection parameters are present. '
+ 'Please add rejection parameters before '
+ 'using this option.')
is_delayed = True
return is_delayed
@@ -399,12 +753,14 @@ class Epochs(ProjMixin):
else:
epochs += [epoch_raw]
- # in case the proj passed is True but self proj is not we have delayed SSP
+ # in case the proj passed is True but self proj is not we
+ # have delayed SSP
if self.proj != proj: # so append another unprojected epoch
epochs += [epoch_raw.copy()]
- # only preprocess first candidate, to make delayed SSP working we need to
- # postpone the preprocessing since projection comes first.
+ # only preprocess first candidate, to make delayed SSP working
+ # we need to postpone the preprocessing since projection comes
+ # first.
epochs[0] = self._preprocess(epochs[0], verbose)
# return a second None if nothing is projected
@@ -419,11 +775,17 @@ class Epochs(ProjMixin):
"""
if self.detrend is not None:
picks = pick_types(self.info, meg=True, eeg=True, stim=False,
- eog=False, ecg=False, emg=False, exclude=[])
+ ref_meg=False, eog=False, ecg=False,
+ emg=False, exclude=[])
epoch[picks] = detrend(epoch[picks], self.detrend, axis=1)
# Baseline correct
epoch = rescale(epoch, self._raw_times, self.baseline, 'mean',
- copy=False, verbose=verbose)
+ copy=False, verbose=verbose)
+
+ # handle offset
+ if self._offset is not None:
+ epoch += self._offset
+
# Decimate
if self.decim > 1:
epoch = epoch[:, self._decim_idx]
@@ -561,7 +923,7 @@ class Epochs(ProjMixin):
else:
idxs = np.nonzero(self.times >= self.reject_tmin)[0]
reject_imin = idxs[0]
- if self.reject_tmax is None:
+ if self.reject_tmax is None:
reject_imax = None
else:
idxs = np.nonzero(self.times <= self.reject_tmax)[0]
@@ -586,7 +948,7 @@ class Epochs(ProjMixin):
self._current = 0
return self
- def next(self):
+ def next(self, return_event_id=False):
"""To make iteration over epochs easy.
"""
if self.preload:
@@ -610,7 +972,12 @@ class Epochs(ProjMixin):
if self._check_delayed():
epoch = self._preprocess(epoch_raw)
- return epoch
+ if not return_event_id:
+ return epoch
+ else:
+ return epoch, self.events[self._current - 1][-1]
+
+ return epoch if not return_event_id else epoch, self.event_id
def __repr__(self):
""" Build string representation
@@ -669,106 +1036,6 @@ class Epochs(ProjMixin):
return epochs
- def average(self, picks=None):
- """Compute average of epochs
-
- Parameters
- ----------
-
- picks : None | array of int
- If None only MEG and EEG channels are kept
- otherwise the channels indices in picks are kept.
-
- Returns
- -------
- evoked : Evoked instance
- The averaged epochs
- """
-
- return self._compute_mean_or_stderr(picks, 'ave')
-
- def standard_error(self, picks=None):
- """Compute standard error over epochs
-
- Parameters
- ----------
- picks : None | array of int
- If None only MEG and EEG channels are kept
- otherwise the channels indices in picks are kept.
-
- Returns
- -------
- evoked : Evoked instance
- The standard error over epochs
- """
- return self._compute_mean_or_stderr(picks, 'stderr')
-
- def _compute_mean_or_stderr(self, picks, mode='ave'):
- """Compute the mean or std over epochs and return Evoked"""
-
- _do_std = True if mode == 'stderr' else False
- evoked = Evoked(None)
- evoked.info = cp.deepcopy(self.info)
- # make sure projs are really copied.
- evoked.info['projs'] = [cp.deepcopy(p) for p in self.info['projs']]
- n_channels = len(self.ch_names)
- n_times = len(self.times)
- if self.preload:
- n_events = len(self.events)
- if not _do_std:
- data = np.mean(self._data, axis=0)
- else:
- data = np.std(self._data, axis=0)
- assert len(self.events) == len(self._data)
- else:
- data = np.zeros((n_channels, n_times))
- n_events = 0
- for e in self:
- data += e
- n_events += 1
- data /= n_events
- # convert to stderr if requested, could do in one pass but do in
- # two (slower) in case there are large numbers
- if _do_std:
- data_mean = cp.copy(data)
- data.fill(0.)
- for e in self:
- data += (e - data_mean) ** 2
- data = np.sqrt(data / n_events)
-
- evoked.data = data
- evoked.times = self.times.copy()
- evoked.comment = self.name
- evoked.nave = n_events
- evoked.first = int(self.times[0] * self.info['sfreq'])
- evoked.last = evoked.first + len(self.times) - 1
- if not _do_std:
- evoked._aspect_kind = FIFF.FIFFV_ASPECT_AVERAGE
- else:
- evoked._aspect_kind = FIFF.FIFFV_ASPECT_STD_ERR
- evoked.data /= np.sqrt(evoked.nave)
- evoked.kind = aspect_rev.get(str(evoked._aspect_kind), 'Unknown')
-
- # dropping EOG, ECG and STIM channels. Keeping only data
- if picks is None:
- picks = pick_types(evoked.info, meg=True, eeg=True,
- stim=False, eog=False, ecg=False,
- emg=False, ref_meg=True, exclude=[])
- if len(picks) == 0:
- raise ValueError('No data channel found when averaging.')
-
- picks = np.sort(picks) # make sure channel order does not change
- evoked.info['chs'] = [evoked.info['chs'][k] for k in picks]
- evoked.info['ch_names'] = [evoked.info['ch_names'][k]
- for k in picks]
- evoked.info['nchan'] = len(picks)
- evoked.data = evoked.data[picks]
- # otherwise the apply_proj will be confused
- evoked.proj = True if self.proj is True else None
- evoked.verbose = self.verbose
-
- return evoked
-
def crop(self, tmin=None, tmax=None, copy=False):
"""Crops a time interval from epochs object.
@@ -999,9 +1266,9 @@ class Epochs(ProjMixin):
mindex = list()
mindex.append(('condition', np.repeat(names, shape[2])))
mindex.append(('time', np.tile(self.times, shape[0]) *
- scale_time)) # if 'epoch' in index:
+ scale_time)) # if 'epoch' in index:
mindex.append(('epoch', np.repeat(np.arange(shape[0]),
- shape[2])))
+ shape[2])))
assert all(len(mdx) == len(mindex[0]) for mdx in mindex)
col_names = [self.ch_names[k] for k in picks]
@@ -1010,9 +1277,9 @@ class Epochs(ProjMixin):
[df.insert(i, k, v) for i, (k, v) in enumerate(mindex)]
if index is not None:
with warnings.catch_warnings(True):
+ if 'time' in index:
+ df['time'] = df['time'].astype(np.int64)
df.set_index(index, inplace=True)
- if 'time' in df.index.names and hasattr(df.index, 'levels'):
- df.index.levels[1] = df.index.levels[1].astype(int)
return df
@@ -1145,10 +1412,6 @@ class Epochs(ProjMixin):
# actually remove the indices
return epochs, indices
- @property
- def ch_names(self):
- return self.info['ch_names']
-
def combine_event_ids(epochs, old_event_ids, new_event_id, copy=True):
"""Collapse event_ids from an epochs instance into a new event_id
@@ -1465,6 +1728,7 @@ def read_epochs(fname, proj=True, add_eeg_ref=True, verbose=None):
epochs.event_id = (dict((str(e), e) for e in np.unique(events[:, 2]))
if mappings is None else mappings)
epochs.verbose = verbose
+ epochs.drop_log = []
fid.close()
return epochs
diff --git a/mne/event.py b/mne/event.py
index 0bc6c5f..05c4d76 100644
--- a/mne/event.py
+++ b/mne/event.py
@@ -9,17 +9,13 @@
import numpy as np
from os.path import splitext
-import logging
-logger = logging.getLogger('mne')
-
from .fiff.constants import FIFF
from .fiff.tree import dir_tree_find
from .fiff.tag import read_tag
from .fiff.open import fiff_open
from .fiff.write import write_int, start_block, start_file, end_block, end_file
from .fiff.pick import pick_channels
-from .utils import get_config
-from . import verbose
+from .utils import get_config, logger, verbose
def pick_events(events, include=None, exclude=None):
@@ -269,7 +265,53 @@ def write_events(filename, event_list):
f.close()
-def find_stim_steps(raw, pad_start=None, pad_stop=None, merge=0, stim_channel=None):
+def _find_stim_steps(data, first_samp, pad_start=None, pad_stop=None, merge=0):
+ changed = np.diff(data, axis=1) != 0
+ idx = np.where(np.all(changed, axis=0))[0]
+ if len(idx) == 0:
+ return np.empty((0, 3), dtype='int32')
+
+ pre_step = data[0, idx]
+ idx += 1
+ post_step = data[0, idx]
+ idx += first_samp
+ steps = np.c_[idx, pre_step, post_step]
+
+ if pad_start is not None:
+ v = steps[0, 1]
+ if v != pad_start:
+ steps = np.insert(steps, 0, [0, pad_start, v], axis=0)
+
+ if pad_stop is not None:
+ v = steps[-1, 2]
+ if v != pad_stop:
+ last_idx = len(data[0]) + first_samp
+ steps = np.append(steps, [[last_idx, v, pad_stop]], axis=0)
+
+ if merge != 0:
+ diff = np.diff(steps[:, 0])
+ idx = (diff <= abs(merge))
+ if np.any(idx):
+ where = np.where(idx)[0]
+ keep = (idx == False)
+ if merge > 0:
+ # drop the earlier event
+ steps[where + 1, 1] = steps[where, 1]
+ keep = np.append(keep, True)
+ else:
+ # drop the later event
+ steps[where, 2] = steps[where + 1, 2]
+ keep = np.insert(keep, 0, True)
+
+ is_step = (steps[:, 1] != steps[:, 2])
+ keep = np.logical_and(keep, is_step)
+ steps = steps[keep]
+
+ return steps
+
+
+def find_stim_steps(raw, pad_start=None, pad_stop=None, merge=0,
+ stim_channel=None):
"""Find all steps in data from a stim channel
Parameters
@@ -304,61 +346,88 @@ def find_stim_steps(raw, pad_start=None, pad_stop=None, merge=0, stim_channel=No
--------
find_events : More sophisticated options for finding events in a Raw file.
"""
+
# pull stim channel from config if necessary
stim_channel = _get_stim_channel(stim_channel)
- pick = pick_channels(raw.info['ch_names'], include=stim_channel)
- if len(pick) == 0:
+ picks = pick_channels(raw.info['ch_names'], include=stim_channel)
+ if len(picks) == 0:
raise ValueError('No stim channel found to extract event triggers.')
- data, _ = raw[pick, :]
+ data, _ = raw[picks, :]
if np.any(data < 0):
logger.warn('Trigger channel contains negative values. '
'Taking absolute value.')
data = np.abs(data) # make sure trig channel is positive
data = data.astype(np.int)
- changed = np.diff(data, axis=1) != 0
- idx = np.where(np.all(changed, axis=0))[0]
- if len(idx) == 0:
- return np.empty((0, 3), dtype='int32')
+ return _find_stim_steps(data, raw.first_samp, pad_start=pad_start,
+ pad_stop=pad_stop, merge=merge)
- pre_step = data[0, idx]
- idx += 1
- post_step = data[0, idx]
- idx += raw.first_samp
- steps = np.c_[idx, pre_step, post_step]
- if pad_start is not None:
- v = steps[0, 1]
- if v != pad_start:
- steps = np.insert(steps, 0, [0, pad_start, v], axis=0)
+ at verbose
+def _find_events(data, first_samp, verbose=None, output='onset',
+ consecutive='increasing', min_samples=0):
+ """Helper function for find events"""
+ if min_samples > 0:
+ merge = int(min_samples // 1)
+ if merge == min_samples:
+ merge -= 1
+ else:
+ merge = 0
- if pad_stop is not None:
- v = steps[-1, 2]
- if v != pad_stop:
- last_idx = len(data[0]) + raw.first_samp
- steps = np.append(steps, [[last_idx, v, pad_stop]], axis=0)
+ if np.any(data < 0):
+ logger.warn('Trigger channel contains negative values. '
+ 'Taking absolute value.')
+ data = np.abs(data) # make sure trig channel is positive
+ data = data.astype(np.int)
- if merge != 0:
- diff = np.diff(steps[:, 0])
- idx = (diff <= abs(merge))
- if np.any(idx):
- where = np.where(idx)[0]
- keep = (idx == False)
- if merge > 0:
- # drop the earlier event
- steps[where + 1, 1] = steps[where, 1]
- keep = np.append(keep, True)
- else:
- # drop the later event
- steps[where, 2] = steps[where + 1, 2]
- keep = np.insert(keep, 0, True)
+ events = _find_stim_steps(data, first_samp, pad_stop=0, merge=merge)
- is_step = (steps[:, 1] != steps[:, 2])
- keep = np.logical_and(keep, is_step)
- steps = steps[keep]
+ # Determine event onsets and offsets
+ if consecutive == 'increasing':
+ onsets = (events[:, 2] > events[:, 1])
+ offsets = np.logical_and(np.logical_or(onsets, (events[:, 2] == 0)),
+ (events[:, 1] > 0))
+ elif consecutive:
+ onsets = (events[:, 2] > 0)
+ offsets = (events[:, 1] > 0)
+ else:
+ onsets = (events[:, 1] == 0)
+ offsets = (events[:, 2] == 0)
- return steps
+ onset_idx = np.where(onsets)[0]
+ offset_idx = np.where(offsets)[0]
+
+ if len(onset_idx) == 0 or len(offset_idx) == 0:
+ return np.empty((0, 3), dtype='int32')
+
+ # delete orphaned onsets/offsets
+ if onset_idx[0] > offset_idx[0]:
+ logger.info("Removing orphaned offset at the beginning of the file.")
+ offset_idx = np.delete(offset_idx, 0)
+
+ if onset_idx[-1] > offset_idx[-1]:
+ logger.info("Removing orphaned onset at the end of the file.")
+ onset_idx = np.delete(onset_idx, -1)
+
+ if output == 'onset':
+ events = events[onset_idx]
+ elif output == 'step':
+ idx = np.union1d(onset_idx, offset_idx)
+ events = events[idx]
+ elif output == 'offset':
+ event_id = events[onset_idx, 2]
+ events = events[offset_idx]
+ events[:, 1] = events[:, 2]
+ events[:, 2] = event_id
+ events[:, 0] -= 1
+ else:
+ raise Exception("Invalid output parameter %r" % output)
+
+ logger.info("%s events found" % len(events))
+ logger.info("Events id: %s" % np.unique(events[:, 2]))
+
+ return events
@verbose
@@ -458,60 +527,19 @@ def find_events(raw, stim_channel=None, verbose=None, output='onset',
--------
find_stim_steps : Find all the steps in the stim channel.
"""
- if min_duration > 0:
- min_samples = min_duration * raw.info['sfreq']
- merge = int(min_samples // 1)
- if merge == min_samples:
- merge -= 1
- else:
- merge = 0
+ min_samples = min_duration * raw.info['sfreq']
- events = find_stim_steps(raw, pad_stop=0, merge=merge,
- stim_channel=stim_channel)
-
- # Determine event onsets and offsets
- if consecutive == 'increasing':
- onsets = (events[:, 2] > events[:, 1])
- offsets = np.logical_and(np.logical_or(onsets, (events[:, 2] == 0)),
- (events[:, 1] > 0))
- elif consecutive:
- onsets = (events[:, 2] > 0)
- offsets = (events[:, 1] > 0)
- else:
- onsets = (events[:, 1] == 0)
- offsets = (events[:, 2] == 0)
-
- onset_idx = np.where(onsets)[0]
- offset_idx = np.where(offsets)[0]
-
- if len(onset_idx) == 0 or len(offset_idx) == 0:
- return np.empty((0, 3), dtype='int32')
-
- # delete orphaned onsets/offsets
- if onset_idx[0] > offset_idx[0]:
- logger.info("Removing orphaned offset at the beginning of the file.")
- offset_idx = np.delete(offset_idx, 0)
+ # pull stim channel from config if necessary
+ stim_channel = _get_stim_channel(stim_channel)
- if onset_idx[-1] > offset_idx[-1]:
- logger.info("Removing orphaned onset at the end of the file.")
- onset_idx = np.delete(onset_idx, -1)
+ pick = pick_channels(raw.info['ch_names'], include=stim_channel)
+ if len(pick) == 0:
+ raise ValueError('No stim channel found to extract event triggers.')
+ data, _ = raw[pick, :]
- if output == 'onset':
- events = events[onset_idx]
- elif output == 'step':
- idx = np.union1d(onset_idx, offset_idx)
- events = events[idx]
- elif output == 'offset':
- event_id = events[onset_idx, 2]
- events = events[offset_idx]
- events[:, 1] = events[:, 2]
- events[:, 2] = event_id
- events[:, 0] -= 1
- else:
- raise Exception("Invalid output parameter %r" % output)
+ events = _find_events(data, raw.first_samp, verbose=verbose, output=output,
+ consecutive=consecutive, min_samples=min_samples)
- logger.info("%s events found" % len(events))
- logger.info("Events id: %s" % np.unique(events[:, 2]))
return events
diff --git a/mne/fiff/__init__.py b/mne/fiff/__init__.py
index 5071794..1b5af68 100644
--- a/mne/fiff/__init__.py
+++ b/mne/fiff/__init__.py
@@ -8,13 +8,16 @@
from .constants import FIFF
from .open import fiff_open, show_fiff
from .evoked import Evoked, read_evoked, write_evoked
-from .raw import Raw, start_writing_raw, write_raw_buffer, \
- finish_writing_raw, concatenate_raws
-from .pick import pick_types, pick_channels, pick_types_evoked, \
- pick_channels_regexp, pick_channels_forward, \
- pick_types_forward, pick_channels_cov, \
- pick_channels_evoked
+from .meas_info import read_fiducials, write_fiducials, read_info
+from .raw import (Raw, start_writing_raw, write_raw_buffer,
+ finish_writing_raw, concatenate_raws, get_chpi_positions,
+ set_eeg_reference)
+from .pick import (pick_types, pick_channels, pick_types_evoked,
+ pick_channels_regexp, pick_channels_forward,
+ pick_types_forward, pick_channels_cov,
+ pick_channels_evoked, pick_info, _has_kit_refs)
from .proj import proj_equal, make_eeg_average_ref_proj
from .cov import read_cov, write_cov
from . import bti
+from . import kit
diff --git a/mne/fiff/brainvision/__init__.py b/mne/fiff/brainvision/__init__.py
new file mode 100644
index 0000000..8d992e4
--- /dev/null
+++ b/mne/fiff/brainvision/__init__.py
@@ -0,0 +1,7 @@
+"""Brainvision module for conversion to FIF"""
+
+# Author: Teon Brooks <teon at nyu.edu>
+#
+# License: BSD (3-clause)
+
+from .brainvision import read_raw_brainvision
diff --git a/mne/fiff/brainvision/brainvision.py b/mne/fiff/brainvision/brainvision.py
new file mode 100644
index 0000000..afbe9f7
--- /dev/null
+++ b/mne/fiff/brainvision/brainvision.py
@@ -0,0 +1,518 @@
+"""Conversion tool from Brain Vision EEG to FIF
+
+"""
+
+# Author: Teon Brooks <teon at nyu.edu>
+#
+# License: BSD (3-clause)
+
+import os
+import time
+import re
+import warnings
+from StringIO import StringIO
+from ConfigParser import SafeConfigParser
+
+import numpy as np
+
+from ...fiff import pick_types
+from ...transforms import als_ras_trans, apply_trans
+from ...utils import verbose, logger
+from ..raw import Raw
+from ..meas_info import Info
+from ..constants import FIFF
+from ...coreg import get_ras_to_neuromag_trans
+
+
+class RawBrainVision(Raw):
+ """Raw object from Brain Vision eeg file
+
+ Parameters
+ ----------
+ vdhr_fname : str
+ Path to the EEG header file.
+
+ elp_fname : str | None
+ Path to the elp file containing electrode positions.
+ If None, sensor locations are (0,0,0).
+
+ ch_names : list | None
+ A list of channel names in order of collection of electrode position
+ digitization.
+
+ preload : bool
+ If True, all data are loaded at initialization.
+ If False, data are not read until save.
+
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ See Also
+ --------
+ mne.fiff.Raw : Documentation of attribute and methods.
+ """
+ @verbose
+ def __init__(self, vhdr_fname, elp_fname=None, ch_names=None,
+ preload=False, verbose=None):
+ logger.info('Extracting eeg Parameters from %s...' % vhdr_fname)
+ vhdr_fname = os.path.abspath(vhdr_fname)
+ self.info, self._eeg_info = _get_eeg_info(vhdr_fname, elp_fname,
+ ch_names)
+ logger.info('Creating Raw.info structure...')
+
+ # Raw attributes
+ self.verbose = verbose
+ self._preloaded = False
+ self.fids = list()
+ self._projector = None
+ self.comp = None # no compensation for EEG
+ self.proj = False
+ self.first_samp = 0
+ f = open(self.info['file_id'])
+ f.seek(0, os.SEEK_END)
+ n_samples = f.tell()
+ dtype = int(self._eeg_info['dtype'][-1])
+ n_chan = self.info['nchan']
+ self.last_samp = (n_samples / (dtype * (n_chan - 1))) - 1
+
+ if preload:
+ self._preloaded = preload
+ logger.info('Reading raw data from %s...' % vhdr_fname)
+ self._data, _ = self._read_segment()
+ assert len(self._data) == self.info['nchan']
+
+ # Add time info
+ self._times = np.arange(self.first_samp, self.last_samp + 1,
+ dtype=np.float64)
+ self._times /= self.info['sfreq']
+ logger.info(' Range : %d ... %d = %9.3f ... %9.3f secs'
+ % (self.first_samp, self.last_samp,
+ float(self.first_samp) / self.info['sfreq'],
+ float(self.last_samp) / self.info['sfreq']))
+ logger.info('Ready.')
+
+ def __repr__(self):
+ n_chan = self.info['nchan']
+ data_range = self.last_samp - self.first_samp + 1
+ s = ('%r' % os.path.basename(self.info['file_id']),
+ "n_channels x n_times : %s x %s" % (n_chan, data_range))
+ return "<RawEEG | %s>" % ', '.join(s)
+
+ def _read_segment(self, start=0, stop=None, sel=None, verbose=None,
+ projector=None):
+ """Read a chunk of raw data
+
+ Parameters
+ ----------
+ start : int, (optional)
+ first sample to include (first is 0). If omitted, defaults to the
+ first sample in data.
+
+ stop : int, (optional)
+ First sample to not include.
+ If omitted, data is included to the end.
+
+ sel : array, optional
+ Indices of channels to select.
+
+ projector : array
+ SSP operator to apply to the data.
+
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ data : array, [channels x samples]
+ the data matrix (channels x samples).
+
+ times : array, [samples]
+ returns the time values corresponding to the samples.
+ """
+ if sel is None:
+ sel = range(self.info['nchan'])
+ elif len(sel) == 1 and sel[0] == 0 and start == 0 and stop == 1:
+ return (666, 666)
+ if projector is not None:
+ raise NotImplementedError('Currently does not handle projections.')
+ if stop is None:
+ stop = self.last_samp + 1
+ elif stop > self.last_samp + 1:
+ stop = self.last_samp + 1
+
+ # Initial checks
+ start = int(start)
+ stop = int(stop)
+
+ eeg_info = self._eeg_info
+ sfreq = self.info['sfreq']
+ n_chan = self.info['nchan']
+ cals = np.array([chan_info['cal'] for chan_info in self.info['chs']])
+ mults = np.array([chan_info['unit_mul'] for chan_info
+ in self.info['chs']])
+ picks = pick_types(self.info, meg=False, eeg=True, exclude=[])
+ n_eeg = picks.size
+ cals = np.atleast_2d(cals[picks])
+ mults = np.atleast_2d(mults[picks])
+
+ if start >= stop:
+ raise ValueError('No data in this range')
+
+ logger.info('Reading %d ... %d = %9.3f ... %9.3f secs...' %
+ (start, stop - 1, start / float(sfreq),
+ (stop - 1) / float(sfreq)))
+
+ with open(self.info['file_id'], 'rb') as f:
+ buffer_size = (stop - start)
+ pointer = start * n_chan
+ f.seek(pointer)
+ # extract data
+ data = np.fromfile(f, dtype=eeg_info['dtype'],
+ count=buffer_size * n_eeg)
+ if eeg_info['data_orientation'] == 'MULTIPLEXED':
+ data = data.reshape((n_eeg, -1), order='F')
+ elif eeg_info['data_orientation'] == 'VECTORIZED':
+ data = data.reshape((n_eeg, -1), order='C')
+
+ gains = cals * mults
+ data = data * gains.T
+
+ stim_channel = np.zeros(data.shape[1])
+ evts = _read_vmrk(eeg_info['marker_id'])
+ if evts is not None:
+ stim_channel[:evts.size] = evts
+ stim_channel = stim_channel[start:stop]
+
+ data = np.vstack((data, stim_channel))
+ data = data[sel]
+
+ logger.info('[done]')
+ times = np.arange(start, stop, dtype=float) / sfreq
+
+ return data, times
+
+
+def _read_vmrk(vmrk_fname):
+ """Extracts the event markers for vmrk file
+
+ Parameters
+ ----------
+ vmrk_fname : str
+ vmrk file to be read.
+
+ Returns
+ -------
+ stim_channel : array
+ An array containing the whole recording's event marking
+ """
+
+ with open(vmrk_fname) as f:
+ # setup config reader
+ assert (f.readline().strip() ==
+ 'Brain Vision Data Exchange Marker File, Version 1.0')
+
+ cfg = SafeConfigParser()
+ cfg.readfp(f)
+ events = []
+ for _, info in cfg.items('Marker Infos'):
+ mtype, mdesc, offset, duration = info.split(',')[:4]
+ if mtype == 'Stimulus':
+ trigger = int(re.findall('S\s?(\d+)', mdesc)[0])
+ offset, duration = int(offset), int(duration)
+ events.append((trigger, offset, offset + duration))
+ if events:
+ stim_channel = np.zeros(events[-1][2])
+ for event in events:
+ stim_channel[event[1]:event[2]] = trigger
+ else:
+ stim_channel = None
+
+ return stim_channel
+
+
+def _get_elp_locs(elp_fname, ch_names):
+ """Read a Polhemus ascii file
+
+ Parameters
+ ----------
+ elp_fname : str
+ Path to head shape file acquired from Polhemus system and saved in
+ ascii format.
+
+ ch_names : list
+ A list in order of EEG electrodes found in the Polhemus digitizer file.
+
+
+ Returns
+ -------
+ ch_locs : ndarray, shape = (n_points, 3)
+ Electrode points in Neuromag space.
+ """
+ pattern = re.compile(r'(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)')
+ with open(elp_fname) as fid:
+ elp = pattern.findall(fid.read())
+ elp = np.array(elp, dtype=float)
+ elp = apply_trans(als_ras_trans, elp)
+ nasion, lpa, rpa = elp[:3]
+ trans = get_ras_to_neuromag_trans(nasion, lpa, rpa)
+ elp = apply_trans(trans, elp[8:])
+ ch_locs = dict(zip(ch_names, elp))
+ fid = nasion, lpa, rpa
+
+ return fid, ch_locs
+
+
+def _get_eeg_info(vhdr_fname, elp_fname=None, ch_names=None, preload=False):
+ """Extracts all the information from the header file.
+
+ Parameters
+ ----------
+ vhdr_fname : str
+ Raw EEG header to be read.
+
+ elp_fname : str | None
+ Path to the elp file containing electrode positions.
+ If None, sensor locations are (0,0,0).
+
+ ch_names : list | None
+ A list of channel names in order of collection of electrode position
+ digitization.
+
+ preload : bool
+ If True, all data are loaded at initialization.
+ If False, data are not read until save.
+
+ Returns
+ -------
+ info : instance of Info
+ The measurement info.
+
+ edf_info : dict
+ A dict containing Brain Vision specific parameters.
+ """
+
+ info = Info()
+ # Some keys to be consistent with FIF measurement info
+ info['meas_id'] = None
+ info['projs'] = []
+ info['comps'] = []
+ info['bads'] = []
+ info['acq_pars'], info['acq_stim'] = None, None
+ info['filename'] = vhdr_fname
+ info['ctf_head_t'] = None
+ info['dev_ctf_t'] = []
+ info['filenames'] = []
+ info['dig'] = None
+ info['dev_head_t'] = None
+ info['proj_id'] = None
+ info['proj_name'] = None
+ info['experimenter'] = None
+ info['description'] = None
+ info['buffer_size_sec'] = 10.
+ info['orig_blocks'] = None
+ info['orig_fid_str'] = None
+
+ eeg_info = {}
+
+ with open(vhdr_fname, 'rb') as f:
+ # extract the first section to resemble a cfg
+ assert (f.readline().strip() ==
+ 'Brain Vision Data Exchange Header File Version 1.0')
+ settings = f.read()
+
+ params, settings = settings.split('[Comment]')
+ cfg = SafeConfigParser()
+ cfg.readfp(StringIO(params))
+
+ # get sampling info
+ # Sampling interval is given in microsec
+ sfreq = 1e6 / cfg.getfloat('Common Infos', 'SamplingInterval')
+ sfreq = int(sfreq)
+ n_chan = cfg.getint('Common Infos', 'NumberOfChannels')
+
+ # check binary format
+ assert cfg.get('Common Infos', 'DataFormat') == 'BINARY'
+ eeg_info['data_orientation'] = cfg.get('Common Infos', 'DataOrientation')
+ if not (eeg_info['data_orientation'] == 'MULTIPLEXED' or
+ eeg_info['data_orientation'] == 'VECTORIZED'):
+ raise NotImplementedError('Data Orientation %s is not supported'
+ % eeg_info['data_orientation'])
+
+ binary_format = cfg.get('Binary Infos', 'BinaryFormat')
+ if binary_format == 'INT_16':
+ eeg_info['dtype'] = '<i2'
+ elif binary_format == 'INT_32':
+ eeg_info['dtype'] = '<i4'
+ elif binary_format == 'IEEE_FLOAT_32':
+ eeg_info['dtype'] = '<f4'
+ else:
+ raise NotImplementedError('Datatype %s is not supported'
+ % binary_format)
+
+ # load channel labels
+ ch_names = ['UNKNOWN'] * n_chan
+ cals = np.ones(n_chan) * np.nan
+ units = []
+ for chan, props in cfg.items('Channel Infos'):
+ n = int(re.findall(r'ch(\d+)', chan)[0])
+ name, _, resolution, unit = props.split(',')[:4]
+ ch_names[n - 1] = name
+ cals[n - 1] = resolution
+ if unit == '\xc2\xb5V':
+ units.append(1e-6)
+ elif unit == 'V':
+ units.append(0)
+ else:
+ units.append(unit)
+
+ # Attempts to extract filtering info from header. If not found, both are
+ # set to zero.
+ settings = settings.splitlines()
+ idx = None
+ if 'Channels' in settings:
+ idx = settings.index('Channels')
+ settings = settings[idx + 1:]
+ for idx, setting in enumerate(settings):
+ if re.match('#\s+Name', setting):
+ break
+ else:
+ idx = None
+ if idx:
+ lowpass = []
+ highpass = []
+ for i, ch in enumerate(ch_names, 1):
+ line = settings[idx + i].split()
+ assert ch in line
+ highpass.append(line[5])
+ lowpass.append(line[6])
+ if len(highpass) == 0:
+ info['highpass'] = None
+ elif all(highpass):
+ if highpass[0] == 'NaN':
+ info['highpass'] = None
+ elif highpass[0] == 'DC':
+ info['highpass'] = 0
+ else:
+ info['highpass'] = int(highpass[0])
+ else:
+ info['highpass'] = np.min(highpass)
+ warnings.warn('%s' % ('Channels contain different highpass '
+ 'filters. Highest filter setting will '
+ 'be stored.'))
+ if len(lowpass) == 0:
+ info['lowpass'] = None
+ elif all(lowpass):
+ if lowpass[0] == 'NaN':
+ info['lowpass'] = None
+ else:
+ info['lowpass'] = int(lowpass[0])
+ else:
+ info['lowpass'] = np.min(lowpass)
+ warnings.warn('%s' % ('Channels contain different lowpass filters.'
+ ' Lowest filter setting will be stored.'))
+ else:
+ info['highpass'] = None
+ info['lowpass'] = None
+
+ # locate EEG and marker files
+ path = os.path.dirname(vhdr_fname)
+ info['file_id'] = os.path.join(path, cfg.get('Common Infos', 'DataFile'))
+ eeg_info['marker_id'] = os.path.join(path, cfg.get('Common Infos',
+ 'MarkerFile'))
+ info['meas_date'] = int(time.time())
+
+ # Creates a list of dicts of eeg channels for raw.info
+ logger.info('Setting channel info structure...')
+ info['chs'] = []
+ info['nchan'] = n_chan
+ info['ch_names'] = ch_names
+ info['sfreq'] = sfreq
+ if elp_fname and ch_names:
+ fid, ch_locs = _get_elp_locs(elp_fname, ch_names)
+ nasion, lpa, rpa = fid
+ info['dig'] = [{'r': nasion, 'ident': FIFF.FIFFV_POINT_NASION,
+ 'kind': FIFF.FIFFV_POINT_CARDINAL,
+ 'coord_frame': FIFF.FIFFV_COORD_HEAD},
+ {'r': lpa, 'ident': FIFF.FIFFV_POINT_LPA,
+ 'kind': FIFF.FIFFV_POINT_CARDINAL,
+ 'coord_frame': FIFF.FIFFV_COORD_HEAD},
+ {'r': rpa, 'ident': FIFF.FIFFV_POINT_RPA,
+ 'kind': FIFF.FIFFV_POINT_CARDINAL,
+ 'coord_frame': FIFF.FIFFV_COORD_HEAD}]
+ else:
+ ch_locs = None
+
+ for idx, ch_info in enumerate(zip(ch_names, cals, units), 1):
+ ch_name, cal, unit_mul = ch_info
+ chan_info = {}
+ chan_info['ch_name'] = ch_name
+ chan_info['kind'] = FIFF.FIFFV_EEG_CH
+ chan_info['coil_type'] = FIFF.FIFFV_COIL_EEG
+ chan_info['logno'] = idx
+ chan_info['scanno'] = idx
+ chan_info['cal'] = cal
+ chan_info['range'] = 1.
+ chan_info['unit_mul'] = unit_mul
+ chan_info['unit'] = FIFF.FIFF_UNIT_V
+ chan_info['coord_frame'] = FIFF.FIFFV_COORD_HEAD
+ if ch_locs:
+ if ch_name in ch_locs:
+ chan_info['eeg_loc'] = ch_locs[ch_name]
+ else:
+ chan_info['eeg_loc'] = np.zeros(3)
+ chan_info['loc'] = np.zeros(12)
+ chan_info['loc'][:3] = chan_info['eeg_loc']
+ info['chs'].append(chan_info)
+
+ # for stim channel
+ stim_channel = _read_vmrk(eeg_info['marker_id'])
+ if stim_channel is not None:
+ chan_info = {}
+ chan_info['ch_name'] = 'STI 014'
+ chan_info['kind'] = FIFF.FIFFV_STIM_CH
+ chan_info['coil_type'] = FIFF.FIFFV_COIL_NONE
+ chan_info['logno'] = idx + 1
+ chan_info['scanno'] = idx + 1
+ chan_info['cal'] = 1
+ chan_info['range'] = 1
+ chan_info['unit_mul'] = 0
+ chan_info['unit'] = FIFF.FIFF_UNIT_NONE
+ chan_info['eeg_loc'] = np.zeros(3)
+ chan_info['loc'] = np.zeros(12)
+ info['nchan'] = n_chan + 1
+ info['ch_names'].append(chan_info['ch_name'])
+ info['chs'].append(chan_info)
+
+ return info, eeg_info
+
+
+def read_raw_brainvision(vhdr_fname, elp_fname=None, ch_names=None,
+ preload=False, verbose=None):
+ """Reader for Brain Vision EEG file
+
+ Parameters
+ ----------
+ vhdr_fname : str
+ Path to the EEG header file.
+
+ elp_fname : str | None
+ Path to the elp file containing electrode positions.
+ If None, sensor locations are (0,0,0).
+
+ ch_names : list | None
+ A list of channel names in order of collection of electrode position
+ digitization.
+
+ preload : bool
+ If True, all data are loaded at initialization.
+ If False, data are not read until save.
+
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ See Also
+ --------
+ mne.fiff.Raw : Documentation of attribute and methods.
+ """
+ return RawBrainVision(vhdr_fname=vhdr_fname, elp_fname=elp_fname,
+ ch_names=ch_names, preload=preload, verbose=verbose)
diff --git a/mne/fiff/brainvision/tests/__init__.py b/mne/fiff/brainvision/tests/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/mne/fiff/brainvision/tests/__init__.py
@@ -0,0 +1 @@
+
diff --git a/mne/fiff/brainvision/tests/data/test.eeg b/mne/fiff/brainvision/tests/data/test.eeg
new file mode 100755
index 0000000..b531faf
Binary files /dev/null and b/mne/fiff/brainvision/tests/data/test.eeg differ
diff --git a/mne/fiff/brainvision/tests/data/test.vhdr b/mne/fiff/brainvision/tests/data/test.vhdr
new file mode 100755
index 0000000..697ce92
--- /dev/null
+++ b/mne/fiff/brainvision/tests/data/test.vhdr
@@ -0,0 +1,142 @@
+Brain Vision Data Exchange Header File Version 1.0
+; Data created by the Vision Recorder
+
+[Common Infos]
+Codepage=UTF-8
+DataFile=test.eeg
+MarkerFile=test.vmrk
+DataFormat=BINARY
+; Data orientation: MULTIPLEXED=ch1,pt1, ch2,pt1 ...
+DataOrientation=MULTIPLEXED
+NumberOfChannels=32
+; Sampling interval in microseconds
+SamplingInterval=1000
+
+[Binary Infos]
+BinaryFormat=INT_16
+
+[Channel Infos]
+; Each entry: Ch<Channel number>=<Name>,<Reference channel name>,
+; <Resolution in "Unit">,<Unit>, Future extensions..
+; Fields are delimited by commas, some fields might be omitted (empty).
+; Commas in channel names are coded as "\1".
+Ch1=FP1,,0.5,µV
+Ch2=FP2,,0.5,µV
+Ch3=F3,,0.5,µV
+Ch4=F4,,0.5,µV
+Ch5=C3,,0.5,µV
+Ch6=C4,,0.5,µV
+Ch7=P3,,0.5,µV
+Ch8=P4,,0.5,µV
+Ch9=O1,,0.5,µV
+Ch10=O2,,0.5,µV
+Ch11=F7,,0.5,µV
+Ch12=F8,,0.5,µV
+Ch13=P7,,0.5,µV
+Ch14=P8,,0.5,µV
+Ch15=Fz,,0.5,µV
+Ch16=FCz,,0.5,µV
+Ch17=Cz,,0.5,µV
+Ch18=CPz,,0.5,µV
+Ch19=Pz,,0.5,µV
+Ch20=POz,,0.5,µV
+Ch21=FC1,,0.5,µV
+Ch22=FC2,,0.5,µV
+Ch23=CP1,,0.5,µV
+Ch24=CP2,,0.5,µV
+Ch25=FC5,,0.5,µV
+Ch26=FC6,,0.5,µV
+Ch27=CP5,,0.5,µV
+Ch28=CP6,,0.5,µV
+Ch29=HL,,0.5,µV
+Ch30=HR,,0.5,µV
+Ch31=Vb,,0.5,µV
+Ch32=ReRef,,0.5,µV
+
+[Comment]
+
+A m p l i f i e r S e t u p
+============================
+Number of channels: 32
+Sampling Rate [Hz]: 1000
+Sampling Interval [µS]: 1000
+
+Channels
+--------
+# Name Phys. Chn. Resolution / Unit Low Cutoff [s] High Cutoff [Hz] Notch [Hz] Series Res. [kOhm] Gradient Offset
+1 FP1 1 0.5 µV DC 250 Off 0
+2 FP2 2 0.5 µV DC 250 Off 0
+3 F3 3 0.5 µV DC 250 Off 0
+4 F4 4 0.5 µV DC 250 Off 0
+5 C3 5 0.5 µV DC 250 Off 0
+6 C4 6 0.5 µV DC 250 Off 0
+7 P3 7 0.5 µV DC 250 Off 0
+8 P4 8 0.5 µV DC 250 Off 0
+9 O1 9 0.5 µV DC 250 Off 0
+10 O2 10 0.5 µV DC 250 Off 0
+11 F7 11 0.5 µV DC 250 Off 0
+12 F8 12 0.5 µV DC 250 Off 0
+13 P7 13 0.5 µV DC 250 Off 0
+14 P8 14 0.5 µV DC 250 Off 0
+15 Fz 15 0.5 µV DC 250 Off 0
+16 FCz 16 0.5 µV DC 250 Off 0
+17 Cz 17 0.5 µV DC 250 Off 0
+18 CPz 18 0.5 µV DC 250 Off 0
+19 Pz 19 0.5 µV DC 250 Off 0
+20 POz 20 0.5 µV DC 250 Off 0
+21 FC1 21 0.5 µV DC 250 Off 0
+22 FC2 22 0.5 µV DC 250 Off 0
+23 CP1 23 0.5 µV DC 250 Off 0
+24 CP2 24 0.5 µV DC 250 Off 0
+25 FC5 25 0.5 µV DC 250 Off 0
+26 FC6 26 0.5 µV DC 250 Off 0
+27 CP5 27 0.5 µV DC 250 Off 0
+28 CP6 28 0.5 µV DC 250 Off 0
+29 HL 29 0.5 µV DC 250 Off 0
+30 HR 30 0.5 µV DC 250 Off 0
+31 Vb 31 0.5 µV DC 250 Off 0
+32 ReRef 32 0.5 µV DC 250 Off 0
+
+S o f t w a r e F i l t e r s
+==============================
+Disabled
+
+
+Data Electrodes Selected Impedance Measurement Range: 0 - 100 kOhm
+Ground Electrode Selected Impedance Measurement Range: 0 - 10 kOhm
+Reference Electrode Selected Impedance Measurement Range: 0 - 10 kOhm
+Impedance [kOhm] at 16:12:27 :
+FP1: ???
+FP2: ???
+F3: ???
+F4: ???
+C3: ???
+C4: ???
+P3: ???
+P4: ???
+O1: ???
+O2: ???
+F7: ???
+F8: ???
+P7: ???
+P8: ???
+Fz: ???
+FCz: ???
+Cz: ???
+CPz: ???
+Pz: ???
+POz: ???
+FC1: ???
+FC2: ???
+CP1: ???
+CP2: ???
+FC5: ???
+FC6: ???
+CP5: ???
+CP6: ???
+HL: ???
+HR: ???
+Vb: ???
+ReRef: ???
+Ref: 0
+Gnd: 4
diff --git a/mne/fiff/brainvision/tests/data/test.vmrk b/mne/fiff/brainvision/tests/data/test.vmrk
new file mode 100755
index 0000000..c14d4f3
--- /dev/null
+++ b/mne/fiff/brainvision/tests/data/test.vmrk
@@ -0,0 +1,22 @@
+Brain Vision Data Exchange Marker File, Version 1.0
+
+[Common Infos]
+Codepage=UTF-8
+DataFile=test.eeg
+
+[Marker Infos]
+; Each entry: Mk<Marker number>=<Type>,<Description>,<Position in data points>,
+; <Size in data points>, <Channel number (0 = marker is related to all channels)>
+; Fields are delimited by commas, some fields might be omitted (empty).
+; Commas in type or description text are coded as "\1".
+Mk1=New Segment,,1,1,0,20131113161403794232
+Mk2=Stimulus,S253,487,1,0
+Mk3=Stimulus,S255,497,1,0
+Mk4=Stimulus,S254,1770,1,0
+Mk5=Stimulus,S255,1780,1,0
+Mk6=Stimulus,S254,3253,1,0
+Mk7=Stimulus,S255,3263,1,0
+Mk8=Stimulus,S253,4936,1,0
+Mk9=Stimulus,S255,4946,1,0
+Mk10=Stimulus,S254,6620,1,0
+Mk11=Stimulus,S255,6630,1,0
diff --git a/mne/fiff/brainvision/tests/data/test_bin_raw.fif b/mne/fiff/brainvision/tests/data/test_bin_raw.fif
new file mode 100644
index 0000000..a62b99c
Binary files /dev/null and b/mne/fiff/brainvision/tests/data/test_bin_raw.fif differ
diff --git a/mne/fiff/brainvision/tests/data/test_elp.txt b/mne/fiff/brainvision/tests/data/test_elp.txt
new file mode 100644
index 0000000..3754a67
--- /dev/null
+++ b/mne/fiff/brainvision/tests/data/test_elp.txt
@@ -0,0 +1,45 @@
+% Ascii stylus data file created by FastSCAN V4.0.7 on Thu Oct 17 12:30:44 2013
+% raw surface, 86 visible points, bounding box reference
+% x y z
+ -5.6729 -12.3873 -30.3671
+ -37.6782 -10.4957 91.5228
+ -131.3127 9.3976 -22.2363
+ -30.4493 -11.8450 83.3601
+ -122.5353 9.2232 -28.6828
+ -6.8518 -47.0697 -37.0829
+ 7.3744 -50.6297 -12.1376
+ -33.4264 -43.7352 -57.7756
+ 3.8676 -77.0439 -13.0212
+ -31.9297 -70.6852 -57.4881
+ -6.1042 -68.2969 45.4939
+ -26.8874 -108.1869 -29.3948
+ -93.4960 -57.5314 -59.6307
+ -28.5191 -90.8090 65.3667
+ -20.3574 -115.7971 26.8439
+ -52.4084 -132.2694 -10.8940
+ -79.6612 -109.5778 -50.2500
+ -120.4482 -80.1049 -48.4998
+ -59.5687 -140.7296 28.7939
+ -79.2198 -141.0449 8.6352
+ -98.5593 -130.9501 -14.6008
+ -73.7114 -79.5972 108.4127
+ -64.2139 -118.9901 81.5907
+ -109.4613 -144.7746 38.7691
+ -144.6454 -113.6235 -15.1309
+ -172.6252 -72.4156 -5.0970
+ -111.8295 -132.7764 88.6002
+ -133.5129 -127.0993 66.4257
+ -155.4911 -128.0503 41.9582
+ -87.9713 -42.7048 122.4772
+ -125.8923 -88.7830 113.4730
+ -159.2922 -104.0640 84.9862
+ -188.8384 -81.4090 45.6836
+ -179.7623 -35.5428 13.4639
+ -134.3199 -7.4196 99.9593
+ -167.0685 -28.2038 84.3689
+ -172.0302 -4.7960 60.4032
+ -65.6105 -14.9387 115.0734
+ -163.2992 3.5260 -9.0238
+ 1.0591 6.2860 4.8814
+ -51.6423 10.2912 -47.8098
+ -61.2542 29.6360 -43.4039
diff --git a/mne/fiff/brainvision/tests/test_brainvision.py b/mne/fiff/brainvision/tests/test_brainvision.py
new file mode 100644
index 0000000..320ee3a
--- /dev/null
+++ b/mne/fiff/brainvision/tests/test_brainvision.py
@@ -0,0 +1,75 @@
+"""Data Equivalence Tests"""
+
+# Author: Teon Brooks <teon at nyu.edu>
+#
+# License: BSD (3-clause)
+
+import os.path as op
+import inspect
+
+from nose.tools import assert_equal
+from numpy.testing import assert_array_almost_equal, assert_array_equal
+
+from mne.utils import _TempDir
+from mne.fiff import Raw, pick_types
+from mne.fiff.brainvision import read_raw_brainvision
+
+FILE = inspect.getfile(inspect.currentframe())
+data_dir = op.join(op.dirname(op.abspath(FILE)), 'data')
+vhdr_path = op.join(data_dir, 'test.vhdr')
+elp_path = op.join(data_dir, 'test_elp.txt')
+eeg_bin = op.join(data_dir, 'test_bin_raw.fif')
+ch_names = ['FP1', 'VEOGt', 'F7', 'GND', 'F8',
+ 'FC5', 'F3', 'FZ', 'F4', 'FC6',
+ 'FC1', 'FCZ', 'FC2', 'CP5', 'C3',
+ 'CZ', 'C4', 'CP6', 'CP1', 'CPZ',
+ 'CP2', 'P7', 'P3', 'PZ', 'P4',
+ 'P8', 'O1', 'POZ', 'O2', 'A1',
+ 'A2', 'HEOGL', 'HEOGR', 'VEOGb']
+
+tempdir = _TempDir()
+
+
+def test_brainvision_data():
+ """Test reading raw Brain Vision files
+ """
+ raw_py = read_raw_brainvision(vhdr_path, elp_fname=elp_path,
+ ch_names=ch_names, preload=True)
+ picks = pick_types(raw_py.info, meg=False, eeg=True, exclude='bads')
+ data_py, times_py = raw_py[picks]
+
+ print raw_py # to test repr
+ print raw_py.info # to test Info repr
+
+ # this fif was generated using MNE-C
+ raw_bin = Raw(eeg_bin, preload=True)
+ picks = pick_types(raw_py.info, meg=False, eeg=True, exclude='bads')
+ data_bin, times_bin = raw_bin[picks]
+
+ assert_array_almost_equal(data_py, data_bin)
+ assert_array_almost_equal(times_py, times_bin)
+
+
+def test_read_segment():
+ """Test writing raw eeg files when preload is False
+ """
+ raw1 = read_raw_brainvision(vhdr_path, preload=False)
+ raw1_file = op.join(tempdir, 'raw1.fif')
+ raw1.save(raw1_file, overwrite=True)
+ raw11 = Raw(raw1_file, preload=True)
+ data1, times1 = raw1[:, :]
+ data11, times11 = raw11[:, :]
+ assert_array_almost_equal(data1, data11, 8)
+ assert_array_almost_equal(times1, times11)
+ assert_equal(sorted(raw1.info.keys()), sorted(raw11.info.keys()))
+
+ raw2 = read_raw_brainvision(vhdr_path, preload=True)
+ raw2_file = op.join(tempdir, 'raw2.fif')
+ raw2.save(raw2_file, overwrite=True)
+ data2, times2 = raw2[:, :]
+ assert_array_equal(data1, data2)
+ assert_array_equal(times1, times2)
+
+ raw1 = Raw(raw1_file, preload=True)
+ raw2 = Raw(raw2_file, preload=True)
+ assert_array_equal(raw1._data, raw2._data)
diff --git a/mne/fiff/bti/raw.py b/mne/fiff/bti/raw.py
index 2bf0eb1..c0f0431 100644
--- a/mne/fiff/bti/raw.py
+++ b/mne/fiff/bti/raw.py
@@ -7,28 +7,26 @@
#
# simplified BSD-3 license
-import logging
import os.path as op
from itertools import count
import numpy as np
-from ...utils import verbose
+from ...utils import logger, verbose, sum_squared
from .. import Raw
from .. import FIFF
from .constants import BTI
from .read import (read_int32, read_int16, read_str, read_float, read_double,
- read_transform, read_char, read_int64, read_uint16,
- read_uint32, read_double_matrix, read_float_matrix,
- read_int16_matrix)
+ read_transform, read_char, read_int64, read_uint16,
+ read_uint32, read_double_matrix, read_float_matrix,
+ read_int16_matrix)
from .transforms import (bti_identity_trans, bti_to_vv_trans,
- bti_to_vv_coil_trans, inverse_trans, merge_trans)
-
-logger = logging.getLogger('mne')
+ bti_to_vv_coil_trans, inverse_trans, merge_trans)
+from ..meas_info import Info
FIFF_INFO_CHS_FIELDS = ('loc', 'ch_name', 'unit_mul', 'coil_trans',
- 'coord_frame', 'coil_type', 'range', 'unit', 'cal', 'eeg_loc',
- 'scanno', 'kind', 'logno')
+ 'coord_frame', 'coil_type', 'range', 'unit', 'cal',
+ 'eeg_loc', 'scanno', 'kind', 'logno')
FIFF_INFO_CHS_DEFAULTS = (np.array([0, 0, 0, 1] * 3, dtype='f4'),
None, 0, None, 0, 0, 1.0,
@@ -108,7 +106,7 @@ def _convert_head_shape(idx_points, dig_points):
fp = idx_points.astype('>f8')
dp = np.sum(fp[2] * (fp[0] - fp[1]))
- tmp1, tmp2 = np.sum(fp[2] ** 2), np.sum((fp[0] - fp[1]) ** 2)
+ tmp1, tmp2 = sum_squared(fp[2]), sum_squared(fp[0] - fp[1])
dcos = -dp / np.sqrt(tmp1 * tmp2)
dsin = np.sqrt(1. - dcos * dcos)
dt = dp / np.sqrt(tmp2)
@@ -396,9 +394,9 @@ def _read_config(fname):
if dta['hdr']['version'] == 2:
size = 16
dta['ch_names'] = [read_str(fid, size) for ch in
- range(dta['hdr']['n_entries'])]
+ range(dta['hdr']['n_entries'])]
dta['e_ch_names'] = [read_str(fid, size) for ch in
- range(dta['hdr']['n_e_values'])]
+ range(dta['hdr']['n_e_values'])]
rows = dta['hdr']['n_entries']
cols = dta['hdr']['n_e_values']
@@ -446,9 +444,11 @@ def _read_config(fname):
dta['dsp_ch_names'] = BTI_WH2500_REF_GRAD
dta['hdr.n_dsp'] = len(dta['dsp_ch_names'])
dta['anlg_wts'] = np.zeros((dta['hdr']['n_entries'],
- dta['hdr']['n_anlg']), dtype='i2')
+ dta['hdr']['n_anlg']),
+ dtype='i2')
dta['dsp_wts'] = np.zeros((dta['hdr']['n_entries'],
- dta['hdr']['n_dsp']), dtype='f4')
+ dta['hdr']['n_dsp']),
+ dtype='f4')
for n in range(dta['hdr']['n_entries']):
dta['anlg_wts'][d] = read_int16_matrix(fid, 1,
dta['hdr']['n_anlg'])
@@ -730,7 +730,7 @@ def _read_ch_config(fid):
'reserved': read_str(fid, 32)}
if ch_type in [BTI.CHTYPE_MEG, BTI.CHTYPE_REF]:
chan['loops'] = [_read_coil_def(fid) for d in
- range(chan['dev']['total_loops'])]
+ range(chan['dev']['total_loops'])]
elif ch_type == BTI.CHTYPE_EEG:
chan['impedance'] = read_float(fid)
@@ -776,9 +776,9 @@ def _read_bti_header(pdf_fname, config_fname):
# actual header starts here
info = {'version': read_int16(fid),
- 'file_type': read_str(fid, 5),
- 'hdr_size': start - header_position, # add to info for convenience
- 'start': start}
+ 'file_type': read_str(fid, 5),
+ 'hdr_size': start - header_position, # add to info for convenience
+ 'start': start}
fid.seek(1, 1)
@@ -806,7 +806,7 @@ def _read_bti_header(pdf_fname, config_fname):
# actual header ends here, so dar seems ok.
info['epochs'] = [_read_epoch(fid) for epoch in
- range(info['total_epochs'])]
+ range(info['total_epochs'])]
info['chs'] = [_read_channel(fid) for ch in
range(info['total_chans'])]
@@ -994,7 +994,7 @@ class RawBTi(Raw):
use_hpi = False # hard coded, but marked as later option.
logger.info('Creating Neuromag info structure ...')
- info = dict()
+ info = Info()
info['bads'] = []
info['meas_id'] = None
info['file_id'] = None
@@ -1161,13 +1161,13 @@ class RawBTi(Raw):
self.first_samp, self.last_samp = 0, self._data.shape[1] - 1
assert len(self._data) == len(self.info['ch_names'])
- self._times = np.arange(self.first_samp, \
+ self._times = np.arange(self.first_samp,
self.last_samp + 1) / info['sfreq']
self._projectors = [None]
logger.info(' Range : %d ... %d = %9.3f ... %9.3f secs' % (
- self.first_samp, self.last_samp,
- float(self.first_samp) / info['sfreq'],
- float(self.last_samp) / info['sfreq']))
+ self.first_samp, self.last_samp,
+ float(self.first_samp) / info['sfreq'],
+ float(self.last_samp) / info['sfreq']))
logger.info('Ready.')
diff --git a/mne/fiff/bti/read.py b/mne/fiff/bti/read.py
index 3f7d71e..b14eb0c 100644
--- a/mne/fiff/bti/read.py
+++ b/mne/fiff/bti/read.py
@@ -2,11 +2,8 @@
# simplified BSD-3 license
import struct
-import logging
import numpy as np
-logger = logging.getLogger('mne')
-
def _unpack_matrix(fid, format, rows, cols, dtype):
""" Aux Function """
diff --git a/mne/fiff/bti/tests/test_bti.py b/mne/fiff/bti/tests/test_bti.py
index f4b62f7..2c725ec 100644
--- a/mne/fiff/bti/tests/test_bti.py
+++ b/mne/fiff/bti/tests/test_bti.py
@@ -10,8 +10,8 @@ from numpy.testing import assert_array_almost_equal, assert_array_equal
from nose.tools import assert_true, assert_raises, assert_equal
from mne.fiff import Raw as Raw
-from mne.fiff.bti.raw import _read_config, _setup_head_shape,\
- read_raw_bti, _read_data, _read_bti_header
+from mne.fiff.bti.raw import (_read_config, _setup_head_shape,
+ read_raw_bti, _read_data, _read_bti_header)
from mne.utils import _TempDir
base_dir = op.join(op.abspath(op.dirname(__file__)), 'data')
@@ -48,10 +48,10 @@ def test_read_pdf():
def test_raw():
- """ Test conversion to Raw object """
+ """ Test bti conversion to Raw object """
for pdf, config, hs, exported in zip(pdf_fnames, config_fnames, hs_fnames,
- exported_fnames):
+ exported_fnames):
# rx = 2 if 'linux' in pdf else 0
assert_raises(ValueError, read_raw_bti, pdf, 'eggs')
assert_raises(ValueError, read_raw_bti, pdf, config, 'spam')
@@ -67,11 +67,12 @@ def test_raw():
assert_array_equal(dig1, dig2)
coil1, coil2 = [np.concatenate([d['coil_trans'].flatten()
- for d in r_.info['chs'][:NCH]]) for r_ in ra, ex]
+ for d in r_.info['chs'][:NCH]])
+ for r_ in ra, ex]
assert_array_almost_equal(coil1, coil2, 7)
loc1, loc2 = [np.concatenate([d['loc'].flatten()
- for d in r_.info['chs'][:NCH]]) for r_ in ra, ex]
+ for d in r_.info['chs'][:NCH]]) for r_ in ra, ex]
assert_array_equal(loc1, loc2)
assert_array_equal(ra._data[:NCH], ex._data[:NCH])
diff --git a/mne/fiff/compensator.py b/mne/fiff/compensator.py
index 1d8c452..40f9c04 100644
--- a/mne/fiff/compensator.py
+++ b/mne/fiff/compensator.py
@@ -1,10 +1,6 @@
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-
from .constants import FIFF
-from .. import verbose
def get_current_comp(info):
@@ -20,7 +16,6 @@ def get_current_comp(info):
elif comp != first_comp:
raise ValueError('Compensation is not set equally on '
'all MEG channels')
-
return comp
@@ -35,10 +30,10 @@ def _make_compensator(info, kind):
presel = np.zeros((this_data['ncol'], info['nchan']))
for col, col_name in enumerate(this_data['col_names']):
ind = [k for k, ch in enumerate(info['ch_names'])
- if ch == col_name]
+ if ch == col_name]
if len(ind) == 0:
- raise ValueError('Channel %s is not available in data' % \
- col_name)
+ raise ValueError('Channel %s is not available in '
+ 'data' % col_name)
elif len(ind) > 1:
raise ValueError('Ambiguous channel %s' % col_name)
presel[col, ind] = 1.0
@@ -47,7 +42,7 @@ def _make_compensator(info, kind):
postsel = np.zeros((info['nchan'], this_data['nrow']))
for c, ch_name in enumerate(info['ch_names']):
ind = [k for k, ch in enumerate(this_data['row_names'])
- if ch == ch_name]
+ if ch == ch_name]
if len(ind) > 1:
raise ValueError('Ambiguous channel %s' % ch_name)
elif len(ind) == 1:
@@ -103,7 +98,7 @@ def make_compensator(info, from_, to, exclude_comp_chs=False):
if exclude_comp_chs:
pick = [k for k, c in enumerate(info['chs'])
- if c['kind'] != FIFF.FIFFV_REF_MEG_CH]
+ if c['kind'] != FIFF.FIFFV_REF_MEG_CH]
if len(pick) == 0:
raise ValueError('Nothing remains after excluding the '
diff --git a/mne/fiff/constants.py b/mne/fiff/constants.py
index c2657e7..b95135d 100644
--- a/mne/fiff/constants.py
+++ b/mne/fiff/constants.py
@@ -42,17 +42,17 @@ FIFF.FIFFB_HPI_SUBSYSTEM = 121
FIFF.FIFFB_EPOCHS = 122
FIFF.FIFFB_ICA = 123
-FIFF.FIFFB_SPHERE = 300 # Concentric sphere model related
-FIFF.FIFFB_BEM = 310 # Boundary-element method
-FIFF.FIFFB_BEM_SURF = 311 # Boundary-element method surfaces
-FIFF.FIFFB_CONDUCTOR_MODEL = 312 # One conductor model definition
+FIFF.FIFFB_SPHERE = 300 # Concentric sphere model related
+FIFF.FIFFB_BEM = 310 # Boundary-element method
+FIFF.FIFFB_BEM_SURF = 311 # Boundary-element method surfaces
+FIFF.FIFFB_CONDUCTOR_MODEL = 312 # One conductor model definition
FIFF.FIFFB_PROJ = 313
FIFF.FIFFB_PROJ_ITEM = 314
FIFF.FIFFB_MRI = 200
FIFF.FIFFB_MRI_SET = 201
FIFF.FIFFB_MRI_SLICE = 202
FIFF.FIFFB_MRI_SCENERY = 203 # These are for writing unrelated 'slices'
-FIFF.FIFFB_MRI_SCENE = 204 # Which are actually 3D scenes...
+FIFF.FIFFB_MRI_SCENE = 204 # Which are actually 3D scenes...
FIFF.FIFFB_MRI_SEG = 205 # MRI segmentation data
FIFF.FIFFB_MRI_SEG_REGION = 206 # One MRI segmentation region
FIFF.FIFFB_PROCESSING_HISTORY = 900
@@ -107,15 +107,15 @@ FIFF.FIFF_BAD_CHS = 220
FIFF.FIFF_ARTEF_REMOVAL = 221
FIFF.FIFF_COORD_TRANS = 222
FIFF.FIFF_HIGHPASS = 223
-FIFF.FIFF_CH_CALS = 224 # This will not occur in new files
-FIFF.FIFF_HPI_BAD_CHS = 225 # List of channels considered to be bad in hpi
-FIFF.FIFF_HPI_CORR_COEFF = 226 # Hpi curve fit correlations
-FIFF.FIFF_EVENT_COMMENT = 227 # Comment about the events used in averaging
-FIFF.FIFF_NO_SAMPLES = 228 # Number of samples in an epoch
-FIFF.FIFF_FIRST_TIME = 229 # Time scale minimum
-
-FIFF.FIFF_SUBAVE_SIZE = 230 # Size of a subaverage
-FIFF.FIFF_SUBAVE_FIRST = 231 # The first epoch # contained in the subaverage
+FIFF.FIFF_CH_CALS = 22 # This will not occur in new files
+FIFF.FIFF_HPI_BAD_CHS = 225 # List of channels considered to be bad in hpi
+FIFF.FIFF_HPI_CORR_COEFF = 226 # Hpi curve fit correlations
+FIFF.FIFF_EVENT_COMMENT = 227 # Comment about the events used in averaging
+FIFF.FIFF_NO_SAMPLES = 228 # Number of samples in an epoch
+FIFF.FIFF_FIRST_TIME = 229 # Time scale minimum
+
+FIFF.FIFF_SUBAVE_SIZE = 230 # Size of a subaverage
+FIFF.FIFF_SUBAVE_FIRST = 231 # The first epoch # contained in the subaverage
FIFF.FIFF_NAME = 233 # Intended to be a short name.
FIFF.FIFF_DESCRIPTION = FIFF.FIFF_COMMENT # (Textual) Description of an object
FIFF.FIFF_DIG_STRING = 234 # String of digitized points
@@ -147,7 +147,11 @@ FIFF.FIFFV_EOG_CH = 202
FIFF.FIFFV_EMG_CH = 302
FIFF.FIFFV_ECG_CH = 402
FIFF.FIFFV_MISC_CH = 502
-FIFF.FIFFV_RESP_CH = 602 # Respiration monitoring
+FIFF.FIFFV_RESP_CH = 602 # Respiration monitoring
+FIFF.FIFFV_SYST_CH = 900 # some system status information (on Triux systems only)
+FIFF.FIFFV_IAS_CH = 910 # Internal Active Shielding data (maybe on Triux only)
+FIFF.FIFFV_EXCI_CH = 920 # flux excitation channel used to be a stimulus channel
+
#
# Quaternion channels for head position monitoring
#
@@ -244,6 +248,24 @@ FIFF.FIFFV_BEM_SURF_ID_UNKNOWN = -1
FIFF.FIFFV_BEM_SURF_ID_BRAIN = 1
FIFF.FIFFV_BEM_SURF_ID_SKULL = 3
FIFF.FIFFV_BEM_SURF_ID_HEAD = 4
+
+FIFF.FIFFB_BEM = 310 # BEM data
+FIFF.FIFFB_BEM_SURF = 311 # One of the surfaces
+FIFF.FIFF_BEM_SURF_ID = 3101 # int surface number
+FIFF.FIFF_BEM_SURF_NAME = 3102 # string surface name
+FIFF.FIFF_BEM_SURF_NNODE = 3103 # int number of nodes on a surface
+FIFF.FIFF_BEM_SURF_NTRI = 3104 # int number of triangles on a surface
+FIFF.FIFF_BEM_SURF_NODES = 3105 # float surface nodes (nnode,3)
+FIFF.FIFF_BEM_SURF_TRIANGLES = 3106 # int surface triangles (ntri,3)
+FIFF.FIFF_BEM_SURF_NORMALS = 3107 # float surface node normal unit vectors
+
+FIFF.FIFF_BEM_POT_SOLUTION = 3110 # float ** The solution matrix
+FIFF.FIFF_BEM_APPROX = 3111 # int approximation method, see below
+FIFF.FIFF_BEM_COORD_FRAME = 3112 # The coordinate frame of the model
+FIFF.FIFF_BEM_SIGMA = 3113 # Conductivity of a compartment
+FIFF.FIFFV_BEM_APPROX_CONST = 1 # The constant potential approach
+FIFF.FIFFV_BEM_APPROX_LINEAR = 2 # The linear potential approach
+
#
# More of those defined in MNE
#
@@ -423,7 +445,7 @@ FIFF.FIFF_MNE_INVERSE_SOURCE_UNIT = 3547 # Are the sources given in Am
FIFF.FIFF_MNE_ENV_WORKING_DIR = 3550 # Working directory where the file was created
FIFF.FIFF_MNE_ENV_COMMAND_LINE = 3551 # The command used to create the file
FIFF.FIFF_MNE_EXTERNAL_BIG_ENDIAN = 3552 # Reference to an external binary file (big-endian) */
-FIFF.FIFF_MNE_EXTERNAL_LITTLE_ENDIAN = 3553 # Reference to an external binary file (little-endian) */
+FIFF.FIFF_MNE_EXTERNAL_LITTLE_ENDIAN = 3553 # Reference to an external binary file (little-endian) */
#
# 3560... Miscellaneous
#
@@ -433,7 +455,7 @@ FIFF.FIFF_MNE_HEMI = 3562 # Hemisphere association for gen
FIFF.FIFF_MNE_DATA_SKIP_NOP = 3563 # A data skip turned off in the raw data
FIFF.FIFF_MNE_ORIG_CH_INFO = 3564 # Channel information before any changes
FIFF.FIFF_MNE_EVENT_TRIGGER_MASK = 3565 # Mask applied to the trigger channnel values
-FIFF.FIFF_MNE_EVENT_COMMENTS = 3566 # Event comments merged into one long string
+FIFF.FIFF_MNE_EVENT_COMMENTS = 3566 # Event comments merged into one long string
#
# 3570... Morphing maps
#
@@ -459,6 +481,7 @@ FIFF.FIFF_MNE_ICA_PCA_EXPLAINED_VAR = 3605 # PCA explained variance
FIFF.FIFF_MNE_ICA_PCA_MEAN = 3606 # PCA mean
FIFF.FIFF_MNE_ICA_MATRIX = 3607 # ICA unmixing matrix
FIFF.FIFF_MNE_ICA_BADS = 3608 # ICA bad sources
+FIFF.FIFF_MNE_ICA_MISC_PARAMS = 3609 # ICA misc params
#
# Fiff values associated with MNE computations
#
@@ -523,7 +546,6 @@ FIFF.FIFFV_PROJ_ITEM_DIP_FIX = 2
FIFF.FIFFV_PROJ_ITEM_DIP_ROT = 3
FIFF.FIFFV_PROJ_ITEM_HOMOG_GRAD = 4
FIFF.FIFFV_PROJ_ITEM_HOMOG_FIELD = 5
-FIFF.FIFFV_MNE_PROJ_ITEM_EEG_AVREF = 10
#
# Additional coordinate frames
#
@@ -565,9 +587,35 @@ FIFF.FIFFV_COIL_MAGNES_OFFDIAG_REF_GRAD = 4005
# BabySQUID sensors
#
FIFF.FIFFV_COIL_BABY_GRAD = 7001
+FIFF.FIFFV_COIL_BABY_MAG = 7002
+FIFF.FIFFV_COIL_BABY_REF_MAG = 7003
FIFF.FIFFV_REF_MEG_CH = 301
FIFF.FIFF_UNIT_AM_M2 = 203 # Am/m^2
FIFF.FIFF_UNIT_AM_M3 = 204 # Am/m^3
+#
+# FWD Types
+#
+FIFF.FWD_COIL_UNKNOWN = 0
+FIFF.FWD_COILC_UNKNOWN = 0
+FIFF.FWD_COILC_EEG = 1000
+FIFF.FWD_COILC_MAG = 1
+FIFF.FWD_COILC_AXIAL_GRAD = 2
+FIFF.FWD_COILC_PLANAR_GRAD = 3
+FIFF.FWD_COILC_AXIAL_GRAD2 = 4
+
+FIFF.FWD_COIL_ACCURACY_POINT = 0
+FIFF.FWD_COIL_ACCURACY_NORMAL = 1
+FIFF.FWD_COIL_ACCURACY_ACCURATE = 2
+
+FIFF.FWD_BEM_UNKNOWN = -1
+FIFF.FWD_BEM_CONSTANT_COLL = 1
+FIFF.FWD_BEM_LINEAR_COLL = 2
+
+FIFF.FWD_BEM_IP_APPROACH_LIMIT = 0.1
+
+FIFF.FWD_BEM_LIN_FIELD_SIMPLE = 1
+FIFF.FWD_BEM_LIN_FIELD_FERGUSON = 2
+FIFF.FWD_BEM_LIN_FIELD_URANKAR = 3
#
# Data types
@@ -711,3 +759,7 @@ FIFF.FIFFV_COIL_MAGNES_R_GRAD_DIA = 4004 # Magnes WH reference diagonal gradio
FIFF.FIFFV_COIL_MAGNES_R_GRAD_OFF = 4005 # Magnes WH reference off-diagonal gradiometer
FIFF.FIFFV_COIL_CTF_GRAD = 5001 # CTF axial gradiometer
FIFF.FIFFV_COIL_KIT_GRAD = 6001 # KIT system axial gradiometer
+
+# MNE RealTime
+FIFF.FIFF_MNE_RT_COMMAND = 3700
+FIFF.FIFF_MNE_RT_CLIENT_ID = 3701
diff --git a/mne/fiff/cov.py b/mne/fiff/cov.py
index 0ef3515..e99aaae 100644
--- a/mne/fiff/cov.py
+++ b/mne/fiff/cov.py
@@ -5,17 +5,14 @@
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-
from .constants import FIFF
-from .write import start_block, end_block, write_int, write_name_list, \
- write_double, write_float_matrix
+from .write import (start_block, end_block, write_int, write_name_list,
+ write_double, write_float_matrix)
from .tag import find_tag
from .tree import dir_tree_find
from .proj import read_proj, write_proj
from .channels import read_bad_channels
-from .. import verbose
+from ..utils import logger, verbose
@verbose
@@ -172,10 +169,11 @@ def write_cov(fid, cov):
write_double(fid, FIFF.FIFF_MNE_COV_EIGENVALUES, cov['eig'])
# Projection operator
- write_proj(fid, cov['projs'])
+ if cov['projs'] is not None and len(cov['projs']) > 0:
+ write_proj(fid, cov['projs'])
# Bad channels
- if cov['bads'] is not None:
+ if cov['bads'] is not None and len(cov['bads']) > 0:
start_block(fid, FIFF.FIFFB_MNE_BAD_CHANNELS)
write_name_list(fid, FIFF.FIFF_MNE_CH_NAME_LIST, cov['bads'])
end_block(fid, FIFF.FIFFB_MNE_BAD_CHANNELS)
diff --git a/mne/fiff/ctf.py b/mne/fiff/ctf.py
index ced9611..d24d297 100644
--- a/mne/fiff/ctf.py
+++ b/mne/fiff/ctf.py
@@ -6,13 +6,10 @@
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-
from .constants import FIFF
from .tag import find_tag, has_tag, read_tag
from .tree import dir_tree_find
-from .. import verbose
+from ..utils import logger, verbose
def hex2dec(s):
diff --git a/mne/fiff/diff.py b/mne/fiff/diff.py
index 08662bd..810381a 100644
--- a/mne/fiff/diff.py
+++ b/mne/fiff/diff.py
@@ -4,10 +4,7 @@
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-
-from .. import verbose
+from ..utils import logger, verbose
@verbose
diff --git a/mne/fiff/edf/__init__.py b/mne/fiff/edf/__init__.py
new file mode 100644
index 0000000..c332e4f
--- /dev/null
+++ b/mne/fiff/edf/__init__.py
@@ -0,0 +1,7 @@
+"""EDF+,BDF module for conversion to FIF"""
+
+# Author: Teon Brooks <teon at nyu.edu>
+#
+# License: BSD (3-clause)
+
+from .edf import read_raw_edf
diff --git a/mne/fiff/edf/edf.py b/mne/fiff/edf/edf.py
new file mode 100644
index 0000000..356e26e
--- /dev/null
+++ b/mne/fiff/edf/edf.py
@@ -0,0 +1,594 @@
+"""Conversion tool from EDF+,BDF to FIF
+
+"""
+
+# Author: Teon Brooks <teon at nyu.edu>
+#
+# License: BSD (3-clause)
+
+import os
+import calendar
+import datetime
+import re
+import warnings
+
+import numpy as np
+
+from ...transforms import als_ras_trans_mm, apply_trans
+from ...utils import verbose, logger
+from ..raw import Raw
+from ..meas_info import Info
+from ..constants import FIFF
+from ...coreg import get_ras_to_neuromag_trans
+from ...filter import resample
+
+
+class RawEDF(Raw):
+ """Raw object from EDF+,BDF file
+
+ Parameters
+ ----------
+ input_fname : str
+ Path to the EDF+,BDF file.
+
+ n_eeg : int | None
+ Number of EEG electrodes.
+ If None, all channels are considered EEG.
+
+ stim_channel : str | int | None
+ The channel name or channel index (starting at 0).
+ -1 corresponds to the last channel (default).
+ If None, there will be no stim channel added.
+
+ annot : str | None
+ Path to annotation file.
+ If None, no derived stim channel will be added (for files requiring
+ annotation file to interpret stim channel).
+
+ annotmap : str | None
+ Path to annotation map file containing mapping from label to trigger.
+ Must be specified if annot is not None.
+
+ hpts : str | None
+ Path to the hpts file containing electrode positions.
+ If None, sensor locations are (0,0,0).
+
+ preload : bool
+ If True, all data are loaded at initialization.
+ If False, data are not read until save.
+
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ There is an assumption that the data are arranged such that EEG channels
+ appear first then miscellaneous channels (EOGs, AUX, STIM).
+ The stimulus channel is saved as 'STI 014'
+
+ See Also
+ --------
+ mne.fiff.Raw : Documentation of attribute and methods.
+ """
+ @verbose
+ def __init__(self, input_fname, n_eeg=None, stim_channel=-1, annot=None,
+ annotmap=None, hpts=None, preload=False, verbose=None):
+ logger.info('Extracting edf Parameters from %s...' % input_fname)
+ input_fname = os.path.abspath(input_fname)
+ self.info, self._edf_info = _get_edf_info(input_fname, n_eeg,
+ stim_channel, annot,
+ annotmap, hpts, preload)
+ logger.info('Creating Raw.info structure...')
+
+ if bool(annot) != bool(annotmap):
+ warnings.warn(("Stimulus Channel will not be annotated. "
+ "Both 'annot' and 'annotmap' must be specified."))
+
+ # Raw attributes
+ self.verbose = verbose
+ self._preloaded = False
+ self.fids = list()
+ self._projector = None
+ self.first_samp = 0
+ self.last_samp = self._edf_info['nsamples'] - 1
+ self.comp = None # no compensation for EDF
+ self.proj = False
+
+ if preload:
+ self._preloaded = preload
+ logger.info('Reading raw data from %s...' % input_fname)
+ self._data, _ = self._read_segment()
+ assert len(self._data) == self.info['nchan']
+
+ # Add time info
+ self.first_samp, self.last_samp = 0, self._data.shape[1] - 1
+ self._times = np.arange(self.first_samp, self.last_samp + 1,
+ dtype=np.float64)
+ self._times /= self.info['sfreq']
+ logger.info(' Range : %d ... %d = %9.3f ... %9.3f secs'
+ % (self.first_samp, self.last_samp,
+ float(self.first_samp) / self.info['sfreq'],
+ float(self.last_samp) / self.info['sfreq']))
+ logger.info('Ready.')
+
+ def __repr__(self):
+ n_chan = self.info['nchan']
+ data_range = self.last_samp - self.first_samp + 1
+ s = ('%r' % os.path.basename(self.info['file_id']),
+ "n_channels x n_times : %s x %s" % (n_chan, data_range))
+ return "<RawEDF | %s>" % ', '.join(s)
+
+ def _read_segment(self, start=0, stop=None, sel=None, verbose=None,
+ projector=None):
+ """Read a chunk of raw data
+
+ Parameters
+ ----------
+ start : int, (optional)
+ first sample to include (first is 0). If omitted, defaults to the
+ first sample in data.
+
+ stop : int, (optional)
+ First sample to not include.
+ If omitted, data is included to the end.
+
+ sel : array, optional
+ Indices of channels to select.
+
+ projector : array
+ SSP operator to apply to the data.
+
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ data : array, [channels x samples]
+ the data matrix (channels x samples).
+
+ times : array, [samples]
+ returns the time values corresponding to the samples.
+ """
+ if sel is None:
+ sel = range(self.info['nchan'])
+ elif len(sel) == 1 and sel[0] == 0 and start == 0 and stop == 1:
+ return (666, 666)
+ if projector is not None:
+ raise NotImplementedError('Currently does not handle projections.')
+ if stop is None:
+ stop = self.last_samp + 1
+ elif stop > self.last_samp + 1:
+ stop = self.last_samp + 1
+
+ # Initial checks
+ start = int(start)
+ stop = int(stop)
+
+ sfreq = self.info['sfreq']
+ n_chan = self.info['nchan']
+ data_size = self._edf_info['data_size']
+ data_offset = self._edf_info['data_offset']
+ stim_channel = self._edf_info['stim_channel']
+ annot = self._edf_info['annot']
+ annotmap = self._edf_info['annotmap']
+
+ if start >= stop:
+ raise ValueError('No data in this range')
+
+ logger.info('Reading %d ... %d = %9.3f ... %9.3f secs...' %
+ (start, stop - 1, start / float(sfreq),
+ (stop - 1) / float(sfreq)))
+
+ gains = []
+ for chan in range(n_chan):
+ # gain constructor
+ physical_range = self.info['chs'][chan]['range']
+ cal = float(self.info['chs'][chan]['cal'])
+ unit_mul = 10 ** self.info['chs'][chan]['unit_mul']
+ gains.append(unit_mul * (physical_range / cal))
+
+ with open(self.info['file_id'], 'rb') as fid:
+ # extract data
+ fid.seek(data_offset)
+ buffer_size = stop - start
+ pointer = start * n_chan
+ fid.seek(data_offset + pointer)
+
+ if 'n_samps' in self._edf_info:
+ n_samps = self._edf_info['n_samps']
+ max_samp = float(np.max(n_samps))
+ blocks = int(buffer_size / max_samp)
+ else:
+ blocks = int(buffer_size / sfreq)
+ datas = []
+ # bdf data: 24bit data
+ if self._edf_info['subtype'] == '24BIT':
+ data = fid.read(buffer_size * n_chan * data_size)
+ data = np.fromstring(data, np.uint8)
+ data = data.reshape(-1, 3).astype(np.int32)
+ # this converts to 24-bit little endian integer
+ # # no support in numpy
+ data = (data[:, 0] + (data[:, 1] << 8) + (data[:, 2] << 16))
+ # 24th bit determines the sign
+ data[data >= (1 << 23)] -= (1 << 24)
+ data = data.reshape((sfreq, n_chan, blocks), order='F')
+ for i in range(blocks):
+ datas.append(data[:, :, i].T)
+ else:
+ if 'n_samps' in self._edf_info:
+ data = []
+ for _ in range(blocks):
+ for samp in n_samps:
+ chan_data = np.fromfile(fid, dtype='<i2',
+ count=samp)
+ data.append(chan_data)
+ for i, samp in enumerate(n_samps):
+ chan_data = data[i::n_chan]
+ chan_data = np.hstack(chan_data)
+ if samp != max_samp:
+ mult = max_samp / samp
+ chan_data = resample(x=chan_data, up=mult,
+ down=1, npad=0)
+ datas.append(chan_data)
+ else:
+ data = np.fromfile(fid, dtype='<i2',
+ count=buffer_size * n_chan)
+ data = data.reshape((sfreq, n_chan, blocks), order='F')
+ for i in range(blocks):
+ datas.append(data[:, :, i].T)
+ if 'n_samps' in self._edf_info:
+ data = np.vstack(datas)
+ else:
+ data = np.hstack(datas)
+ gains = np.array([gains])
+ data = gains.T * data
+ if stim_channel is not None:
+ if annot and annotmap:
+ data[stim_channel] = 0
+ evts = _read_annot(annot, annotmap, sfreq, self.last_samp)
+ data[stim_channel, :evts.size] = evts[start:stop]
+ else:
+ stim = np.array(data[stim_channel], int)
+ mask = 255 * np.ones(stim.shape, int)
+ stim = np.bitwise_and(stim, mask)
+ data[stim_channel] = stim
+ data = data[sel]
+
+ logger.info('[done]')
+ times = np.arange(start, stop, dtype=float) / self.info['sfreq']
+
+ return data, times
+
+
+def _get_edf_info(fname, n_eeg, stim_channel, annot, annotmap, hpts, preload):
+ """Extracts all the information from the EDF+,BDF file.
+
+ Parameters
+ ----------
+ fname : str
+ Raw EDF+,BDF file to be read.
+
+ n_eeg : int | None
+ Number of EEG electrodes.
+ If None, all channels are considered EEG.
+
+ stim_channel : str | int | None
+ The channel name or channel index (starting at 0).
+ -1 corresponds to the last channel.
+ If None, there will be no stim channel added.
+
+ annot : str | None
+ Path to annotation file.
+ If None, no derived stim channel will be added (for files requiring
+ annotation file to interpret stim channel).
+
+ annotmap : str | None
+ Path to annotation map file containing mapping from label to trigger.
+ Must be specified if annot is not None.
+
+ hpts : str | None
+ Path to the hpts file containing electrode positions.
+ If None, sensor locations are (0,0,0).
+
+ preload : bool
+ If True, all data are loaded at initialization.
+ If False, data are not read until save.
+
+ Returns
+ -------
+ info : instance of Info
+ The measurement info.
+ edf_info : dict
+ A dict containing all the EDF+,BDF specific parameters.
+ """
+
+ info = Info()
+ info['file_id'] = fname
+ # Add info for fif object
+ info['meas_id'] = None
+ info['projs'] = []
+ info['comps'] = []
+ info['bads'] = []
+ info['acq_pars'], info['acq_stim'] = None, None
+ info['filename'] = fname
+ info['ctf_head_t'] = None
+ info['dev_ctf_t'] = []
+ info['filenames'] = []
+ info['dig'] = None
+ info['dev_head_t'] = None
+ info['proj_id'] = None
+ info['proj_name'] = None
+ info['experimenter'] = None
+
+ edf_info = dict()
+ edf_info['annot'] = annot
+ edf_info['annotmap'] = annotmap
+
+ with open(fname, 'rb') as fid:
+ assert(fid.tell() == 0)
+ fid.seek(8)
+
+ _ = fid.read(80).strip() # subject id
+ _ = fid.read(80).strip() # recording id
+ day, month, year = [int(x) for x in re.findall('(\d+)', fid.read(8))]
+ hour, minute, sec = [int(x) for x in re.findall('(\d+)', fid.read(8))]
+ date = datetime.datetime(year + 2000, month, day, hour, minute, sec)
+ info['meas_date'] = calendar.timegm(date.utctimetuple())
+
+ edf_info['data_offset'] = header_nbytes = int(fid.read(8))
+ subtype = fid.read(44).strip()[:5]
+ edf_info['subtype'] = subtype
+
+ edf_info['n_records'] = n_records = int(fid.read(8))
+ # record length in seconds
+ edf_info['record_length'] = record_length = float(fid.read(8))
+ info['nchan'] = int(fid.read(4))
+ if n_eeg is None:
+ n_eeg = info['nchan']
+ channels = range(info['nchan'])
+ ch_names = [fid.read(16).strip() for _ in channels]
+ _ = [fid.read(80).strip() for _ in channels] # transducer type
+ units = [fid.read(8).strip() for _ in channels]
+ for i, unit in enumerate(units):
+ if unit == 'uV':
+ units[i] = -6
+ elif unit == 'V':
+ units[i] = 0
+ else:
+ units[i] = 1
+ physical_min = np.array([float(fid.read(8)) for _ in channels])
+ physical_max = np.array([float(fid.read(8)) for _ in channels])
+ digital_min = np.array([float(fid.read(8)) for _ in channels])
+ digital_max = np.array([float(fid.read(8)) for _ in channels])
+ prefiltering = [fid.read(80).strip() for _ in channels][:-1]
+ highpass = np.ravel([re.findall('HP:\s+(\w+)', filt)
+ for filt in prefiltering])
+ lowpass = np.ravel([re.findall('LP:\s+(\w+)', filt)
+ for filt in prefiltering])
+ if highpass.size == 0:
+ info['highpass'] = None
+ elif all(highpass):
+ if highpass[0] == 'NaN':
+ info['highpass'] = None
+ elif highpass[0] == 'DC':
+ info['highpass'] = 0
+ else:
+ info['highpass'] = int(highpass[0])
+ else:
+ info['highpass'] = np.min(highpass)
+ warnings.warn('%s' % ('Channels contain different highpass'
+ + 'filters. Highest filter setting will'
+ + 'be stored.'))
+ if lowpass.size == 0:
+ info['lowpass'] = None
+ elif all(lowpass):
+ if lowpass[0] == 'NaN':
+ info['lowpass'] = None
+ else:
+ info['lowpass'] = int(lowpass[0])
+ else:
+ info['lowpass'] = np.min(lowpass)
+ warnings.warn('%s' % ('Channels contain different lowpass filters.'
+ ' Lowest filter setting will be stored.'))
+ n_samples_per_record = [int(fid.read(8)) for _ in channels]
+ if np.unique(n_samples_per_record).size != 1:
+ edf_info['n_samps'] = np.array(n_samples_per_record)
+ if not preload:
+ raise RuntimeError('%s' % ('Channels contain different'
+ 'sampling rates. '
+ 'Must set preload=True'))
+ n_samples_per_record = n_samples_per_record[0]
+ fid.read(32 * info['nchan']) # reserved
+ assert fid.tell() == header_nbytes
+ physical_ranges = physical_max - physical_min
+ cals = digital_max - digital_min
+ info['sfreq'] = int(n_samples_per_record / record_length)
+ edf_info['nsamples'] = n_records * n_samples_per_record
+
+ # Some keys to be consistent with FIF measurement info
+ info['description'] = None
+ info['buffer_size_sec'] = 10.
+ info['orig_blocks'] = None
+ info['orig_fid_str'] = None
+
+ if edf_info['subtype'] == '24BIT':
+ edf_info['data_size'] = 3 # 24-bit (3 byte) integers
+ else:
+ edf_info['data_size'] = 2 # 16-bit (2 byte) integers
+
+ if hpts and os.path.lexists(hpts):
+ fid = open(hpts, 'rb').read()
+ locs = {}
+ temp = re.findall('eeg\s(\w+)\s(-?\d+)\s(-?\d+)\s(-?\d+)', fid)
+ temp = temp + re.findall('cardinal\s(\d+)\s(-?\d+)\s(-?\d+)\s(-?\d+)',
+ fid)
+ for loc in temp:
+ coord = np.array(map(int, loc[1:]))
+ coord = apply_trans(als_ras_trans_mm, coord)
+ locs[loc[0].lower()] = coord
+ trans = get_ras_to_neuromag_trans(nasion=locs['2'], lpa=locs['1'],
+ rpa=locs['3'])
+ for loc in locs:
+ locs[loc] = apply_trans(trans, locs[loc])
+ info['dig'] = []
+
+ point_dict = {}
+ point_dict['coord_frame'] = FIFF.FIFFV_COORD_HEAD
+ point_dict['ident'] = FIFF.FIFFV_POINT_NASION
+ point_dict['kind'] = FIFF.FIFFV_POINT_CARDINAL
+ point_dict['r'] = apply_trans(trans, locs['2'])
+ info['dig'].append(point_dict)
+
+ point_dict = {}
+ point_dict['coord_frame'] = FIFF.FIFFV_COORD_HEAD
+ point_dict['ident'] = FIFF.FIFFV_POINT_LPA
+ point_dict['kind'] = FIFF.FIFFV_POINT_CARDINAL
+ point_dict['r'] = apply_trans(trans, locs['1'])
+ info['dig'].append(point_dict)
+
+ point_dict = {}
+ point_dict['coord_frame'] = FIFF.FIFFV_COORD_HEAD
+ point_dict['ident'] = FIFF.FIFFV_POINT_RPA
+ point_dict['kind'] = FIFF.FIFFV_POINT_CARDINAL
+ point_dict['r'] = apply_trans(trans, locs['3'])
+ info['dig'].append(point_dict)
+
+ else:
+ locs = {}
+ locs = [locs[ch_name.lower()] if ch_name.lower() in locs.keys()
+ else (0, 0, 0) for ch_name in ch_names]
+ sensor_locs = np.array(locs)
+
+ # Creates a list of dicts of eeg channels for raw.info
+ logger.info('Setting channel info structure...')
+ info['chs'] = []
+ info['ch_names'] = ch_names
+ if stim_channel == -1:
+ stim_channel = info['nchan']
+ for idx, ch_info in enumerate(zip(ch_names, sensor_locs, physical_ranges,
+ cals, units), 1):
+ ch_name, ch_loc, physical_range, cal, unit_mul = ch_info
+ chan_info = {}
+ chan_info['cal'] = cal
+ chan_info['logno'] = idx
+ chan_info['scanno'] = idx
+ chan_info['range'] = physical_range
+ chan_info['unit_mul'] = unit_mul
+ chan_info['ch_name'] = ch_name
+ chan_info['unit'] = FIFF.FIFF_UNIT_V
+ chan_info['coord_frame'] = FIFF.FIFFV_COORD_HEAD
+ chan_info['coil_type'] = FIFF.FIFFV_COIL_EEG
+ chan_info['kind'] = FIFF.FIFFV_EEG_CH
+ chan_info['eeg_loc'] = ch_loc
+ chan_info['loc'] = np.zeros(12)
+ chan_info['loc'][:3] = ch_loc
+ if idx > n_eeg:
+ chan_info['coil_type'] = FIFF.FIFFV_COIL_NONE
+ chan_info['kind'] = FIFF.FIFFV_MISC_CH
+ check1 = stim_channel == ch_name
+ check2 = stim_channel == idx
+ check3 = info['nchan'] > 1
+ stim_check = np.logical_and(np.logical_or(check1, check2), check3)
+ if stim_check:
+ chan_info['range'] = 1
+ chan_info['cal'] = 1
+ chan_info['unit_mul'] = 0
+ chan_info['coil_type'] = FIFF.FIFFV_COIL_NONE
+ chan_info['unit'] = FIFF.FIFF_UNIT_NONE
+ chan_info['kind'] = FIFF.FIFFV_STIM_CH
+ chan_info['ch_name'] = 'STI 014'
+ info['ch_names'][idx - 1] = chan_info['ch_name']
+ if isinstance(stim_channel, str):
+ stim_channel = idx
+ info['chs'].append(chan_info)
+ if stim_channel is None:
+ edf_info['stim_channel'] = stim_channel
+ else:
+ edf_info['stim_channel'] = stim_channel - 1
+
+ return info, edf_info
+
+
+def _read_annot(annot, annotmap, sfreq, data_length):
+ """Annotation File Reader
+
+ Parameters
+ ----------
+ annot : str
+ Path to annotation file.
+
+ annotmap : str
+ Path to annotation map file containing mapping from label to trigger.
+
+ sfreq : int
+ Sampling frequency.
+
+ data_length : int
+ Length of the data file.
+
+ Returns
+ -------
+ stim_channel : ndarray
+ An array containing stimulus trigger events.
+ """
+ pat = '([+/-]\d+.\d+),(\w+)'
+ annot = open(annot).read()
+ triggers = re.findall(pat, annot)
+ times, values = zip(*triggers)
+ times = map(float, times)
+ times = [time * sfreq for time in times]
+
+ pat = '(\w+):(\d+)'
+ annotmap = open(annotmap).read()
+ mappings = re.findall(pat, annotmap)
+ maps = {}
+ for mapping in mappings:
+ maps[mapping[0]] = mapping[1]
+ triggers = [int(maps[value]) for value in values]
+
+ stim_channel = np.zeros(data_length)
+ for time, trigger in zip(times, triggers):
+ stim_channel[time] = trigger
+
+ return stim_channel
+
+
+def read_raw_edf(input_fname, n_eeg=None, stim_channel=-1, annot=None,
+ annotmap=None, hpts=None, preload=False, verbose=None):
+ """Reader function for EDF+, BDF conversion to FIF
+
+ Parameters
+ ----------
+ input_fname : str
+ Path to the EDF+,BDF file.
+
+ n_eeg : int | None
+ Number of EEG electrodes.
+ If None, all channels are considered EEG.
+
+ stim_channel : str | int | None
+ The channel name or channel index (starting at 0).
+ -1 corresponds to the last channel.
+ If None, there will be no stim channel added.
+
+ annot : str | None
+ Path to annotation file.
+ If None, no derived stim channel will be added (for files requiring
+ annotation file to interpret stim channel).
+
+ annotmap : str | None
+ Path to annotation map file containing mapping from label to trigger.
+ Must be specified if annot is not None.
+
+ hpts : str | None
+ Path to the hpts file containing electrode positions.
+ If None, sensor locations are (0,0,0).
+
+ preload : bool
+ If True, all data are loaded at initialization.
+ If False, data are not read until save.
+
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+ return RawEDF(input_fname=input_fname, n_eeg=n_eeg,
+ stim_channel=stim_channel, annot=annot, annotmap=annotmap,
+ hpts=hpts, preload=preload, verbose=verbose)
diff --git a/mne/tests/__init__.py b/mne/fiff/edf/tests/__init__.py
similarity index 100%
copy from mne/tests/__init__.py
copy to mne/fiff/edf/tests/__init__.py
diff --git a/mne/fiff/edf/tests/data/biosemi.hpts b/mne/fiff/edf/tests/data/biosemi.hpts
new file mode 100644
index 0000000..cf3d2b5
--- /dev/null
+++ b/mne/fiff/edf/tests/data/biosemi.hpts
@@ -0,0 +1,82 @@
+# This file contains the default locations for the 64
+# channel biosemi cap, available on the biosemi website
+# http://www.biosemi.com/download/Cap_coords_all.xls
+#
+# This includes default locations for 3 cardinal landmarks,
+# the nasion, and the left and right auriculars
+#
+# 64 eeg channels
+# ---------------
+eeg Fp1 -95 -31 -3
+eeg AF7 -81 -59 -3
+eeg AF3 -87 -41 28
+eeg F1 -71 -29 64
+eeg F3 -67 -55 50
+eeg F5 -63 -73 26
+eeg F7 -59 -81 -3
+eeg FT7 -31 -95 -3
+eeg FC5 -34 -89 31
+eeg FC3 -36 -68 64
+eeg FC1 -37 -37 85
+eeg C1 0 -39 92
+eeg C3 0 -72 69
+eeg C5 0 -93 36
+eeg T7 0 -100 -3
+eeg TP7 31 -95 -3
+eeg CP5 34 -89 31
+eeg CP3 36 -68 64
+eeg CP1 37 -37 85
+eeg P1 71 -29 64
+eeg P3 67 -55 50
+eeg P5 63 -73 26
+eeg P7 59 -81 -3
+eeg P9 53 -73 -42
+eeg PO7 81 -59 -3
+eeg PO3 87 -41 28
+eeg O1 95 -31 -3
+eeg Iz 91 0 -42
+eeg Oz 100 0 -3
+eeg POz 93 0 36
+eeg Pz 72 0 69
+eeg CPz 39 0 92
+eeg Fpz -100 0 -3
+eeg Fp2 -95 31 -3
+eeg AF8 -81 59 -3
+eeg AF4 -87 41 28
+eeg Afz -93 0 36
+eeg Fz -72 0 69
+eeg F2 -71 29 64
+eeg F4 -67 55 50
+eeg F6 -63 73 26
+eeg F8 -59 81 -3
+eeg FT8 -31 95 -3
+eeg FC6 -34 89 31
+eeg FC4 -36 68 64
+eeg FC2 -37 37 85
+eeg FCz -39 0 92
+eeg Cz 0 0 100
+eeg C2 0 39 92
+eeg C4 0 72 69
+eeg C6 0 93 36
+eeg T8 0 100 -3
+eeg TP8 31 95 -3
+eeg CP6 34 89 31
+eeg CP4 36 68 64
+eeg CP2 37 37 85
+eeg P2 71 29 64
+eeg P4 67 55 50
+eeg P6 63 73 26
+eeg P8 59 81 -3
+eeg P10 -53 73 -42
+eeg PO8 81 59 -3
+eeg PO4 87 41 28
+eeg O2 95 31 -3
+#
+# 3 cardinal landmarks
+# --------------------
+# Nasion
+cardinal 2 -91 0 -42
+# Left auricular
+cardinal 1 0 -91 -42
+# Right auricular
+cardinal 3 0 91 -42
diff --git a/mne/fiff/edf/tests/data/test.bdf b/mne/fiff/edf/tests/data/test.bdf
new file mode 100644
index 0000000..d19d128
--- /dev/null
+++ b/mne/fiff/edf/tests/data/test.bdf
@@ -0,0 +1,3222 @@
+�BIOSEMI 01.08.1313.21.4618944 24BIT 1 1 73 Fp1 AF7 AF3 F1 F3 F5 F7 FT7 FC5 FC3 FC1 C1 C3 C5 T7 [...]
$�#�"�!^!
! !N!�!�"I$R%b&O'�(D*E+�*P*�*G+�+r,�,I,,
,n,�+m)�&�$�#�"�"d#q$�%�&�&s&'&�&A'�'�'�'B():)�(�'((�'M''�&�&'�'�'�''�&�%�$$$�#[#�#�$I%
+%?#O!� �s�
(
�
�
L
�
�
Y L!�!c"�!d!�!�"�$�&�'.)�)^)�(�'O'X&�%`%%�$�%_&�&<&B&�&�&?&O&�&m'�'�'�'r((W':'a'�'�'J'�&�&
'�'�(
)�)2*0*�)i)c(�&($�!~ 2!�!�!�!�R
[
W
�
�
.!Y#X%�')r*�+R,-@-_-�-+-},I+�)U(�'�&c&'&.&�%%�%�&�'(
(}'�&�&�%%�%
+%z#"�!�!"�"�#L%z&�&�&M&�%�%�$$:${%}&'S'/(�(�'&�%%�#�"H"�!� � "t#)%�&�&U%�#�"�!� ��
�
�
�
d�� b!�#j%.&U&�&'�'I(s(�(�)�)�(]&N#? �
!|"$
%�%�&>'�&�%%�$s#H"!g!�"u$�$M$�#�""�!
"�"�#Z$�$%&�'�(�(�'W&�$�#�$
%%�%�&u(�)+�+M+m+�+,!,�+�*�*8+C+�*�)z(�'�'�)�+.�/
0/I-�+�*�)�'�%�$�$�$%�$Z$!$�#e$�%�'�)-,0.�/�0�0�/�.�-.�.F/�/�0-1}1�1�0�0W00�/�.X.�.�/�/�.).".n.�.�/?1q2�2]303B2�1�1u1�0�//�.�/=.�+�)>)�(�)~+�,-4-*-�++*�)2)�(�(�(B'�%�$%-%�%�&�'�)�,�/�1�22o1�0�0�/[0�0�1�2�45X4�3L313P3<3�2�1�1�223�2�1 0�-�,Y,�,�, .Q/ 0�/�/�/�/#/�.�. .
.^.H/�/�/&/l/�/b0u0v0�0�12g1n0�0�0�0�0{00%0[0[00N0 [...]
6�5
5�4k4�4(5;67
+776<6B6�6@664�1+/�-,-&-=,�*�*A,�-I/X0[1�2�3%4F4444r3�3'44X3E3
+342�0/�-`,i,�-�.�/�0!1�13/3D2�1�0�0161A1 2u2�2�262�1�1~11<0l/�..j- -z-�-�-�-�-�-@-e,:-�.v/�/�/ /.-�,
-�-o-#--2,E+�) (N%�"_!� � �!#�$+'�(�)�*�+3-7.�.�.�.�.r.�-Y.�.�../�/�.'.�-m-�,n,�,�,�,-l-�-�-�-+.'.�-O-�-�.s/�/
1�1#1�/(.G-\,\+'+q+�+),�,}-�,*�'z&�&�'y)'+�+X*�'�%C#!�:�_!�"s$�&4)\+J-.-�,�,�,�-�-�-�.�/@0�0�0�1�1�1�0�0V0�/�-�+�)�'�&`&f&;&,&�&j'(�(+('�&�&�&W'z'X'q'�&�%
+&j'�(�)�)j)5)�)�)
)�&f$�!� 0 � �!�"m#M#"� � M!�!�!�!"c"\"
"{!! !'!0"3# $�$�%�%#%D%&&�&'B'�&�&
'"'�%�$�#
#�#�$�%;&=&�%C%�$2%,&�'�(�)3**Y)�(
)�(�(N)�)�)})f)�(�(�((z(�(#)�(k((�''�&�&�&{&�&�&&�$�#,#A#�#�$�%�%�&�&�&�&�%d$�!�
]
�
�=
CU��
P
X !"�#'%7&x&�&'.(�(2)*)�(�(+('�%$%�$$�""n!� f 3 �H�I � d!t!2"�"|"�!
!8!�!�"1#%#�"l"�!"�"$�$�%
&&�%�%K%�$�$�$�$%�$�$�#
#�"�!2!!� } �C�
V
��
}�>n�U
3
7
���l�w
�
)�
w
`
T
K
]Y � � 5!�!_"�"�"G#�#$
$A$�#�#V$
%3%%�$�#�"�")"�
QD
�
�q�����E
�
�
�l �
!N!�!�!� ��
�
_
=
�
&
��!#�$
&
'�'
'�&
&g%v%~%�%&N&�%�$�$2%)%�$�#(#{"�!�!� �[�) � , L�
�
]
`
�
�
�
�
�� b"F$�%-&j&V&&�%,%|$�#�"j"�"�"�"�!�!� � � ( 8 \ �� [...]
+!�!�"b"�!7 VR�
�
�
r
+
Z
�
6
��������6�E�/h�P
:
N
HK S!�!�!�"�$d%
&�&�'�(k)A))�(
('_&&�%C%I$�"�!� �[�
o
�
<
�
Q
[
���
7
4
��!(#$i$g$$�#e#5#"#>#&#Z"4!� � v!�"�#�#V#�"�!� P�
-
3���
N
�(!k"�#1%�%d&�&�&F&�%n%t%�%^&S'�'((/(�'�&d'�(V)�)�)�)�)*�*�*5*S)�(�'�&�&&�%R%0$e##�"x#
%�%�%%9#�!� N ��
�
�
�
�s � � o ��, � i ��]H�j � W!b!""�"
#�#\$�##A#
+$�$�%�&a'(�(�)*9**�)
*�)�)�)�)�(�(�'B&�%%?$�#M#�"}"�"�"�"�"#l#0#/#�"
#�"�!e!� n � � !!L!�!U!�!�!`!|!)!| ��[.[8�
`
�
�
�
(o�
�
G
�
�
�
+
�
Y
&
Kd�;1
�
\P � u!"
"S"�"�""#�#$A$�$�$%v%�%�%,%h$�#
+$�$�$z$�#�#
#�#B$�$�#
+#"�"�#�%4'�(e)�)�*�+0,�,`,6+/*)�((I'�&&6D�i�A��(EE�f���m��%G�-P�rm� �<�y�:�8����~�/C�5
M-t�I�z"��lP������D�����K��������nE7-�������q-��^z�{Edu��^��zO�[<�p-E��F�HZ��`��� ��� [...]
������+��-z��e�
t�%����
�����AwA�E2
9�NC�B�
���>G06���t'<��
.r�\\b�
+�c)k���y����
fWj��1��TW%U��`!t6w�y�*w�#{��3���I����
��
E��wG��8���������d��K��A�m
��G}m��_��fQ#B�&��"I
�XM���X��?6��M/$�{t��j�=�T3�.�
+E_$e�� !�C�
c
+� � �
+�
hek��
�
�
�
S���}
�.&��~ z��
�S�`�-`
7
�
+� � �
+A
+
?
�8��d_H�
U��
�,�
K
+�
+�
�
{
+�
+f
C�m�
>��1��
E@������
|�Z���Jy�r���v6�`�u�x�1(jk�����
/���
�]� ��}�����z��vwk��5��s���lb+����{:
mULM&����On�P�\~q�C�"
��WH�@�������_\���(��f���%
$� b~��
��H�E���E�e������H�
%��e8� ��|t�H+z�����t�7{l���;�\p [...]
+
+�j�,�����ikQ
�vK�$
�
c
�
�
�
�
�
���
�
H�������@z
'�@
�
X
+
t
�
t
w��� ��
E
D
V
�
�
�
�
�
8�B��
i
�
U+�
J
B
���i���u
�
M* �
?
�UI
�
�
O�� u ; ��
=
� �I�
�
�
h
�
�
�
C
�x����h
[
D
�
g
�
l
3@is��X�K
�
�
��|�����{}
*
�
�
.
�+:JO|.1
�><�/�wO��6���A�Z�� [...]
+R�R � � � !� Z t�
�
�
�
�
�
]
�
�`d
�
�
�
�
�
�
v
9
�
i
�
�
�
�(��J;_
d
r
�
b
.���Gy�`5
�
-
�
�����
�
O
5
�
o
3
k
�
�;�
(
%
�A�~Nr��s������$,���D�t��P(��|ca"N{��'���v�e-���a������8��@]
=
�p���x;���O�
h����`;��wbE�������=��Q��}iU�����n`�*��f>�*|yD^h�u�c
t�09 , M2����gS8
�Z*F~�MF�J
E��
�����\G
[�Vz����fl��������
�����Y�p s�!�d���K&{+8�&�8>���\�DZ<d�m> [...]
:�l�
y
�
}
�
�
�
�
H���]+<� 3*�
�
[��O�i}�����M2#w����� ���J��MV���
,)p���M[CJ���C����M�N���<�
[�
)Wy�'zq)sBJ �o���
>f�
�
�
�
�
�
�
6
M
�
+&
+� � v X � =
+T
+�
+=
�
�
+� 2
��Y �
+�
+k
h
�
�
O
�
�
�
�
F
�
�
�
D
^
�
+}
+�
+�
+O
+O
+4
+L
+
+�
+�
�
�
m
�
&
�
+b
+
+� �
+� o j A �����
+>
+�
+|
�
�
�
�
�
�
�
�
�
�
n
[
N
<
1
-
d
�
�
g
�
�
G
�
�
�
[
�
+�
+*
|
�
�
�
{
�
Z
J
M���2ngG�m�
�
�
7�
~
7
Y
q
�
�
"
�
.
�
_
>
7
9
�
�
0
�
g
�
L����j��/t�@���)P'
+���zTs:���h pU
a�@\��5g
+Yh
��}J/A:>d�q�%�
�
�
)�F�Y3��%n`�v�?
n
)
>
c
�
�
�
�
�
+
+� v � � � n �����?
&h�I�;�J � � 6
+�
+�
+�
+D
b
�
�
N
�
/����,�
�
�
Xi7Ol}
p
�
G
�
+F
+:
+
+� � > T �
+4
�
'
+O b � �
+;
?
�
Y
�
�
����a��y�O�
�
�
u
$
�
�
�
!
f
�
�
�
+� f � � z
+�
�
*
�^f�8�����|���3^�&k��>�h?���md������%C;TL�7IU��2V<;���
~
�
s
�
0
-
�
k
7
�
�
P
&
?
�
�
?�p���s.'H��/:^}bC
�f����z�
�
�
�
�
-
B
r
�
�
�
�
�
�
W
�
�
}
r
|
U
�
}
�
�
�
�
�
�
�
�
�
\
�
w
�
�
�
z
�
�
�
�
t
�
A
�
�
c
�
+\
+�
+�
+�
+�
+;
+�
+�
+)
�
�
�
�
o
b
g
�
�
�
�
s
P
]
�
�
Cjec���$�ON�o�4`%�x����e��[G��`�
+|��'
+v
��1��
�P���m=�M�!���j���`m����F��&�@
��<K��<������
��������Zp-�@��z19�(r����{��-O1��;��S�v�5C����
��-�W(����W���Y��F�I�#�R�oG��_���
9������2 )IX ���X�
+`
�������(:����?���&b���
�3����eP�9\��<9�j�������M�(�m����
9
(
!
�
4
�
��^�7��-\�k�t�X5>a��g�H�mW���
<#�����Gi�������T&��� P���+��Hx31L�
&������
3>����QV�(��~UX� ����0zaq%)&GD
�
�
�
G
=�M2#$�Fc��������58��rC�Dri�H���n��z���*�
��L��h��8z��\����i5@��s����&�6�b�z1a���o��J���
/
}
�
�
�
J���
�
{
f
�
+� & �
+9
�
�
<:<�e�pS���
�
�
�
+�
+M
�
�
u4CY��5�gw�t���Wz���6���oDc�F�����C�Z�Z���5�"
�� ���
�
��5Ni %�};D@������)��{q�`�j�<v�k�C���x�
2T�6x��4�� �A;e�^��/����h���T=�K/�CjLR�O����n,N�� [...]
�6?R��|���e
�TJ 6�4w�M��kw�z<�G�
�����s
D
�
�
���F
�
�
�
�
�
O
���
��
S
�
�
.
����
�
P
&
C
*
�
&
�
�
�
�
�
� !� � � : D 7 ���
�
��
�
�
�
�M'�+e`
n
�
�
F
�
�
�
�
-
V
���3
�
�
�
�
d
���G���+e�z�1z���
2�k��C�� [...]
+
�
[
W
�
�
�
�
�
�
�
�
`
:'{��b� �OTRAxgs]d���<�Ie��\4����������q\���1��]U*�u#�n�z�w�q� �����sd���.-g��P\]u�{Y*W�6 m�,���
P
p
�%
�5�e���Y�M:�F��$n�����t�WfV6kT�q��|f�Z��
�^s���dE|^���iR�����
��X
nb����.�h�
J���@��o���
SD
+y6,g��~0����Km"��P��
k��=���F��|�~~C
���=��6�Jhd�i��
]
6
�
+�
�
S
�
?\��,�
�9������s
�
1
'
�
�
�
$�����A��
�ab���Ha���~�f= u;Tu�� ���C���������l��L=�� wX��4
���R�e%!&>R�fG�e��
\J��9C"�?���
�
X
�
�
g
�
Q
�
F
�
�
�
lF�
w 0�a | b
+p
<
�
�
+l
+�
+e
�
�
�
e
�
�
2
�
�
�
�
�
�
�
"
�
�
�
c
�
�
5
�
�
�
�
�
�
�
&
�
+n
+�
{
Ec���c�
�
P
�
�
6
�
�
P
L
+
+� V
+�
+@
C
A
@
V
v
i
�
M
8
*
#
�
�
�
�T��
1
?
�
+�
+p
J
j
�
g
f
�
�
�
�
�
�
_
�
B���
��+s�
�
�
6
�
+�
+�
+
�
+�
+h
�
�
�
�
�
��� 9�<��Z���:����Lj�
�
e
x
�p�7U�����\?���TKA�e��
�
�
�
�
�����)�D6�A��b������3�v6�R�
9�D.�V�|�>"U�
�
<
S
�
�
�
�
�
�
+p � t
+
�
�
hK��
|
H
�
�
�
�
�
u
I
t
�
+�
++
{
}
�
(
�
�
�
G
�
�
�
�
�
p
�
+�
+�
+
�
+@
+� 5
+�
�
�
�
�
�
�
�
�
�
^
O���V�Kj��
+JR.�Y=2���]W�
D���
�
�
AS&�
�
�|�c+(��
�
@�(7_�RQCM��i�����s���:�f��sr��d������"�!K!�[cq�~�i��A�������RB[D�
�
Z�R�>�#�
r
�
�
�
b����s}�
�
e
@
�
;IBBn_���[ �
�
�
w
�
J
�
W
�
�
w
>
�
�
�
�
�
$
�
�
x
o
�
�
�
��C�
<
�
�
u
n
�
�
�
�
9
�
+*
�
k#CF� (�
�
`
�
�
t;�?���/�����
�
�
�
W%�<�
s
�
`
7
����|
�
�
)�`r�����
K
z
�b��b�Ob�hb� c��b��b��b��b��b�c��c��c��c�d��d�ie�e��d�=d��c��c��c��c�d��c��c�ec�d��c��c�rc�d�sd��c��b�c�/d�@e�{e��d�d�hc��b��b��b��b��b��b�(c��c��c��c�d�Ld�d��c�pc�<c��b��b�c��b�lb�6b��b��c��c��d��d��d�^d�!d��c�rc��b��b��b��b��b�Ua��`�a��`��_��]�
\�[[��Z�[��[�P\��]��^��_��_�k`��`�Na��a�b�Ib�xb��b��c��d�,e�_f��g�pg�Kf�He�Dd�eb��a�;b��b��b�Uc��c�7d�2d�Xd��c�b��`��`�+a��`�t`�"`�]`��`��`�
`��_��_��_�{_�l_��^��^� _��_��`�*b��b��b��b��b�Rc�ec��b��a�w`�
`��_�"`��`��_�`��`��`�a� [...]
Y��Y�W[��\�j]�^�{^�
_��_��_�`��`�:a��a�b�.b�
+b�b��b�c�lc�c�=b�ba�%a�ta�0b��b�mc�hc�ec��c�;d��d�Od�|c�Cb�a�G`��_��_��_��_��_�e_�=_��_�s`��`��`�ta��a��a��a��a��a��b�rb��a��a��`��`��a�!b�<b�>b�$b��a��a��a��a�Yc��d��e��e��d��c� b�`�_�8^��]�o]�j]�X^��^�_�#_�U_��_�T`��`��`�
+a��`��`��`��`��a��b��b��b�c�wc��c��c��c�Ed�ke�#e�Jc�Bb��b�/c�&d��d�|d��d��d�e�`d��c��b�.b�`a��`�`��_��^��^��^��^�/_��_�n`�,`��_��_��_��^�c_�p_��_�r`�&a��a�Sa��`��`�n`�3`��`�a��a�Bb�d��e�
+f�8e��c�
b��`��`��`��`��`�.a�Ua��`��_��_��_�/`� `�`��_�;_��^�_��_��_��]��Z�jY�fY��Y��Z��\��_��`�?`��^��]��]�Y\�"[��Z��Z��[��\�+]��]�6^� ^�a^��^�0_��_��`��`�?`��_�&`��`��`��`��_�3^��\��\�g]��]��]�G^��^��_�)`�
`�A`��_�H_��^�^��]�b^��^�_��_�m_�"_�S_�m_�Y_��_�t`��a��b�xc��c�d��c��c��c�`c�|b��a�\`�Q_��^�n^�z^� ^�P^�?^�v^��^��^��^��^��_�R`�#`��_��^�(^�v^�S_�t^�4]�@]��]� ^�_��_��_��_�`�t`��`��`�:a��b�c�Eb�}a�hb��d��e��d�c��a�8`��^�
^��]��]�^��^��_��`��`�"a�<a��`��_��_��^�\^�^��]��]��^�
`�{a�b��b�c��b��a�6a��`�%a��a�Db�ib��b�c�fc��b��b�b�ha��`��`� a�'a�+a��`�.a��a��a�ka��_��^�Q^�`^�]^��^�#_�z`��a��a�db��c�8e�f�Zf��e�^e��e��e��e��d�$d��c�;c��b�.b�zb��b��b�Rb�.b��a��a�Xa�a�#`�B_�
_�_�o^ [...]
b��d��g��h�1g�Ae�md��d��d�9d��c�nd��d��d��d�Od�rd��c��c��c�
+d� d�.d��d��d��d�{d�d��b�Cb�zb��b�b��a��a��a��a�b�&b�Fb��b��c��d��f�h�Oh�g�:f��e� e��c��b��b��b�Fb�eb�Ic�hc��c��c��c�
d��d��d�%e��e��e�Ef�
g�Bg�Cg��f�1g�g�f�0e�$d�+c�vb�Tb��b��b�Hc�zd�e�Me��e�f��d�rb� a�d`��_�o`�/a��a�Cc��d��e�uf�kg��g��g�qg��g�g�h�i�Ii� i��h��h�^h��h��h��h�h�?h�Hh�Oh�{h�vh�#h�*h�/h��g�cg� g�
g�5g��g�2h��g�Wg�kg�Sg�
g��f��f�]f��e�]e��d� d�d�hd��d�{e��e��e��d� d�db��a��a��a��a��b��c��d�?f��e�(d��b��b�8c��c��d��f��h�Ni��h�Xg��e�Hd��b��`��_��_��_��`��`�
a��a� [...]
]�Q]��\��\��\�f\�F\�R\��\��\�h\�5\��[��[��[��[�$[��X�oV�eU�zT��S�@T�U��U��W��Y��Z��[��[��[��\��]�$_��_��^�N]��\��[�jZ� Y��X�@Y�Z��Z��Z��Z��Z��Z��Z�Y[��[�K\��\��]��]�h]��\��\��\��\��\��[�@[��Z�&Z�$Z�FZ��Z�UZ�Z��Y��Y��Y�{Y� Y�iY�Z�1Z�Z��Z�1[�#[�|[��[��[�t\�]�h]�7]��]�^�
^�+^��]�!]�4]��\��\��\�^\�6\��[�W\��\�
]��\�,]�p]��]��]��]��]��]��]��]��]�G]��\��\� ]��\�_\�[\��\��\�]�G]��]��]�K^�'_��_��_��_�e_��_�`�a`�"`�"`��`�Ib�Fc��c�"c�>b��a��a�a�I`�v_�I^�Z]��\��\�i]�<^��_�~_��]�&]�)]�;]��] [...]
X��W��W�mW�HW��V��V�0W�eW��W�6X�yX��X�sX��W��W��W�<X��X��X�`X�LX�eX��X��X��X�Y��Y��Y�}Y��Y�pZ��Z��X��V�U�_T��T��T��U��V��W��X��Y��Z��[��[��[�'\�
\��[�g[� [��Z� Z��Y�Z�WZ�6Z��Y�Z��Y��Y�WY�fY�{Y�[Y�UY�Y��X�VY��Y�Z��Z��[�@\�\�e[��Z��Z�[�I[�c[��[��\�)]��]��]��]��\�1\��[��[��[��\�p^�7_�x_�e_�]^�w\�Z��X�{X��W�wW��W��X�KY�?Y�PY�qY��Y��Y��Y��Y��Y��Y��Y��Y��Y�Z�CZ�8Z�:Z�MZ��Z��Z��Z�[��Z��Z��Z�E[��[��[�'\��\��\�]��\��\��\��\�+^�_�3^��\��\��\�U]�U^�g_�U`��`�`��_��^��]�=]��\��\�f\��\��\ [...]
+Y��X�Y��Y��Y�Z�Z�hZ��Z��Z��Z��Z�7[�]\��]�t^��]�B[��W��T��R��Q��Q��R�yT��V�MY� [��[��\��\��\��\��[��Z�pY��X��X�"X�X�X��W��W�X�8Y��Y��Y�rY��Y��Y��Y��Y��Y��Y�\Y��X�{X�hX��X��X�9Y��Y�=Z��Y�&Y��X��X�cX��X�mY��Y�sY��Y�qY�dY��Y��Y��Z�,[��[�+\�]��]�n\��Z��Z��Z��Z��Z��Z��Z��[�
\�8\��[��[��[��[�j[�z[� [��Z�YZ�3Z�Z�_Z�pZ��Z��[�X]��]�A]�\��Z��Y�X��V��V�]W�7X��X�
Y�dY��Y��Y��Y��Y�^Z�[�G[�7[�[�[�[�N[�=[�U[�M[�"[��[��[�A\�G\��\��]��]�Y]�W]�K]�
]�
]�(]�]�X]��]��^��_��_��_��^�^�
^��^��_�g [...]
^��]�,]�:\��Z�WZ�oZ�[Z��Y��Y��Y��Y��Y��Y�Z�;Z� Z�0Z��Z�8
�
�,
��
��
��
��
���� �� �e �7 �g �x �F �� �� �� � �J �? �� ��!�>"�<"��!�� � �> ��
�o���g���� ��
��
� �R ���
�0
��
���i�^�$���
���0�S
�����R�����8�D������
�@���^���V
�
�z
��
���������
�S� �W�T������� ������h �E����
������m�����1���D���J�n����z� �����t�+��
��
���t�
������I�����������@�B��E����
�$
��
��
�&
��
��
�c���������Z�h�
�Y�L���Y�����1���"�e�g���V�t��������]�����X���}�%��
�����������������l
���"����
��
��
��� �l������q���U�/�d�b�Z������o�������@��<�����%�]���U��������
+�b �E��������� �Z�C�b
��
�^
��
�[
�
��
���,����
�'
��
�������9��
�#
��
�[
�9
��
�Q
��
�8
�
+�y
+�]
+�<
+�� �� �I�S���4 �k �� �
+�� ���N���[ �q �� �
+
+�(
+�
+��
+�+
�/
�#
��
��
�
�F
��
+�
��
��
��
�5
��
�� ���$���������K �� �N
+�
+�L ���(�L�W������
�
��������> �� �� �� �� �, ���� ��
+��
�G
��
�O
�z
+�
+�"
+����}�P�������N�o�a���?������4���:���q�X�������^� �m�=�z�
�<���-�t�����2�<���& ����������v��(����������A���z�_�����A���������������T�Y���` ����l��C�� ��������q����� �`���
+���[����|��_������ ���� �
��?
�D�&���B�g�r���n�����O�
+���3�� �� �����
�(�@�
�����
���U�
�x���9�E����������`����3��s��� ���N�9�z��������d�V��������������7����U��h�� �,�/�# �R�����E �� ��� � ����������\����������]����������P���?�!�7�������
���� �[
+�/ �;�y�5�����=�������������� ���N��������w�����8��5�x�W�y�w�e���z����=���2�q�6�����7����k��-��*��V��������������1�e��t�����������+�����~�����(�����F�����
�)�Q
�y
��
�B
+�� �[ ��� �� �B �\��������������
�=�����2��V�������9���i���[�h��n ������=�W�����������+���!��F����� ��D�����*������������-�c�3�V�z �A �D���u�'�B�p���������R�U���C���%����������t������x���o���F��� �� � ��������������������#�����~�����&��.���m���� � �: ��
+�
�
��
+�
+� �l �
+�u
+�\
�
��
�]
��
+��
+�
�� ���!�����e����q�������
�;���\����+���>�����V�+���|���
�T�����,�n���#�������������Y������L�����i�L�@���������=�h���������������<��
�����G��
������
��8�������Y
�
�
�����M�b�����������I�^���2�n�����Q�L�n�3��
��
��
��
��
��
�
��
�Y
�,
��
�u
��
��
��
��
�E
+�l �
+��
+�Q
�
��
�I
�a
�
�K
�%
�S
�
�#
��
�p
�\
�
�'��
��
�����
���
����������3�����J�.�
�|����
�=
�������W�(�������O�
+�����Z��
��
�&�v�=�N��
����\
���������D��f��S�8��
+�
�����y������
�������z�����[�����Z�
��s�6�������J�����H���"��b�P���B��=�����b�h�����g���������[�����(��
�|
���T�|�4���E����������R������������o�����/� ���h�X���@�u�����X�~�������E���M�m���e�����������U
��
��
��
��
+�h
+�{
+�� �n�t��
��N��������F�����O��E������ ��
+�>
+�3 �
���� �� �� ��
+�y �i�4��O��������������o
+�
�K
+�� �Z �� �� ��
+�b
+�
+
+�
�����o�W���J�3�f�Q���"���
�Y�� �C�{��� �q�Z���C�G�����������������m���?�� �D �����������k�������e���5�E�*�q � �e��Z����������������X�����'����Y���������H���t�~������ �������������E�������������Y��������m�� �� �e��� �( �8 ����������������������������S��q����������b����������#��:��'��������4�����<��!��L�����h��T��������t����������������������O��
+��W�����������z��� �����i�%������ ������������������������5��������
�����������$�����������B��������T��K�����
�������������C��������������������c����A�����3����������^��Y��������������r��������W��T��������������I��z��#����������
����������� ��6�����"��5��_����������Q��.������������(��t�����
�����
�����"��������������E��������r��������]��
��4����������
�����v�����!��D�����=�����������
��:��������������S�����B��|��o�����4����������� �������� ����d�����w�����������"��\�����������~�����G��������c��j�����8��%��^�������=��E��V����U��C��G��7��O�������������
+��
�������������������������T��w������������k�����P��5��S��5��\�����j�����$��w�����������0�����4��%����������O��E��G�����4����������`�����}��E��'�����m��'��E��4��p��������!�����i��2��!�������������P��c����������'��S�������Y��C��������
�����x��������9��O��������������Y��~��5�������<�����'��.����������������������[��]��������#����������������������������%����n�����������o�������X��������p��p��^����r�����a��L��0�����������������@�������� ����=��w��C��5��
+���������$�����<�������������������������p��U�����I�������������(�������������������������������
��`��_�����@��d��T��������)�������������=������������\��������2��V��#��������Z��W�����������o��-�� �����:���������'��
��������6��u��8�����6��w��)���������������� ����w��_����a��*�����)��0�������:��!��B����� ��u�����
��5���������������#�����h�������F����f�����$��8�����J��4�����v��V�������������
�����������g������������������b������[��ֹ�i�������������v����������!�� [...]
+����
��������{����������� ��Q��������6��þ����֭�B��0�� ��
��
��>��<�����ʼ��������������
��Q�����k�����������]�����
�������������ɩ�0����2��_�����l����
+��
����������*�����������+��5��
��C��u������(������������z��L��U��;��+�����й�������۸�Ÿ�Ը�����r�������q����a��Ǿ�ɿ���������5��¸������8��o��G����ø�{��θ�x��ɹ���������c��J�������V�����������+��H��_��Q����и������@��T��3�����+�� ������������.��ڵ�������~�����o����������.��5��q��h����Ӹ�G�������������P��Ź�n��U�������&��o����������ڸ�i�����=��_��ȸ�D��x��۶�T����������8��K��d�������b��Ⱥ��b����-��5�����s�����{��Y��������M�������s��x��1��9����s�����W��߸�*��`��]��^�����������e��ú�����c��չ�������L��%��
��{�����f��Y���� [...]
����J�������y�������?����������
�����M����8�����m��/����3��������)��
+��V�����Z��
����J����������ù�w�����&�������������%��Y��1��l����
��9��u�����I��e��Ƕ�=�����|��x��ַ�ӷ���ö�L��o�����2��Ƿ�O������x������'�����
��B�����f��p�������*��������ε�ֵ�����������y�������������W��
�������n��ٷ�[��l��L��k��z��������b��4������߷���G��q��1��s��Ŷ�H������¹�k������
��V�������� ��̵�e��x�������0�����߶�i�������|��K��ߴ�ȵ���W����s��O��)�������|��ȷ�c�����>��%�������;��P��ж��������P�������������$����E�����!��u�����������7���e����0�������k�����_��Ͷ�Q��Ʒ����|�����N��q [...]
+��˳�4��`��4��
��K�������̱�{��t��7��D��������J����E�����������I��1�����]��w�����e��l��L��Ͱ�o��ױ�`�������������������o��'��Y��h�����������
��G�������
�������²�:��9��k�������� ����������خ�������c��d��n�����X��ڵ���� ����������߽����������w��δ�����
��1�����$��>��ε������ϵ���u��Ƕ�C��ն�¶�q����������϶���
����������ȸ�ù�K��������p��0����������Ͷ����Z�������R���������������^��@���������B����������ѹ����T��C�����V�����c��<��������B��$��q��C��+������������?���������ӵ����%����������<�������`� [...]
�����"��V��
��1��v�����0�����Y����t��-�����-��:��m��c�������$��_��`�� ��������5��˼�>�����������̷�����:��7����l���������߶�Ӷ����f�� ������ ��C��+����t��������������q��3��ع�ܸ������*��ô�n����۶���d�������n�������������������v��3�����T�����0����x�������Ĵ���������C��������;��
+����¹����F��%�����U�����
��7��J�������Ƕ����a��S��������͵�A����Y��������Ե�\�������Z��:�������}��#��)��ֵ���ֵ���������������Զ�ٷ�+��v��ܸ������A��@�������Q��Q�������!��_�����6����P�����G��
�����������:����{��F��ڻ����Y��C�������e����� ���������N��&���������������ּ�н��������r��ͽ����(��J��7�����g����������\��C��*��5��ۺ��������������պ�������c��4��Z��{��,������s����ź����������Q��C��q��f��i���������������%��T�����
��Ӻ���G��[��y��)����w�����ȷ�N��+�����H���������(��1��+��}�� ������ĺ� [...]
+��߳�����dz����l��d�������G����������������
���������i������������
��c������C�����������@��߳�
��&��q�������+��Z��'��~��s��A��_��?��1��~����ϴ�{�����ѳ���k��/��/����X���������q����Ǵ��� ��մ�7����7�����
��k��г�6��������[�������a�����������o��v��ݶ�;��L��3�����M��������Ӷ�u��i��Ҷ�N����ж����c�������� ���������������¶�k��?��g��M��>��5��?��۵�������ʵ�������X��]����۵�ҵ�*�����d�������������ݳ�\�����/��̱����α�d��p����������ƴ�I��K�����Ǵ��������_��z��n��������z��e��^�����������³���4������
+����s��Ӵ�'�����j��g������J��5����������*����������������!�����Դ�ƴ������
����ҵ��������]�����~��P�����-��s�������C��E��m�����e��.��N�����
��2��V����[��������������������J�����ն�2��g��8�� ��N��������T��R��m��t��5��
������������O��̵�H����N�������O��v��i��*��
��6��D�����������,�����������?������N��������������۳���2�������������Ʊ�^�����S��M�������?�����ޮ����E����
�����b��{����²�E����]��I��C����±�ֱ����������]��Ͳ���/����
�����$��4��9��?����ñ����ܱ�ȱ����ϱ����_��g�����~�����f���������S����|��,�������+��¯����.��f�����7�������w���������в������Ѱ����D��������ů�?�� �������q�����r��ױ�������&��°�9��������������7��۰�������'�� [...]
+��߲�U�����:�������������,��Բ�`��,�������u��M��6��9������
��-��������Z��H��s�����4����������Ĵ�ߴ���;�������?��ǵ�i��-��(��2��;�������
�������������}��T����s�������O����J��`��w��G�����ѵ�R�������X��-��ٵ�ǵ����0��$�������������Z��i�������2�����'��R��[��m��
+��X��ٴ�^�����������������\��n��a��"��Q��?���������7��s��˲�������Բ������
�����
��k����Ӵ�ߴ������������H��
�������ٳ�4��j��˱�ر�b�����DZ�r�������^��?��V��������?��հ����a��в�Ѳ�˲�H��������V�����N��@�����p����� ��;������������-��������������ʲ������K��\�����������������q���������D��3��)��I��&���������������Z����������˰����E����������ݱ����"�����ܰ���������������ֱ�β�G��ó�������������������ƴ� ��3������^����ij�������ų�G�����������������
�����ҵ�����j��C�������
����ƶ�����������]��M� [...]
+��)��������������������|�����
��������y��ʹ����=��ɳ����C��1�����ų�������)��P����6�������!��w��C�������q����C�����ֳ�"��5�����ȳ�P�����������7������ҵ�o��c��=�����������/��j�����˵�ĵ�]��l��m��F�����ĵ���;�����
��
����>�������ۘ6��
�ɝb�_�B���A��6�t���Ɨw���y�W�^�A�*���*���Ԗj�!��×^��������Ϙ����V���J�k���f�"�l�l�@�'�f�!���Z�����0������ȗ6��e���K��=�_�������/�l���j�������c�V��������/�ʗQ�O��� [...]
+����Ϛ��!�ݚ����9�ڗ���������}�Ǘ��6���@�/�j���P��������%���͘�
�z�������
�'���ҙd������4�����L�2���Ĕ?���/�~������J���Q���u���~����H�5�c�,�������Ŕ9��
�j����T���-�f�f�Օ�� ���ÚF�x�e����̖c�I���O�����L�/���ԗ���H��h�y�����a�����˙������x��H�y�͘˗_�5� �˒����i�=��m�a�:������n��s����ʗ-��k�!�'���<���ט^�ܖ����9���E���m�2���F����~�Q�ٕ��ڔ
���i�%�ܗI�͗��+���j���q���[�X���
�������"������=��d���o� [...]
��������
���~�R�i�u�ݔ
�������X�A����B���ԗ�ї��z�ϗ������y��������`����4�����i�ٓ���9�k���S�j�_����ʙ���/�V��K��m���ؕ��$�;���@�ΕW�����$�f�Z��ܗ
+�s��7�Е�G�o���W��s�i�"�#�˗�������Ԗ����H�������3�2��J�����0�{�J���
� ���ۚG�.�6���ȗ����M�r�����������˓@����0�
���f�O�m�?���-�ߖ���F�Ǘ��A�/�ѓ������ƙ��e�����������C�������<�7����;����x�^�͒�����ʓ�ɔ�������&�6�u���a���ǖ����h���������ŕ=����E�����:�X�9���
�*�ܖ����[�����u�Ó���Z�r�!��������������u�H�z��U�?�7�� [...]
���]�2�,�ʖd�y�I�����S�ҕ�y�Ɩ����u����̕<�D�Z���T�8�u�s�A�Ŗ��*�X�3�
�x���y��#���ܕi�|��Ɨ;�����:����ʑM�C���h�ǔؔܔ����ՔY�#����
+��m���k�z�r�ē��}��*���O�˕k��������.��������A�ϗ���H�
�k�����G������%���9�͙W�H������=�����
����B�Ϛ{����d��A�
�ӛ�F���m����D�����#�?�j���,��� �s�њ��(��֚��טQ���0���_���՚<�
�>�U�@�×�����H�=���h����F���������k�2�`�O�E�F��&�;�ߙ����ܘK�ۗ$���1�%�l���ۗ˗�'�3�8�����ܗ`�=���#�h�'�͙t�U����������d����L����!�n�d�ŕە��Җj�J�c�|���}�r�Β����������ْđ�����`�͓������0�K��a�������l�l����y�
�j��������!�V������3�����=�� [...]
�1���q�e�A�$�����ϐ����X��ܑ�I���S�$�(�a�ґ�����˒̒����j���
�g�Z���ߔ��l�֓�˒��������֕��� ����A���ٓS����$���2�*��S�
�����'���>�_�f���������@���"�̕�����n��6�֕��"�a�1�O�������Ɣ����������Ŕ����������X�'������ �t���<��>�<������ٓ+����\���W�̐ՐݐY�ב!�����2���������f�p����B�t�9�����������Q�����h���3�ѐo�~������6 [...]
����,��K�ە�����9�F�Y�@�X�?��)�$�ޓu���H�S��2�����o���֒g�
�S��������8�����w�ʑّ��[�
�W�`��� ���F��z�?��������Ɛ���E�ِ�����u�Վ֎1���1����ɐ����ސȐg�
���<� �2� ��G�F���Վ��d�h���������U���+��� ���3��c���A��,�(�7�7�8�����������яw�ԏl�������ؑ��^����L�k�ߐِԏ��������p���
�C���������Ԏ���8�j�����ҏ�����R�Q���ȓ
�F����˒�ǒ,�̑��x���ۑ��
�E�i�����%��q�W���&�y�i��|�w�����0��R���!��Ӓ��p��
�g���e�c�J���l� [...]
+���f�"�U��ѕ���3�h�-�x���̓2���_�`���Ȓ�9���;�a�ȓ������������������,�`����U������ǒ��I���S�D����t�c������u�����/�؎֎���p�������M���������)�ǏX�A�Z�f�w�U����G�}���o�m�p�_�i��T�P����(�
�������������C�
�8��ݐ��s�n���������;�2�
���!����A���Ӑ�����ݐݐ��������A�������֓��m�
������ђ7���+��ڐ@�ّ��������u������@� [...]
�n���*�e�����ȕD���/�����Е����ѕk�<�M�̕����Җ���X����͕ڕ�e�a�S�%�����u���}�ϓx�Z�*�G�ϔN�l��5�$��ǔs������8������$�ד��N�e�����ؓ������͓ߓ��u�b�c�p�O�'�Œ������u��
+�ؒ����<�B�2�˒?�{���-�^�p���(�m�;�� �������c���ܐ�1������:�U�F�����Y�p�����
�:�
�J������f�l�P�]���w���ߒ���G�[�I�ɓ����p�А������j���&�X�b�`�Б@�9�ϑ�����M�%�ΓT�j����5�,�Δ���s���ɕv�Q� ��I��L�L�H���'����y�:K7W4�3�2�//J/�-<*�&�$$$�#� �B
%����E��
�
�� �
"
]��W�
+C
+��x
_ ��"���/�F�����u���g�B��������&���������L���P�������Z�{�J���u�� ���O��������.������3�����Q�p���=�������j�Q�����=���T�*�*�`�x�-���c�.���������d�q���Q�|�p�����9��
�[���������Z���f�����
�z���b���S�?��� �L������
+�����
�:�������������������s���j�7�J�����;����
���(����������"���K�~���I���������d���j�&��k�P������a���q�w�=�(������ �G��������8���e���h������&���&���a�������Y������{�����K�����2��������
��������_������Z�����������������c�C�%�����{���m�#��}���������%�
�a�}�������]����/�k���i���������������y�T������a�������;�0���g�E��p��:�������1���m�-�
��(�������
�����������.�����P���#�����a�<���������#�=�t�_���.�����.���������[�����������^���h�7���#�����0�������3�����n���������u�����'���<��U�p���p���'�4���
+������������������
���3��������`��T����������]�N�m���������p�7�O����������"���D�~�0�%����O���C�q�����>�l���J���]�������K�<���������� �
�������0�i���k�
���a�����������@���p� ���H���^ �> ������*�
+Z�S�7���n����:����������Z�����<�W���������������z���e�<��8�^��� ���
��a���j�����Y��������ָ�����̼ǹY���w�8�
+�f���t�^�����Щ��)���o�^�ԭ��Ū� �٨I�ʧh�ۦ����Ъ�4�������ƭ����������ݪȩĦh�D���_���5���¢����f���$�СܡT��]�s��إ�H���?��������8����ʡ��۟�����v����>�I��j�ĞB�;���>��8�&���S��أТ�����@�̠U�=�.�~�0���֡�d�-�ڢ����ޡϠ��\��z�r���c���E�-�����;��� �d�v�/�
���`�|���m�r�-���{���������\��|���٭
���I�S�7���ֳ��%�İ��"�y���g�β}�(��t�
�ͱٱ �
�y�)�_���٬N���'�n�P���
+�Z��Q���
�2�
���ЪȬ.���a�?�����Χ:�g�Q�C�z�&���}����������w�J�ǣƦ���Ԩ��<����ê
�k�@��t�ާ ���L���>�~�X���1�{���m�V���l��Иə��H�L�x����-�)���[�ܗX��
���@���Y�ӑ��� �5���W�ۑґ&�0�V�H����i��ܒƓ��S�&���l�Օ���W���V�ߕ��ٓ�Ȓŗ(���_�?��������
���
�*�G���ךC���W����H�{�g�H���٠R�ʟ��Ҡӡ������`���T�������ԥ��B���9�a�f����������:���ܨ�۬;�R���m�0�����~�U�O�b�.���S�d�����I�2������������7�Լɺ��v�:�� ���5�`��� [...]
+�K����
�>�(����:��x�K�]���}�����h�����2���k���P�n�H����|�S�'�����7�!�Y�����������t�}�a�J�?���I���<�[����K��ڲ������7�/��u�V�X�U�����,�ϧe�D�̥
����?������s�@�!�;�
�
����7��;�%��[�ϭ��2�4�����G���B�S�Ч`���c��/�������{�#�ˣ��z�˧g�٧���B�������w�v����4����ǡ��,�ԛߙɘ��
�[�\���A�˞������N�ޛJ���ڞ͜��
+�����̘
���f�
���E�n�P�ٔ^���ד������U�����ۛ�����A�ѝM�ޟU�`���Ğ/�����ҕ��������ʛ�\�*�}���)�����
�T���H���
�&�5����<��-���|����������u�˗D����E�Κ����0����z�1�����,�g�o��y��������0� �3�
�$�7���}�f�t���M��ÛD�8�u�ޘ������Θ�����G���N�������z�1�f�)�u�W���
�+����������@�ڜc����O����a���Λ��_���֜��x�$�Ȟd�ל
�g�R� [...]
+�X���@�j�/�����|�t�����H��m��
���L�ާ���R����]�Q�P�����֡
�ף�t��������K�Ԛ&�ڕ
+�/���q�����+� ���3�љ����B��7�̛M���D�D����Ȟ�x���-�5�G�<�������f�ӖO���:���X�A�L������љ���.�2������K���m���V���������-������k�`��h����ʜ�(����Ü����q����� �ʜ��U�@���U��5���4�R�*�|���������a�ğ���p�6�X�9���]�r�ʥ��!����G���q��G����ў��?�������-������� �n�p���ܥY�����^�
��ħY��ϥ �0���Σ��7���E������o�Ȣb����� [...]
�@���4�c�(�+�)�_�D��2���
�h�.��w���a����-���5���D�?�O���<�>�c��ʲ�״9�r���ɺ;��v�˹��˷H�ߺ@�������4�����
�<�i���>����������B���I�t�����Q��������c�������/������+���}���}����
�h�
��Ͻ����ľ�V�1���������
��r���n���������9���.������n�\���'���{�����4���
���L���������a��y��
+�������������O�������������3��������������$��^��/�������������������������$��V��y��m��|��E��a�����"�������������'��G�����b��
����z��X��1��C��������$�����������i��������1�����f��+�����������?�����`��Z��~�������������������d�����������e��1�����T��G��A��b����� �������������������������
�� �����=��������I��[��&��d�����9�����
����y��v�����V�����/����� ����{��������������������������r��������������%��'��U��������������������������*�� ��|��*�����v�����������U��D����>��r��5��������= [...]
+��b��L�����
�����)��3��������L��f��{��2������������������n��������=����w��>��X����J��������h��\�����I�����������������/��������������A�����#��������������������#�����������������E��������^����������4�����������J��\�����a�������F��������Z����\��������&��������������������@��k��������l�����
+��3��������n�����������������!�������������������������������T��r�����,�������������������������w��q�����8��e�����Y��
��q����������g��������
�����������������������������������������{�����������������
��v��������&��(����>�����<��
+��������M���������������������@����2��{��������~�����L����y�����������>�����������������4��-��������t��������������������������������������������T��M��G��Z����������=��a��*��#��!�����y��`����������/��������.�������
��w�����������+��]��3��5��m�����a����������������o�����������[��������&����� ����G�����h�����������������8�����
��e��C��D��W��S��U����������Q�����������x������������]��)����������Q��U�����$��W��U��,����P�����1��������������M��������)��_��������p��8��Q��b��� [...]
�������������O�����:��~����������~����Z��~��������Q�������d�����������������������l�����z��q��!�����C�����(�����������}�����
+��x��g��d��&�����x��(�����������V�����������������@��������p��0��m�����s��������H�����B��������l����� ��������-��k��������g�����������|�����6��x��}�����x�����<����^�������������������l��8��������������|��!��c�������������������������&�����=��������u��i�����G��~�����.��'�����Z�����������}��3����8�����k��������������A�����P�������������������������� ��$��������2�������������q��,��x���������������$��B����b��{��������C�����T��X�����J����������������������#�����������`��������M��:��| [...]
�����5��;��k��������u��2��f�����
�������X�����r��^����������"����������'��?�����Y��������M��������^�����4�����(����� ��g�����1��=�����[��z��L�������`��)��D����g��a����������������>�����Y��e��O�������������-��������������d�������;�����������������������%��F��?��#�������Q�������w��w��������@�������c��8�����,�����y�� ��^�����������������G����������"�������������~��J�������������������^�� ����W��a��<��>��1��q��C����G������������A��(��9�����������������4��f��������H���������� [...]
������������8�����������O�������������L��.��D��r����O��������������!����&��1�������-��\��l��M�����Y��������k�������� ����������������d�����������:��k��q�����������@���������������C��Q��l��M��O��"��*��A��������������i�� ��h��L�����t������������������������
��U��������������������������������W�����I�������������������<�����������������q�����>����������~����Z��P����$�����������a��]����������������]��d�����������������P��?��J�������d��e����������������������[��������_� [...]
����������� ��������D��(�������,�������������������������������q���������������4��{����������:�� �������������w��|���������������������v����c����
+�������������� ����������e��G��
�����������#��L��_����������������V��������������������"��J�����P��m��U�����5��
��(�����������3��������}��K��������
��
+�����5���� �����4�����I������������������|����\��������������0��~�����5�����������������M��!��4����������s�����,��������]��������s�����������#�����y��l��Z����7��q��P��'�����������F�����?�����������������������
�����q��d�������`����[��������;�����������G��8��_������������������(�����/��m��>��s������������M�����X��������$��������������^�����x����������P����0�����������;����������� ����K��������d��������������L������D��J��T��a��f�����
��`��q�������
�����������������8��4��� [...]
����������������������������������Q��������?�����C��������������5��D����
�����������*�������N�����
��c�����������:�������������
��$��Z��������G��|��������w��l��Q��b���������������� �������1��������H��
+�����������������������p��#��)��e�������2�����������b��3�����������>��O��������������v��@�����=�������������j�����c��������������������]����������-�����9�����z��b�����~�����a��������������#����������r��
����
+��'��a��p�����������}��Q��S��`��������������������W��S��_��A��3�����������o��������������Y��O�����A��+��Y�����������b�����d�����'�����7�������������������Q��C��I�������J�����M��������������
��
��'�����_��I��M��!��o�����1�����������\����������]��{�������������������^�������������������� �������F�� �����y��[��~�����������r��M��B�������������c�����_��7�����`��m������������^��!�������������������=��
+��,��O��R��\��Q��������������H��U�������������j�����������
�������t�����8�����'��/��������K�������������
��_��}�����"��C��������*��P������������������������� ��T�����F��\��������]��������L�������0��������
+������������@�����������<�����������Vj
j Xj wj Gj Cj .j Jj Bj �j �k �k Vk [k 2l Gm �m �m m Jl k �i di xj 4l �m �n o �n �m �k �i �f (e f 4h _i i �h �h <i
j �j 3l >m �l �k �i h �g i �j l Wl �k �j j j =k �k �k 2j �h �g g cg �i �k �l rl l �l )o �p �p p o 3l �i j �i �i !j Si �h i $i �h �i �j Aj >j �k �k �i �g �f �f 3f e �e Tf f cf ig �g �g �g �g h `h �h bh �h .i j �j ,k �k ]l �k �j �i
h Tf �f h �i �j (k �j �i kh qg �g �i �j �j @j �i �h h Qh �i 0k xk �j �i �h �g �f g -h 'i (j �k "m n n �m �l >j 8i �i +j 2k [...]
p �s qw 'w Fs }l kb �X �V �Y ^ b �d tf �g �i �j Vk Nk Mj 7g �c �a
c Xd he �e ue �d d �c 'd ;d �c �d �f �h �i cj �i �h �g �f �g i 7j Ej �i �j zl �l l �k cj �g �e �e �g
j �k ?m �m �m �l �j �e ;b �a bd �g j !k �j �g �b �a �d �h Ei /h cg �e e �d ke =f �f �f �g }h �h �i k �k �k �l �m n �m �m �m m El k �j kj �i 5h >g �g �i �j ^k -l ?m :m ~l �k �k sk Ak �j �j �j Nl ;n �o p �p �p io �m hl j f �` �_ �b Jf
+h �h �i Tk m 1m Vl �k k ej fj �h �g �g Dh �h �i �j yk �l �l �l �k Ol ~n �o �n �k mi f �c �c �e !g �g �f �e �e �f #g 5g �g h ,h 8h �g �g i �i �j �k Kk �i �h �i �l Co �o _n 5l 1i �e -c �b )c �c �d #d �a �_ �` Kb �c td �d �d ie �e �e �e �e �e e fe #f sf �f �f
h �h hh <h �g g �g i �i |i ?i �i j
i lg �f �f $f f �f �f g |g �g Ih �h �h Wi pj !k Il �l 'm �m �l �i 0h hg �g i Fk ^l �l �l �k jj ai �h $i �i �j �j �j �k �k �l ~m �l �k Nk �j �h h �i �l �n �o �p Pq �q dr Xu �x -y �v �p � [...]
+j �j Qk �k l �k �k 5l l �k 'l
l Pk k �j dk k _j "k �l �m �l �k �j jj �j Uk �k zk 1k [k kl {m �m �m Qn �n �n n �m bm *m �l �l Tm
m �k �j �j �j �k Tl m Jm �m �n o �n _n �m rn �o �p �p -p �n m 8l pk Lk Ul �m Zn Ln �n �n jo �o Jo o ,o >n �k �j �j �k �m �n xn �m m �k �k �k l 4l �k �k Hk �j �i $j �k �l Gm �m Pn �n 6o o �m Gm �l �l ^m �m
m `l �l Om �m }m ?m m m �m ]n �n (n
m �k j �h �h �h �i j Sj oj :j Mj ej �j 9j j �j 'k k 7k �k bl �l Dn �n tn m �l �k i �f �f g �g qh ~ [...]
+e �c �b Vb c >d �e >f &f $f �e �e If �f 1f �e �e .f �f ag Bg �f �f �f g g �g �g �g Xh �h Mi �i oi ci �i �i `j �j �j Xj fj 9j �i �h �h Wi �i j Fj j �i (j �j �j qi �h �h ni
j �j )k \k
+l >l >l ll Ym 'n tn jn n �m Ll Bj �h Oh �i
k l �l Pm ;m �l �l Tl �k )k �j Zj �j jk �k �k xl Vl
l �j �h �f ;f �f �h �j kk 1k �j Xj %j �i i mh Sh �h �h �h �h �h i �h �h �h �h i Ni �i
i �h �h �h i �h �h �h �h �h �h �h �h !i i �h i i %i i
i �i �i Vi i Ui i �h (h �g �g �g h �h �h �h i i "i �h zh �h �h �g �f �f ;g _g ,g �f �f �f �f g �f g �g 4h <h ^h �h �h �h �h �h Ai �i �i �i i �h �g Bg Eg �g �g h �g Eh oh �h �h �h pi ]i �h i �i j j �i �i �i /j j �i |i ;i �i �i �j � [...]
+k �j �j �j Fk kk �k xk �k Ul �k >k "k $l Xm �l +l �l 1l �k Yk Vk �k �k �k l
l &l �k �k �k k �j #j �i
j nj �j ^k �k Zl m �l �l �k -j i �f �d �d Ge �e �f g Ag ,g �f �f �f �f �g ~g sg @g �f �e we ld �c �c �d e �e �e f �e Be ,e We we ue }e �e se �e Ff �f �f �f g �f �f �f �g ig �f 6f �e f of �f Cg h h �g h h Lh |h �h �h �h sh Nh )h �f pf �f �f �f �g �g Hg 7g �f �f �f �f �f �f zf gf �f 8g �g �h Yi �i j �i wh [g �f rg Fi �i �i �i ui �i �i gj k �j �j 2i xg �g =h �g gf �e >f �f ` [...]
+k
+k �k
l 4l l l �k `j �h /h hh �h �h Gh �g �g ;h Ph
h /h @h gh h �g 5h =h �g �g �g 5h �h Ri �i �i Qi �i |i kh �g [h �h 6i
i �h �g 0g 6g �f f �e ke �e �f g ag �g �g og
g 8g �f g gg �g �g 7h 1h �g �f �f �f �f Hf f Yf g 4g g �g �g h �g h
h ^h
h ]h bh h Ph Gh Uh �h i �i �i �i �i
j �j Ok �k �k <k j
i i �i �j Mj nj }j Bj �j k �j k Ek !k Ok �k �k �k �k �k �k �k qk Ok k �j �j �j �j
+k �j oj �j �j �j �j �j �j �j \j �i �i �i �i �i �i %j �i �i �i j Cj �j �j �j �j ck Ck �j Lk �j �j �j tk l �l �l ^l <l �k �k Lk k Lj �i �j �k �k �k 6l �k )k `k #l �l �l �l Xm zn @n n �m @m �l ul �l 4m Mm ;m
m ;m ;m 'm Tm �m jm $m m �l sl �l �l =l ll il zl Ll ;l �k k k �k �l Vl �k mk 9k �j �j j �i �i �i 6i �h �h ci �i �i �i �i Ki i i �h �h �h
i �i Pi �h bh �g �g 9h mh �h �h �h oi ti �i �i �i �h Vh h �g zg h {h �h �h �h 2i ti �i i �h �h Xh �h �h �h �h 7i ~i �i j �i �i �i j 4j �j vj Sj �j |j �i "j 5k �k *k ij �i Rj �j :k �j j �i j xj hj j pj �j nj �j �j fj �j �j Kj �j �j k /k k �k l �k �k Gl -l �k �k Nl �l �l m �m hm ^m �l yl l Xk 2k �j fj ij �j k k mk xk mk �k Tk �k �k �k �k �k ?#�
Y.����y����K�a�����b�m� ��-5�
2%���wI6>��0&����WcgqTu�� ���Vv{��d
p�=��o� �c�M2�R���{�W/rF��6.qX+���,��z���Sd��1NXl
+���������
����+ .`x)�s��hg�C�P|C�]�����������m�d=�>m�rf��ta��P��3;��z/�g � ' f���V
N�$�{��QG.������}_S+�D*m�h{��x�Z�vk�����\e��*�B���]5�Mg�D��O���l���[m~�-��w���: [...]
[5Y��9���qW��4UA-p��n�+a���|�D�1�(�����r�8 ���@<��Tp�)��+'���6A�N�P�w�
��BiS�P�� 4��M���� ���� �� �� �� �� � 1� � R�H�/6��-�$�� ]� �� �� �� /� �� H c ��q��
�� [ � � � � v � � � *N��V8��~���B [...]
��
q��e��M�����M
M,*N� � � q � _��� g � ����Mu �� � � �� � �� �� >� ��
� � S� Q� 7� 7� v� �� �� � �� �� �� Q� �� �� �� �� �� ! ��
�� �� [� �� �� �� �� �� � � , " L 7 Y � 0%?:�lr�{�i��"�����&�#�6m��K<}j?MLu������I[������!�%��A@<����&������/
+KX&��gl��-
��O�?�.�C�{�R� ��G����z�z_�#���������w~w-�X�����CX���T!� � $`� � <����$'�n� i � �u'I9 �� � z��x� � n\<��� s����]\���������+� � � � ���#��������� � v � ��:M|D�*
qj? [...]
+� I� �� )� S� �� �� �� �� �� X� �� �� �� p� �� Q� ~� �� �� �� 6� �� �� �� ]� ~� \� !� 6� k� `� r� 7� r� � T� � �� �� H� ��
� %� �� �� r� 6� E� �� �� [� A� Y� \� �� �� �� I� R� h� �� P� [� �� �� �� �� � � � U \ 5 c 3 � 0� � � � > �� �� �� �� �� �� m� =� � r� �� A �� �� H �� �� �� x� ^� �� D� �� � �� E� �� �� �� [� *� �� � � S� *� � �� �� C� e� &� H� L� 2� P� �� �� �� �� u� �� � �� �� �� � �� 8� � L� � �� �� � � �� � F� � k� b� m� o� Q� s� L� �� E [...]
+� � �� �� _� �� ^� &� �� �� � z� �� �� � �� }� �� �� m� ;� �� K� c� � �� �� p� �� �� �� �� �� 3� �� M� p�
+� N� V� � �� �� �� �� �� �� �� � x� 9� !� J� �� �� �� �� � �� ]� �� o� S� �� �� �� �� �� "� W� �� �� �� !� �� �� �� �� �� �� �� �� P� �� �� V� u� �� �� �� � _� Y� � � -� �
� g� `� G� l� j� 5� �� A� W�
� �� �� � H� �� �� � �� P� #� �� � =� � F� � �� � k� 2� � R�
� c� � �� u� D� � +� O� � H� F� �� �� �� �� �� O� �� �� �� �� ;� v� t� ^� Q� *� Q� � �� �� 7� r� t� v� �� `�
� f� �� �� y� �� �� S� l� � �� �� �� �� L�
� �� � �� �� T� 0� *� J� �� �� � �� y� E� ?� -� 4� v� �� �� �� � �� �� �� �� �� �� �� �� �� �� �� x� �� p� M� �� �� �� �� �� $� �� o� �� �� 0� >� �� �� )� u� ~� w� �� �� �� s� �� �� � �� �� Z� L� �� �� �� �� �� �� �� A� p� L�
� �� �� �� }� 9� j� �� �� �� b� �� �� �� N� d� �� �� �� �� �� �� w� +�
� � i� �� >� M� �� /� f� �� �� [...]
+� Q�c���a� �
�@�p���ǻ���Ի����������i�n�*�2�{�������W�Ļ�����
�Y���m���ӻ/�"�)�����
���!���p���ɻ���}�`������>��\��=�����A���� �r�ûһ�D��,���պ������ƹV�ܺ.�N�S�)��L�ƹ��?�ϸy�����θ3��������������r���e�V� ��A�i�a����Q���;����a�ع��h�z���u�¹ɹ������r���
+�������H�߹��]���6���l����(�2����s�|�d�,�s������j�k���������ӻ��Ż{���ۺ��I������� �l����������<�}�V�m���a�?�X��x���S�,�����
�+��Լ��"��ֻ0�1�]�+�G���r���j������~�����.�_�Q���������g�L�+�@����@�9���
�ø �����|�߹D���*�ع���>� �,�x���]���ȹ��E��
�Y���ĹE������d�q�t�l���c����ȹ��
���\�I�H�%�"���ݸظ�d�g���
�
���ٹf�Ժ��պԺ5��g�̸�ƹ!�Q�����]���Ⱥ�&�����Ի��\���Y��z�/�u�ո���������ȹ������Ź����t�_�x����v�i�K�0�
+���"�Z�� �3�@�G�s���9�ݺ���������Һ���Ժ������;����K���L��������)�m�������t���йi�����^���������V��F����
+�����J��Ӹ�;�Ҹ��v��� �D�u���0�&����i����F���L�k������&��k�s�����̷÷�������w�����,�s�Z�[�(���۶%���3�z�i� �*�ĵ+���`�����a�~�j�T��������m����������{�.�
���������� �2�"�u�t���з��[����w�k�j��^�`�ܶJ����9�������)�q�d�|�u����U�h�g���Ǹ ��
�V�5�����'� �ҹйܹι��`�V�j����4���9�e�=���Ѻ���������m��B�"�ʺ^�}�|�
�w�;�5������G���/�����\���
�����ٺk�4�۹��+�����p�q�^�����y�B�q����W�$����f��(�A�8�·��|�C�l���ŷ����۷�_�z�ɷ$����2�.���a���
���;�ȶ��a��ٴ� ���������2���
�
�4�<�m�˵�ϵ���1�������3��
�����*����7�������R�s�_��ɶ
���ն��Ƕ�\��������%�o�]���$�����C���V���Ƹ��¸��ָL�U�#�4�N�K�]�����������y��N��<�!�6���Һ���H�\��������x���
��7�����m�D����������պ����S�����:�����]�Ѻ����������պ������Y�������<�~�ѻ����7�Y�v�)�R������!����N���6�q��H��� [...]
�}�z���
������`���*�Ѷ�G�(�
����O�W�i�p�i�Ƕ�����g�ʵN������ ����ĵ�����x�y���ȵ�\�K�'�͵
�-�
+�k���P�]�Ŷ����
�
�O���������߷��f��a�z�^�r�V�k�������������շ,�����{���h�4�Z�g�ݸŸ��
�*���J����c���
�>���
�����J�"��۷��]�h�M�����=�ӷ��E�Q�\�
�w�
���j�g�H�W�����������ֶ������q������������ҵ����|�h���ʵ{�D�4��-�5�K�K�$������ɴ
�ٴȴ����~���h�o�F�F�1�>�t�s�6�:�L�l�X���M�_�Գ=����a�U�|�߳����"�:�9���x�s���г
�@�8�8�X�;�'�
���
��ϳ �
�;�����L���ȴ������"���a�P�H�����'��+�Y����$�e�
�������
����������^�B�F���ε�̵����N�t���z�U���ص
�͵ٵյ��ĵ�
�
��+�H�A�E�=�8���z�J��@�p����ŵ�;�������{��ٵ����ʵ������]�����ص�+����ŵ|�
����u�T�����ɴ��Ĵ��j�s�z�f��S�߲X������-������ײ,�y�.���߲Ҳ�ϲ����-�A���ɲزͲ������i�W�7�^�Z�
���������.�!����\�ֳ��9�����~� [...]
+�%�[�������ǵ����ǵ#�;��ص������ֵɵǵƵܵ����εݵĵ~�:��
�������R�����}�M�I�M�
�7�>�5�(����J�+�H�������q�d�������~�P��)�'����Z�U�-����H�4�y�ʱ����_���ر��P�^�_�\�?�����e�w�����K�W�����@�
���
�$�T���
��ʱ� �ޱ���������ıݱ�����;����������������+���ٱ����w�ʱ�ñ��{�����±��E�S�5������K�/�����+�1�5�H�V��
����T�F�ر���-�
�)�������C�+�W�p�z�^�& �
�
+
%
�
G
�
c
� P!�!a!� y � a x !
%!>"Y"�"�"!k I
y
t
�
�
�
#~�
�!
#�"�!�^
�v
�
�C!
!�
�
!�!�!� �
z
+
S
|l�
�� 0!�!�"�#F#�!v ��
�
o�*
�
�G!�!�!�"z"!n]
n
�5/��V)
D
�
�
T
1
�
>
�Q [ � X!9!� " �
!
Z
J�0
,
E
z
C
o
g
b{ � D ��
t
>
�
�D �B
4
�
�
�
]* F!f"$#�"]"Y"�<
D
�
�
�1 �h��
G
�
� �!`"
"!!4!� ��L O t$
�
�
�
�
�
�
SR
�
�Q�� g � � i!"�" [...]
�
7 p"�#y$�$�$g#z!�!#�#�#|#�!�
Y����
�T�
.
���w
=
�
w
\����:)
�
^
[
��
�
a � � ��i
�
�*�v�c
� h �
X
�
,
=
S
�
u a#U$w#� �
&E�|X
�
W
�
] H!
"�"j"�
g[!��
P����s��!
�
k
1
�
�
{��
�
o
�
�
/ �Q _ ���`
�
+
� �#�$<%>#�a
������g�
�n
�
i
�
�
�
�
�
�
�
*
?
*
(p�2 !i!� �
+!. � B ��
�
nG�*!�!A""##�"K"�!
�� �!"�"�!� �Z) ] �
b
K
e
�
�� "�#y$\#�#�"5 8
H
\�.
�
C
�
�
&�
�
�
�
�� I 3�
o
A
�
(
u
-
\
������
�
�
W
�
D
�
�
h�V�
�
$!� �$"
�
����=
��(�|}�}��u
�
�
c
T
�
�
�
����
�
�
�
<
�
$
+
�6
�
{
�
|
����{
�
��!�!g"�"D!N
C
a��h
Y
�
�
C
8
�
r
�
�
"
B
�
��i��
�� $!� � T!�!�!�"$N$##i <
�
.
�
E�� �!_!� !�
!
!,!2!U!�
�
�
�
J � � � � �!8"Y"�!� J �
�
;v��q!#�#�#�#�"�
�
�
�
�
�
+ � _ |�
�
�
�
�
"|
a
6
�
B
�
m
�
�
2
�
����>
�
rH�
]
�
1
�
�
Q
�
t���
S
B
�
�
�
`�
Y
^k��
>
K
D
�
� [j
�
�
�
�
=
@
3
g
�
N
�
�
v
r
)
�����
+Y�
�
2
�
�
�� � ? !
qQ(/Z�{
�
�
u
�
Y/ ���
�
P�
6
�
�
�
*
X
�S x�-2
5
p
�
H
3
9
�
W� 6 �z c��# � � )6�
�
��� �!�!�!� �y�0 f � � � !� � � t � _ � � !N!+!� t 9 �
�
�
a ��
�
B
<
�
�
�
8�
�
�� R �# � �\np����
��s T 4 c B � F!�!$!# �
���P
�
�
�
�
� [...]
�
�
0
�
@
��
�
m
�
�
�
{
G
V
�
Z
P
�
�
�
�
�
�
M
�
�
�
�
�
�
�
t
�
�
�
f
V
�
�
�
S
s
9
Y
i
�
�
�
0
c
[
a
0��
�
�
'
7x�
�
�
�
Q
�
�
I
��V��9��� �������)�4D$�e�R`:�:\���
�N�N����;�G4z������_MPB2^t����
A�5�����a�:�� [...]
�f72�Y�`}q��xI��_
U�
�Z��"��t�3
c
'
(
�
$
�
�
U
�
U
�
j
�
�
�
�
�
�
Xl 8 �1�
�
�
~
�
�
�
�
'
�
�
t
F
0
�
�
A
S
�
�
�
B
�
�
�
�
U
+
c
�
�
�
�
Z
�
�
���p
J
6
�e�j�
��Q
�z���&����I��z�
�)��a�
+0��E�8-QU�[�:���^��
+����{�/J@��\o� �`�I�v|
���L
a
�
�
�T<��mV(
I
������v�
���D
�
�
�
�
�
�
�:�I�����
��h\�F�a
���;
;
2
��|
I
�
�
�
�
d
�
/
�
t
*
�
�
{
�
�
�
H
a
�
�
:
m
�
+
�
z
Du
�
�
t
$
e
p
�
�
�
�
�
�
"
�
�
�
@
�
�
v
�
�
�
>
�
k
p
�
�
�
�
�
5
�
.
/
��o�36�Ql�~��Vh
�_e�_(n�Gc���J8�76��i�l�
]�k�+#��{�W���T��F�=r�
� ��^�q�����a
)�,��d�v���
T��`Y>-�0���K�Y���x� [...]
�������������_���L���c�������@�������b�X�#� ���y�������.�K�T�
�����
+� ����g���}���������r�������2�(���_�t�������r�f�v����U�����������\�l���T����p���������y�������f�0���i���X�����I�s��������������`�
���A���c���#�G���������^���O���[�����9�����9���k�*���|�+�#���K������������,��������l����9�����X�d�J�����d�l���&�J�k�����.�����������6���_��������T�������������A�����S���1���@������~� [...]
+�����n�5���/�C�����{�1�c�������E����������k�����4�����v�J�����W�c�D����n� �{� ���D��� �����K���2�������B�N���/����i�G�������Q���4��?�����
���L�~�������
�
��
����%���u�
�����m�b��������1�2��b��~�����J���k�^�[�
���!�)���}���-�����D��B��+���a�����,�^�+�������$������u�
���(���������k���"�
�|�4��e���~�������6�����9���\�<�����H���-�
�������1���>�
��r�=�B�
�,���������O�����
+�M�t�����������s�H�Q�`��d�����4���\�^�F�{�g�)�u�}�#���7�����,�������)��`���a�j�#�z���,�����s� ���-����9���E�r�X���6�.�T���\������������� ���������[�2�?� ����� �����n�����^��N�a�~�-������T���������o��3�����+���2���z��d�
��o���}���O���z���)�O���������������W�����j������>�#�
�e���������{�����5�y����]�����x�8���Q��� [...]
�������L�F�����#�������z� �O���@���8�C�������3������w���9���;���w���������D��T����r�����f����������
������v���w�,����d���{���1����r�3���V�������(���D�����������o��������:�����&�=�6��{�����b�
�,�����������������E��o������������)���p���S�d������1���b����~�t�Q����
�'��������U�+�)�A�s�0�K�����m����&�<�����}�=������� [...]
�
�>�^���������^�������X�
��� �\����|�����x� ���6����������� �����Q�����q�����t�����\���-���������e����u�m�������A���i�
�����p�����������y�X�B�������������J�������.�����������T���������!���������&�9�����0�������=���D����������=�����:���d����������� � �^�����������^�n�����g������������*������������������ ���j�����`�o� [...]
���~�����
���������L�d����G���������������������������h����&�d�b�"�%�V�������%�j�U�@�<�����6��l�����Q�G�������2�Q���d���&�����B���B�����;�������i����������������Z�C���������F���2����O������������9�#�O�a���g�����y�\�'�L�������
�;��v�o�������:�?����� �����O���
���;�Z�p�x���t�e���&�3�o�R�(��-���T���r���L����%���O�8� [...]
+�R�����;����R��2���P�C�������7���{���r�����l�{�X��)���G�$�)�e�_����������i���������
+���M�i�����y�����G��������;�������Q�����^� �j�A�s�T�w� ���h�C����������� ��������������� � �����D�?�����j�G�w���������������������������/�����O�������������n�1���������������P�����6�%���A������ �'����
�p������������(�I����t�R���
�_���������������
��������4���K��S�@���k�t�$��������
���}�����{��g�����r�����P���-�8�= [...]
�����
�
�������������#�@�v���������a�������W��������G��F���K���}�����r��������j��������l�������9���Z�p�C�S������������T�����������������
�e�R�����h�"���Q�M�����=���H�������q�h�b������B�u���:�J�7���M�c�&�6��)����s�����3���W�{�
���2�����=�w���g�����A�����:����������n�C���&���������'���������������*�����������Q�$���m�6���h��� [...]
+�������-����
�~�����;�[���#���-���q�����}���p����
+���3���/����I��:�������i�-�V�������^������������
�J�������V�(�������l�
�a���H�������O����w���������m�G�����5���1�����x�]������%������S�=��/� �/�l�����
����Y���:���`����������O�g�����������
��������3�+��������5���q��Z��������v� �������A�������������
���\���J�5���
���
���������e���F����Z�V�E�T�
����������
���-�������=�D�S�Z�J�5�x�������1��������
�������������������
�����h����� �������T��f����^���g�%���[�������;�E���U�,�����{�����[���<��u����}�����h�(�(���~�E��7���W��� �������E���������������
�.�D�W�(�����j�����6�����X���@�
�������v�[���'���c�9������w�����������-���4�t�g�j���������<���A�b�������������e�-����h���g���F�~�
�_�,���4���c�(�
�u�j����X�4�����K�N�
+����#�����e�l���D�����z�i�����������W�����������������y�M�D���0���4���x��8�������U�a�����\�����"���l�.����������[�g�^�o��2���
����O���-���+�'�o������B�)�/������H��
+�>������[�W�7�6�q��������C�����������O���+�}�=���q�w���9���J�E�<���4�����������������8�g�������[�G���y�����w�����������a���K������<�E���������X���������Y� ����f���
+��Q�Y�����������e�!�!�3�������������V�%���$�u���s�L�$�����o�>�
�,�m���������f���s�T���,�[�4�a������B�����E�I���2�����o������K�E�������n���3���&�K���g���x��e���G��v���j���"��� �S���b���#���\�'���F�`��������>���b���
�~�����t�8�����C�}�����������������������2�����#����v���M�����B�>���%���v�a���v���u�M�d���!�������#�+�� [...]
��`������������� ���������H���8���"������&�t��������p�!�
���$�g���x���`��J���~�-������P� ���=�D���a�/������������e���$���~�%�?�����|�i����������������5�����z���V�C���t�������� �������H�����t�T�����{�[�����������~�@���������
�����8�<�T���
�1���V��� ��������������B�,�������i�����:�
���8������i���3�����*�k��Z���*�Y�"���>��e���E���������M�������M��.�����F��������������7������ ���<��h�U���~�3�l�e�����
�}�W���v�����m��� �������J���������)���'���3�����2���
�"�O�����B�Z�����;�+�R�����7���������1���<���X�����&�
�����������`�f�����C�����)������%��P����������~�����|�����>�h���i�H�~�Y�����<�����H�����[���������\�i�y��������������������[�������f������a�r�`������D� ���k���3�#������������B�����R���~�e���x��?�=���`�B�Z���������:�����J����u�p�x��� �����F���������8�� ������� [...]
����}���E������T�������^�2��� ���������������j�������������������P���������3� �B���������������r�c��b�/���,�b�J���������F���
�������U�Z�j�1�v����j�����J���������]���B�����%�a�����d��[������[��B���n�����9���#���������
���_�B�%�c���l�l�x������w������"�����d�8�������
�N���:���z�c������[���_���U��������q�/�o����������������V��������F�����0�'���w��������j�������a�m�I�h�Y�%�������;�a����{�N����%��)�N���=�,�<�`�}�T���|���L�&�
����������P�W�<����������9�i���������6��_�������
+���x����}�\���~�W�����s������.�4�d���R�����������\���V�6�������e����������z�����J���������=�
�B��������:�������0����F���s�J����9���2����� �R���������E�!���B�
+����{�K�4�I��m�(������������,������K�R���y�|������0�m���Z�����z�2�M����Y� �������Z���5����������<��W���
������5���Z���v����}���5�l��������������5�����B�@�����}����^��b����;�/�r��D���c�����
�������P���9��������/������ �1��������3�Q�
��������Y�y�������������H�������-����E�k�N��C�w�]�x�s���C�\���(�W�}�=��������N�h�`�����E�e�m�c��� �����������]�����a�4���:����"�l�����\���Y�����7�����3���^�&����b���\�
���e�
�
������������������p�������8���i���]���P�3�A�%�I�A�H�����������6���H�k�N�^�$���������i���v�����B���� [...]
+�i�|�����_�����a���������u���O�6�}�F���������K�n�B�O�~����f���=�"�
�L�Y�|�&��� �\�Y������������� ��������2�F�F�9�Q�"�,�������������:��x��� �� �� �� �� � �� �� T� I�
� �� ��
� #� �� �� �� � �� �� �� �� 1� �� �� �� �� �� �� �� �� 5� �� � �� �� �� "� �� \� �� �� $� ��
� O� \� �� �� �� y� �� �� -� �� �� �� d� �� � �� �� �� �� �� �� �� �� l� �� �� �� �� � � �� k� �� &� $� �� A� �� ;�
� "� � �� �� �� �� � �� �� y� X� `� e� �� �� V� � _� n� 7� �� �� \� C� m� �� J� �� �� � � 6� 3� w� 9� �� =� �� L� �� �� 5� �� ,� "� � � s�
� ?� 1� g� R� �� }� �� �� h� � � �� �� E� d� z� �� �� �� 8� �� �� o� _� B� � �� �� �� B� 6� �� r� ��
� �� �� �� h� Z� � r� p� .� �� �� �� �� ?� [� z� �� �� ]� v� �� �� Y� d� \� � � � � j� �� t� �� :� � �� � #� *� �� >� �� �� ?� �� �� "� � �� ^� ?� �� ~� u� &� 1� �� �� � �� �� q� �� �� �� c� �� �� � "� _� �� � '� � �� W� �� �� �� [...]
� �� �� �� �� �� �� ��
� u� �� �� �� /� �� �� [� �� )� � F� �� �� ��
� �� �� �� B� �� ]� j� �� =� G� �� ]� ,�
� #� �� ;� �� P� �� z� �� � � L� e� �� �� �� � � �� V� R� a� �� L� � �� ?� %� � B� /� 8� �� �� �� �� O� B� z� �� � 3� � �� � ��
�
� �� �� �� �� �� �� ~� (� �� '� �
� Q� +� c� 2� g� �� � � �� � �� \� �� �� �� �� �� �� � �� +� �� �� �� +� �� j� �� � �� �� D� �� �� �� �� &� � �� �� �� �� �� g� �� a� Z� � �� �� M� �� �� a� �� �� �� �� o� � ^� � �� �� �� �� �� [...]
+� �� �� �� �� �� �� o� $� � � �� 0� a� ]� �� e� �� n� �� )� �� �� �� /� H� M� �� �� -� :� �� � �� �� �� k� �� "� � 9� /� � �� ~� �� �� +� �� � �� %� �� {� �� �� F� F� �� �� K� �� 3� �� � �� �� � ,� �� �� 9� �� �� � �� �� � �� `� �� l� �� �� e� �� d� W� �� �� 1� �� �� �� V�
� �� �� 5� �� �� l� �� d� �� �� K� u� E� �� �� �� C� �� � �� �� �� �� �� f� �� �� �� � �� G� �� �� � �� �� �� � �� �� �� �� �� �� �� � �� _� �� 3� {� �� �� � � �� H� �� �� ��
� �� R� [� �� 1� �� �� $ [...]
� G� X� g� �� T� .� Y� S� �� �� � �� X� �� 1� �� 9�
� �� �� � <� `� e� �� �� r� �� |� �� � +� b� �� ]� �� #� � U� m� �� �� �� �� �� B�
� �� #� � *� \� �� !� �� m� W� ��
� �� 5� 7� ?� �� �� �� K� H� � � L� g� � �� +� �� �� �� �� b� �� � m� � �� �� '� D� �� �� �� �� #� �� r� �� �� �� J� }� %� b� � }� �� �� ]� }� %� F� �� �� �� F� m� �� �� �� p� �� �� � ;� � �� �� �� ��
� W� �� � +� �� @� � n� 7� �� ,� �� �� �� �� o� �� E� k� �� p� �� �� "� @� <� �� S� d� Y� 3� �� �� e� �� [...]
� �� �� � � ]� �� n� �� p� �� � �� i� �� �� �� �� �� � � r� �� e� � Q� �� �� � ��
� � �� �� �� �� �� |� e� �� �� � p� �� .� �� <� �� E� � �� �� y� ^� �� �
� �� ;� 6� �� �� )� -� �� �� 7� ^� � �� Y� �� Y� �� �� �� D� s� O� �� �� X� c� U� $� [� {� `� ~� j� h� �� >� @� 7� C� I� �� �� �� �� �� �� �� �� �� �� �� �� �� R� f� �� �� � �� �� P� P� f� � �� j� ]� �� �� �� G� � �� �� � � � R� !� �� 2�
+� �� �� /� 5�
� �� ��
� /� u� '� ��
� �� �� j� �� � T�
� � V� �� �� *� �� �� �� �� � t� #� �� �� �� B� �� �� 2� � �� � ��
� � �� �� �� �� �� �� �� � �� :� �� �� �� k� n� _� {� 3� � (� 7� � �� i� �� ?� �� �� �� �� `� ��
� *� `� �� �� �� � 7� �� �� �� � �� �� �� �� �� X� � �� �� b� �� ,� �� �� �� �� � f� c� �� �� �� /� D� � �� �� P� n� � ;� �� �� ;� � s� �� �� � @� � �� R� C� =� \� �� �� J� j� S� �� �� � h� � �� 4� �� 7� U� �� �� �� 8� ��
� =� /� 2� � J� �� �� { [...]
�������T�w � ^ r | ������x�@��� " ��p���?�����l�~���[�����7 � � �
�)�0�������j�������h���������
� � t . d � \�� $
e������� ��� 5 ���� ����P��l��� � ����p-$.L#G{�,i� � ' ���� � J
��
������
� 8� ����� � ����� k� ������� ����z�Gy}� ��H���1�����E�m��������
�Q�b�c�
�F�
+ ����
�j���*�\���y���3���������/�6�)���
� ��P���m���m���{�C�Q�Q���R�5�(�����������t�
�������L�f�*�6���G�����t���^������D�
+��� ���2�H���!;� M k x
7�����e�7�����$�o � ������ * ����2���Q�$�D��� Z ����<������������%�����U �W��0�s�; S����<����F�������o����� ��������- � � � 6 E ����
�������� �������������
���'���� � � � ,�Z��������m������a� S � ,� � � �����e� �������$�t ��Rb +���v�U���/ � �����
+ �K� � ����1;R��:���5�N��� b V r ~ z ; ��a�?���p�G ' J E ��M��X���b������ �� y�������������������9�}�
�F������5�T���#�{�o � )bF-��w���I�0���j M % �������Z�M�g�?�7�q���O�
��&�g�����&�@�n�������f�E�����3�d��@ � � H�;�H�"���������� ��������.���s��������)�C�6�7�$�"��{�p ��(�:
+�� I���L�w�������=������� � � � �������������2Zav��� ���� � Y�� { ����@�5��;�1�����o���������@ � � a �������������s���&�+���;���O�2��D�[�7���4���%���������-�
�7���c�f�������o���>�g�o������&�X�+���9���� � t ��������G����������
�Q���@� �*�����%�U���>�����������h�������5���������*�H���������������� � -p�2 ~ [...]
�)���[�"�"�E���������S������|�p�t�������s�E�������
+�]���K���M�)�}�������W�i�K���f���h�������������{���
�4���1���J���v�T���d�.�z������f�����������������;�x�_�
����������4�0�E�F����������������/��������������J����~�������
�e���������Y�$����9�G�����h�
�������@�p�~���������3�:�#�G������������%����������!���������u�����������P�C�W�o���R�����V � �u� >�[�������t�u�
[...]
�k��������������'�����v�����������
���>�E�[�B�i�i�E��i�������,�������4�L�������I��������2���%�K�V�m�
���M�#�����m���
� �?��Y�A�y��������������R�������_�������B�����������������I�x�q�u�M�{�>�����#���
+���������[���o�d�2�%� ���*�J�u���z�A�'�r�S���������s�"���������������������) � KI�z� ����=���B������u�>���( , ��`�����t���<�?����� ������^�P�����+� ���W�
���5��� �!�N�_���������9�n�P��������"�����h�@���u��� �N�i�����g���������a���B��r�O�Z�����$�;��p�����n�m�"���B�}������H�M���v�8�B�C�s�l�����t��b���������V�
+���q���+�F���r���������K�s�����D����L��
�������R�����(�C�����
�����������������j������N�z�0�-�7�������p������A�����)������1�4�����������R�:���#�����^��K�b�����!���������y����������r����.�������������������#�����k���+�
�N�|�+�3�F�����g���7���u����y�N�)�����������g������`�z�L�p��,�����:���x����A�Y�����]�M�h�(�' [...]
�������������������������/�=�����e���j�x�������<�F�������������[�����;�������������G�����.������������ �B�����4�^���������^�
+�O���)�����O�������������e�-�d���!�E���W����������Q������K���8����[�������������
�
�\�x�Q������]����������������s�����������6�k���������?���x�2�^�8��������%�S����f������
�����!���&���h���e�?�����A���������2�q���-�Q����#�g�l�!�����!�P�b���������������N�D�
�"�����-�V�����4�����,�����3���S�l���3�����������Y���"�i��V�T����
�D�_�e�
���H���:������v�l�}� ��&�e�����ʀ��F�d��D�������������,���ف������0�������E�W������ہ.���F�@�n����u�>� �[�E����v�������y�~E�{���L�����d��\��� [...]
+~�}�}k~�~(~z~�~%�~�~�~��9~�}�|�|r}�}�}�}�~p~~T~l~�}x}�|||g|�|2}U}}�|�|�|�|�| }q}�}�~�~�~�~w~!~�},}=}`}�}P~E~�}�}�~�~�}m}z}�}~�~��5�9���~�}�}�~�~CS�~�} }�|�|�}i~�~�~�}�|"|i|�|)}�}�}G}�}~~Q~�}�}�}�}~H~ ~�}}�|�|4}�}�~���~|~G~~D~�}�|�|�|�|�|c}A~�~�~�}r}}�|C}}�|�|�}W�H���}�{e{!|�|�|�|�|�|<|�|�}9~�~�}� [...]
�WU~�}�|}g}�}=~V~w~W~�}�}�}�}�}~~�}_}5}�|}%}
}�}~p~�~�~�}�|r}�}i}�}�}�}�}O}�|T|@|Z|�|�|�|
}q|
|&|
||�|�|�|�||A|�{{�z�z�{Q|�|�|�|�{�{�{�{�{;|@|�{{/{�{�{�|a}�}r}}�|�{�{�{{�{�{�{�{�{b|�|�|!|�{i{b{�{�{|�|�|�|Z||�{�{m{V{u{i{e{n{�{�{Q{z{�{/{R{�{�{�{�{.|2|�|�|�|c}�|
|�{<|3|-|q{={C{{�z�zL{�{�{�{�{�{|�|Z}h}}�|�{�{&|j|�|�| }�|�|�|2}�}L~�}�}�}r}:}}.}�|^|�|�|�|V}�}i}o}�}T}
}W}�}�}
~D~
~�}�}b}�|
}�|2}�}�}�~"
~b}�|�|�|
}�}�}�}�}�}~3~i~^~N~C~�}U}}}
}&}$}�|2|b|�|v}t}v}<}!}6}�|�|r|m|�|�|�|�|#}�|�|�}~}:}�|�|�|�|�|�|K|�|*}\}6}I}�}�}�}�}c}M}Z}z}�}~_}�|�|�{{�zM{�{�{�{�{�{M{X{�{�{�{�{$|�{�{D|M||||�{�{�{�{{�z�z�z�z�{�{a{t{�zTz�z�z.{�{k{�z�z�z�z�z{�{�{�{�{�|z|�{{`y%x9xEx�xCyDy�yuz�z�z�z#z�yZyny�y�yDyy<y�y [...]
+}�|}/}e}�}}�|p}d}�|�| |�{1|N|i|�|!}5}�|}>}�|�|�|�|�|�}�}�}�}�}j}4}+}�|�|�|a}�}�}Y}o}�}�}�}m}J}�|�|�|�|�|�|�|�|*}�}
~�}}�|�|�|�|�|3|�{�{�{�{�{�{�{�{�{�{�{�{�{�{�{6|�{Z{{F{�{�{�{:{0{B{B{o{�{�{�{�{�{�{�{�{m{�z�z�z.{�{T{3{.{�z�z
{/{g{:{K{�z�z�z
{{�z{.{m{�{�{�{D{{�z�z�z�z {{{�{�{�{�{{Q{t{{[{�{�{�{g{G{K{�{t{9{{�z�zZ{Z{W{� [...]
+xxkx�xwx�w�w�w
x�xOx�w�wx
x�w�w�w�w�w�w�w�w�w�w�wowZwrw�w�w'x-x�w�w0xDxx x(x|xix�wXwwEww�v�v�v�v�v�vkv�v�v�v�vww�w�w�w4w�v�vw��d�a�~�d�O�^�h�W�]�~�ʬŬ��s�����������[�i���Z�|�n�i�b�����I��������
���;�y���\�x�t��q�������٫,�z�^��ԫ�@�F�����L�
��r�������ɫȫҫ�����ܫ�����`�
+�˪����B�S����C�)����p�I�����������˪�d�H���O���}�M���D�ȫ������«��g�U�L�̪j���-�S�h�b�p�������ޫث٫ҫ8�)������<�/�����}�l�
�
���ȫ������)�3��ҫիҫ����ʫ�R�]���ԫЫ}�f��u��ɬ[�c�w�7��)�5�o�=�ӫ��ʫ�����6�@���� ���Ь������q�Z���~���լ���� � �Ԭ�
�ͬ��I��.���ЬƬ��լ]���ҫp�C�k���������ث��ܫʫ|�������{�9�d����ͪ����p�r�T�������� [...]
�O�>�i�f�G�����۪Ū\���L���l�ѩ
�
+�.�T�������Ū��ڪڪ2�l�:�@�_�V�?�����E���D�a�a�M�x���������b�B����
+��f���a���)�J�N�4�S�~�۪�
��������c�U���ݪ���Ъ���Ȫ��������*�S��$�I�
����� ��5�;�ت�f�*�,�W��0�%���c�
�����թ+�m���c�=���t�P�
��������������q�
+�:���ܩ$�
�����r�L�3�����B��ק�j�ʨ
������]�P�j�x�t���ۨu�����#�
�ڦ}�,�������8�]�����s���M�{�Φ���������ϧ�ȧħƧ#�������֨D�+�������o�h�R�S�������ШӨ������������7�H���e�(�Ϩ��*���(�w���a�K�]���ިè��֨���Ǩ��Ѩ�Ѩ���(�2�>���j���ҩũ����©~�s���Ʃ��������0��éɩ%�v�P�t�����\�
�����f�������ݩѩ֩ͩ��������ߩ��L�R�~�٪�7��1����9�'���)� [...]
�
�P���5��W���������R��}�f�%�<�����-�i����̦t�T�[�g���������������Ц����{�˦��:�"�D�ئŦ �1�,���-�I�L�j�S�R�7���6���ȧ٧���\��&������ʧƧ���R�����m����������������������������Ψ�p�������l����
�@�w�|�ة�����ݨG������
�!���ީ�����۩ϩ�����J��6�٩�̩��
��ة���E�T�\�����}������ԩ"�
�
� �H�1���I�`�t�4�9���թ��_�A������� [...]
�ۦ¦ڦ����������F�C�F�����]��.�J�k�Z�t�����
�Y�%�2�.�4�6��Ʀ��!����=�i���������E�<�>����զ{�����֦�����>����������ϧ����٧֧
�"����ɨ��������f�s�������C���֨ȨǨ�ڨ��m���������3�(�S�k�����ĩϩ����������-��������e�©��ͩ��e�%�A�����|�v�x�q�\�����;�3����ʨƨ�W������ʨި��֨֨��;��ڨ��u�٨�������Ĩ����è��6�.�����<�d�L�[�m�F�� [...]
+�
������E�d�8�p�}�J����ߦ��u��K��Ǧ_���z�T�%�!��
����ĥ������(�������������.������ɤܤΤ�����������������7���7��� ���ʣ{�ϣȣģ�ãh�����ܣ��������������#�k�L�2�����������s�w�p�P�L�e�`�u���������p�V�e�T�L�Y���������ȣ���0���1�[�����������¤c�]���Ǥ�Ǥ��Ѥ����^���������������B��K�������y���������{�c���Ĥ���̤����y�¤� [...]
����|���������ߣѣx�w��E����l����ʣ���ڣ�����(�գc���ۣ � �֣��j�ƣƣ���ʣ���B�\�����������f�i�V�
�2�X��������ԢբĢ��
+��B�<�1��,�~�����_�+���֢�����������F��̢�������
�������ܢ��������� �Ԣ¢ܢѢ�5���٢��z���U�:�_�r���
� �
���b���������ݣt�l��1�@�T�����
��
���ʣ������X����������ģ��������,�;�W�2�I�r�j�b�B�K�G�h�\�S�2���G���������o�2�.�g�ɣ��ģ��A�J�X�?����E� �����������ޢ��ʢ���ˢޢϢܢ���������Ƣt����ߢ������������������y���~�K�0��>�������X�,�9�*�;�f�]�P���l�y������/�P�^�I�:�[�-��,�"�Q�v�s�����g�%�.�;�5�.�=�`�����������â��������z�e�������٢ۢ��|���ݢѢ��D�b�����$���������Ѣˢ��Т����� [...]
+�ƣ��������ãģϣ����������R���z�f�/�R���7���<��Т��
+�����Ȣ����Ң����I�c�=���h�H�'��ǡ����١���� �����~�]�G�'��T�C���;���o�D�c�u�-�*�����H�q�_�q�%�I�¡��,�H�m�.�
�E�������^�t���������<�%�
� ��;���N�K�W�g���;�B�X�������۠���Ԡ����ʠˠ~�q�����������������o�K��������ޠ�?�C�5�O�9�ՠ ��b�W�f��
�0�k�w�������à�����������y�P�0�/�,���ɪ۪����G�S�G���!���Ǫ����ª��?�"�����~� [...]
�(�k�|���{�~�8���3�B�����ʩ�Y��������.�)�'�����X�b�7�P�,��٩�8�*�ة�i�8��ܩΩ
�.��"�0���)���/��D�G�:�s�^���
���˩1�B�
�����)�M��ԩ
�N�
�����
�8�!��������7�|�t�
�����~���{�e�.��O���P���A���êb��<�����i�R�O�>�
�Q���Ȫm�)�V���e�O�G�h����������T�y�3�R�|�'��
�ȩ©��Щ���(��
�0�0������ɩ�����ȩ�� ���9�����P�'�:�X�{�����k�_�f�h�J�R�_�H���Ǩ��ըA��%�#�������8�D������Ĩ����/�:�@���
����ި��٨è��/���������Ψݨ
+�� ���Ԩ������Ψ������ڨ����"�w�x���N�D�Q�!�h���x�������b�m�c��2�(����$��ߨ��4�;�i�>������ �����ܨ@�H�������!�Ԩ��9�O�z�n�<�k���j�.��
+�G���n�J�1�?����H�b�e�[�\�����_���������g���W�b�[�(���M�5�H�W�C�/� ����������ڨ
�4�9�ި��������`���Ǩ��������?��K�w�z���������M���ڧ=�E��ۧ��Ƨ��ʧ�a�J��������ç����i���Ч�է�����ڦ'�*�%�*�4�Q�g�����[���k�)��?�Q�{�����S�X�9�B�8�[���~���ҧ��6��
��D���V�f�[��}�r�n�z���ħ��^�y�[�Q�}�����u���r�m�q���/�N���]�3�;�����ۧ����ʧ����ȧ����X�^�������z�~�{�������������ԧԧ������ҧ�������
�%���ݧX�e�7�+�D�3����˧����`�e��� [...]
+��3�0��
�������A�*�h�f�"�
�3��ӥ��?���v�-�����'���U�*�;�G�V�]�w�c�����Q�����[�R�������Ʀ��ڦ��ʦ��0�k���a��������-��=�6�=��
���������
��ڦ
+�^�E�
�8��˧�����}���Q�"�S�9�9�o�n�X�>�������V�~�m�u�������ɧ��u���d�(�C�u����������"��z������q���7�Z���������v�K���ħ������P�9�V�����t�l�����3�Φʦ��Ȧ'�8������Ħ˦��ϦӦ����������Φئ�Ȧ����Q�m����R�����o�C�9�q���y�Y�Z�O�I�A�&������F��� ���T�h��!�0����˥ߥ٥��ե�N�/�ݥͥ��z�q���̥��Υ��>�l���i�i���z�������,�Y�p�|�¥�ڥ�������� [...]
����������������t�����æ�����Ԧ����h�-� �0���v�{���v�����}�z����r�G�/�4�?�d�J�m�M��إ��ɥ����������\���}�n�Y�������u�J�Z�����˥��
+��
���`�6�
���M�9��W�1��ޤˤ�_�]�
�O�a�S�k�x�����`�(��%�>�E�K���,�!����ڤ� �
�(����¤ѤФ�����������ۤ����Ϥ����٤������Ф٤����������ڤ�����2����%���8�\���W��Ф �A�k�T�G���|�s���ť^�x�����������I�.�5�Z�m�P�l�������~�l�t�l���������Х������������{�i�~�����x�W�h�U�-�
��R�H��7�&�6��ʤ������F�>����������ʤu�n�c�o�g�m�S�A�O�"��8�F�4�?�?�E�+�����ɣ����������ͣ��������x�}���ݣ�p�����£ޣ��t��������������Σ��l� [...]
������x�;��ܣ�����ͣ����ݣ�������������s���ɣ��������������������ܣ�'�٣��������p�����F��D�n�P���(�P�/�F�h�����f���'�;�o�D�*�T�k���ȣ��c���������w�U�
+�(�����������`�=�2�x���f�i�o�Z�_�I�����[�>�q��ˢ�����Т!��ޢ� �6�
�
�����'�ʢ����Ţ�ݢ<�V�o�D�ڢ��Ģ����2���[����ˢ���.�=�
�Ң���Т��
�����ɢ-�Z����9���_�<�ݢ��֢�L�����.�U�����0�h�������7�4���$�(�����Ԣ�բ�������עߢТѢ��p�y���!�����ݢ� ��������֢�����,�ɢ�2�#�
����
��բ
�8��������ߢ���آѢ��������|�������ʢ�������
�������Ǣ��'����}�o�p�x�`�Y���l�{�����������X�a���������n�������5�)�M�R�o���͢��k�E�P�c������������J�*� �9�r���o�����������������[�Y�j�b�f�����r���C��O�J�"��������^����-�6��$�]�F�5�
�%�@�������,�$�ҡ�+�����ס��$�E�Y�r�]�1�0�'�#���%��I�����������������Ģܢ���������3�?����������������������
�
�¢��x�ˢ����������������ʢ [...]
+���ݡ���$���!�D��������ɡ��j���������������{�����������`�$�N�x�x���ġ\�E�h�����s�r�S�����šΡ������������}�����s�U�T�Q��N�M�����%�$�T�k�C�ܠ�/�S�4�)�ՠ��Ơؠ
�U�>�� �'�$�����נ����
+��������+���͠�Ԡ��ˠ��e�����q�;�c�j���Ġ����à��n�
�+������������M��{���Ȁ܀ۀ�
�ʀ��ˀ}�R�5��������Ā����Հ��?�Q�C�4���x���'�C�a���߀0����<�����X�v���������m���f�&�����@�*�{���>�B�#��_������������f�����2��(�l�y���߀�R�U�"�ˀ������{�,����T�K���n�Āր������������ƀ����ƀÀ��[�;�����g���?�������ˀ����&���k���� [...]
��
�9�s���X�"���9�!���]�a���@�2�V�
��c�r���/��^�K���
��
+���X���H�3�c�������:���i�`� �<���n����]���������q��������;�c��i���������������3�'���Hh�*��A�N���l�������{kx�}��������
��
�.��������������~����U, A�.��jiu��hBMc����qV,��
+�~�~g~�~,�~�~�~�~�~ �~z~B~�}~L~:~0~!~ ~�}�} ~~�}�}~B~�~b~�~�~Z~q~*~�}�}�}j~k~g~~Y~�~j~~�}�}�}�}i~�~�~�~Z~"~�}m}�}%~x~�~S~`~=~!~"~�~�~�~m~N~-~�}�}�}q~�~�~�~?~l~�~�~Z~G~�~x~o~�~�~�~c~�}�}~�~EF�~�~�~G~F~�~d~�} ~"~]~~W~�~�~�~�~r~R~f~�~`~~~I~�~Yx!~�}W~P~~X~E~#~�}�};~5~q~x~~k}v}�}p~�~&~"~!~~N~�~�~�~� [...]
+~z}M}z}�}�}X}f}�}e}P}�}
~�}
~�}!~~�}~3~�~�~W~~ ~�~x~�}�}H~�}�}X~�~x~|~=~�}�}�} ~ ~p~�~�~�~[~]~�~�~G~c~�~8~~9~�~�~�~�~S~\~a~(~#~�}�}�}�}�}�}�})~[~F~?~l~�~$~�}�}%~~#~�}�}-~2~�}�}o}Z}�}j~X~�}~T~-~~~�}�}
~�}M}�|:}�}�}�}�}�}�}h}�|�|�|}-}�|%}8}W}�}�}�}~~�}�}�}�}(}}w}o}�}�}�}y}�}�}Z}K})}
}�}�}�}�}H}[}�}�}}�|6}*}0}c}u}'}=}r}E}U}N}t}8}F}�}�}�}�}�}7}J} [...]
| |�{1|�|R|1|d||�{|)|�{'|?|�|)||�|�|o|�|�|%|
|y|�||�{D|�{�{n|m|Y|z||�{�{�{�{D|.|�{0|!|�{||�|�|�|�|�|�|�|�|T|�{|| |||;|�|�|�|�|�|C|X|F|&|z|X|4|�{�{�{R|I|x|
|F|p|U|&|J|{|�|E|U|�|�|�|�|�|�|�|�|�|�|�|�|Y|�| }�|�|}�||�|}p} }�|}}:}"}�}m}D}^}n}�}�}�}w}q})} }9};}J}�}�} ~�}�}�}y}Y}}F}s}�}�}�}~}�}�}�}�}�}�}W}�}~�}�}�}�}�} [...]
}�|�|�|�|�|�|
+}?}$}}�|�|,}}�|�|e}p}^}?}#}}&}>}�}s}O};}#}}H}M}�}�}�}�}�}�}�}
~~
~-~+~ ~�}�}u}q}Q}f}h}�}�}�}�}�}�}�}�}�}�}�}�}�}�}�}�}�}>~
~�}�}4}-}}E}�|�|}�|�|�|�|Q}N}�|�|4}]}k}e}@}1}@}7}
}�|�|�|�|�|}3}3}K}
}�|�|e|�|�|�|�|�|$|K|l|T|e|N||
|�|�|�|�|w|y|~|R|p|S|�|�|w|.|/|M|g|�|�|�|�|�|�|}�|�|�|�|�|�|�|�|R|�|}J}�}G}5}}�|�|�|'}})}}}�|�|(} }}$}�};}�|�|�|�|�|�|9}&}�|�|4}Z}�}t}C}}'}E}}�|�|8|g|�|�|}J}�|�|�|�|"|.|�|�|�|�|�|u|W|�|g|C|v|�|s||,|�|�|�|�|4|I|�|} [...]
w�v�v�vPwOww�v�u�u�uIv=v4v_vjv
ww�v�v�v�v w�v�v�v~vdv]v�v�v�vBvKv�vyv7v�uNu�u$vNv�v�v�vsv�v�v/v�u�u
vv�uu�t\u�u�u�u
v
v
v�u�u�u_uDumutuGuEu�u�u0v�u�uxu�u�u�u!v,v:vqv#v�uv vv\v]v�v�v6v�u�u�u�u0v�v�vdv!vv*vv�u�u�u�u�u�u�u�u�u�u�uYv�vzv/v�u!uptit�t�tuyu@u5uu�t�t�t�t�t�u�u�u�u{u
uu;u4u�t�t�t2u/uQuu�u�u�uyu@u`u�uXuRuXu^u�u�uxuau7unu�u�u�u v'v�uxuhu�uv [...]
+s�r�r�r�rsxs�s�s/s�rs~s�sRs>sWss�s0tt�sQs:s�r�rzs�st�s�s{s�s�s�sxs`ss;s�s�s�s�stMtt�s�s�s�st�s`s1sfs�s7tzt�t�t�tJt(t�s�sJsGs s�rs�s�sTtTt�sGsBs t�t<u�t,t�s�s�s-tHt�t�t�t�t,t)s�rcr}r�r�s�s�st�s�s�s�s�s�s�s�s�st�s�rCr�rystvtbt4t(t�s9scsgs�r�r�r�rDs�s�s�s
t�sRs�s�sHs�rAr�r�r�r�r�r�r�r�r�r�r�rEs�stss�r�rcst't�s�s_s� [...]
s�s�s�s�s�s�sss�r�r�r�r�r)ss�r�r
ss�r&s's sjsCs�rs�s�st�ss�r�r�rBr�q
+r�r&s�r5s's�r�r7rMr�r�rs�r�r�r7s]s�s
t6t�s�s�sYs
s�r�r�r�r!sVs
s>s�ss�r�r}rvr�r�r#s.sIsCss�rZr�qrbr�rpr�r�r�r�r�r�r�rs�r�r�r�r�r�rRrr�q�q�qrr:rmr�r�r�r�r�r�r�rwrvr�rtrrr�r�r�r�r�r�r�rsfs�s�sbs8ss
s�rr�q�qr�q�q2r�r�r�rtr7r'r[r�r(r�qnq}q�qr�rs�s�s�ror*rrkr�r�r sAs�r�r�ryrFr�q�qzq�qyq�qpqsq�q�q�q�qCr:rAr9r
r�q�qBq@ [...]
+s�r�qq^qEq2qIq�q)rTrMr�q�qyr�r�rmrLr>rbr�r�r�r�r�r\r.rbr�r�r�r�r�r�r�r�r�r�r%sNs�rarUrr�q�q�q�q~q�q�q�q�q6rr�q�q�q@r�rs�r
r r�qaq�p�p�p0q�q6r8rr�qsq[qPqEqMqDqq�pqhqmq�q�q�qVqq�popppJphpep#pJp}p�p�pzp&pfptp�p�p�p�pvq}q�p�p�p]ppp�p�pcpp�o_pzp4p5pAplp�pq,qqq-q�p{pSp_p[pDpp'pp�odoZogo�o�o�opp�olo�o�o�o�o�o"pFp� [...]
+qbq|qUqJqMqq
qq�p�p�p�p�p
+q
qyq�q�q�q
r�q�q�q�q�q�q�q&r,rrDr�rsrDr�r�rer7r_rJrVr�rTr&r2r�q�qr{r�r�ror�r�r�r�r
s�r�r�r�r�r�r s�r�r�r�r�r�r�r�r�r�r�r�rr�q
+rIrrr�r�r�r�r�r�r�r�r�r�r�r�rs�r�r�rs,ss�r�rmr<r*r9rmrhr&r r9r�r�r�r
+s�r�r�r�r�rlrxr�r�r�r�rs�r�r�r�r�r�r�r�r�r�r�r6rAr�r�r�r�r�r�r�r�rwrZrSr�r}rmrzrUr~rir
r�q'r�r�rerHrCrr?rGr5rrgr�rvrr�q�q�q�qIqcq�q�q�q�q�qr�q�q�q�q�q�q4r.r'r�q�q�qr�qr�q�q�q�qRq�q�q�q�q�q�q�qrbrjrpr�rKrrLr�r�rxr�r�r�rgr
r5rWr�r�r�r~rr�r�r�r�r�rs9s)s�r�r s�r�rWsLssssYscsEsQsjs�s�s�sos�st)tLt
t!t�s�sAs5s(s/sEs,s1s�sNs�s�s�s�s�s�s�sCs s s%s"s�rGsts�s�s)s�r�rBr�q�q�q�q�q�q�q1ryr_r4rNrUr)r�qrr"r2r2rr [...]
r�q�qRq�p�pLqoq(q9q3qFqAqFq4q�p�pq�psp�p�p�p�p�p�p�p�p�p�p�p�pq�p�p
q�p qOqFq�p�p�p�p�p�p�pq
q�p�p�p�p�p�p�p�p<qSqHqMqSqeqKqq�p�p�p~p�p�p<qq�p+q4qMqeq�q�q�q�qHq.qq0qiq�q�qr�r�r�r�r~r-r�qKqq&qDq�q�q6r�rsAss�r�r�r�rTrVrpr�r sXsCss.sWsasRsts`s?s(s?sBs$s�rss
s<s
s~s�s�sys�s�s�s�s�s t t$t2t�s�s�st�s�s�s�s�s�st
t?tQt`t=t
t�s�s�s�s�s�st"t-t#t�s�snsjsUs.s s�r�r�r�rssGsBsEs
+s-sTs9s�r�r
s*s�r�r�r�r�r�r�r�r�r�r�r�r�r�rs�r�r�rrerUrSr~r�rvrlr�r�r�r�r�rsrqrWrFr"rrxr�rQrNrYr?r-r�q�q�qGr�rYr
r�q�qwq�q�q�q�q�q�q
rrrr>r)rr�q�q�q
+rIr4r_r
rrXr
r�q�qrZr�r�r�r�r�rsrgrjrhrRrir'rGr�r^r�r�r�r�r�r�r�r�r�r�r�r�r�rfr]r�r�r�r�r�r�r�r�r*s(ss�r+s7s=s%ss8sfsZs
s
sdsis�r�r?sVss
s�r�r{r6rEr{rsrwr�r�rxr�r�r�r�r�r1s7s�r�rs�r�r�rs�����m����G���F�M�S�a�w�n�L�Z������
�O�����^�j�����/�'�6�
�L���A��
���b�V������'���
���������<���0����Q�^����5�#��
��Q�������������"����q����������J�!�%�����D��Q�N��:���������f�<�U�������
������� �#�
�-�.�
�O�k�=�������������:�(�^���7�T�(���T�#�}�����.�����������F�H�����c�C�>�.�f���
���������������l�*���H�������<�6�R�{���f�V�S�[�[����� �0�-���r�����������6�������������H�p���!�����u�d�?�7�)������������ �W�7����
�������������I�v�~���
�����Q�8�,�l�/���h�@�6�2�j�w���������������E�X�������������9��������������
+�u�T����� �}���]���h���m���������������a���������+�����������u�����������������d���c�����s�������������S�A�e��������`�]������*�3���}�g�&����������n������
���k�M���������T���������M�����k�<����@���������y�K�_�����5�=���M���m�
�������v�`�E���������������'������������j������������#���<���p�u�����������0��������A�q������ [...]
�E�
���
�<������������@�O� �p�]�2��� ���\�]�'�����l�����������J�
�����v�����������g������ �
+���f��E�6�
��+������_���t�Z�����y���S�����e��R�����n�������������6���!�q�#���������r���������c� �Q�������� �����������+�������
+��������X�Q�(�����������������������O�]����������/�4�V�U�.�����#��<�w�~�P�<����������8���b���������a�k�����/�6�������+�R�}�J�N�����������w�����������������������x������������H�G�~�7�G�6�����?�������������������<���]�b�����j������9�8�����������������i�D���~�,�4�!�3�������R�����������O�
�'�>���S�^����Z�&�:������ [...]
���^�"�+�M�������������� �)�N�c�7�����T��������������%�����\�`��� ���������������x�
�3������2�>�m�x�~���V�"�;�������/�
�������D�6�p�@�����������%�����������������4���W����
������0���������\�����F�������q�����^�
�E�b�V�Y���������S���k���*���������5���?�����:�G�?���������k�F�x�W�����������������D�����z���k�n�������������� [...]
���*��.�j�Y�����j�:�"�h�������P�1�����y�l����+�����+����������n�
����q�X�`���E���
�C�k�A� �����u�P�J�o�-������9�c�L�S�+��E�|�z�W�0����������k�b���1�A�L�l�&�����Y�c�0�
���������~�P�k�Q��
�W�b�!������E�h�{���3�����3�e�`�c��������"���4�9�H�Z�/���
��������������������������f��������������������=�8�W�Z�Y�o�O�@�����$���������$�D�
�!�?���9�������f�s�Y�]���������
�����|�����p�y����Q�b�����
�����;�x��Q�!�m���������D�x�������������������5�\�w�I�l�p�W�8�D�+�;�.�,���2�{�J��������� �������]�E�!�����u�j�{�(�
����������������P���
�N�����p�n�\�A���'��8���w���
+���������� ���P�T�F�7�+�`���c�2�P�R�f�e�H�;������8�������������"���������������A�M�`������p�������������j�~�r���[�
���$�:�g�������������������� ��� ���A�i�����1�����m�J����������v��#��b���������������������<���A�,�G�3�X���{�x�k�V�x���������h�\�����������
��������Z�0�J�>�}���<�
�����������{�����v���o�[�_����������� �������4�k����{���y��������������������������������p�)�������������� ��;�]�T�Q�#��� �;��#��������Z�������������~��� [...]
+���{�F�R�������4��� �������������\�z���������������O��y���}�������f�E�<�J�I���������7�(������K�g���������f�x���_�i�+�S��k����Y�{�S������������:�E������_�g�F�<�|������u���V�7�X�D�L���s�V�����r�B�-�7�J�������������L����j���������/]������]J,K�D�A���_Oe�~�~�~�~'}pUH<�~�~�~QX�~�~oW�� [...]
�~[~}~�~������ �~�~�~�~�~�~�~V~(~�}�} ~ ~~U~�������W)�~v~�~m~�~51X}����I_�������
J>Q������O�~ i��y�~#~z~~�}
}"}�}�}�}�}�}~
~�~ K�~]~�}�}>~
~~�}�}/~E~v~E�STbj/W��4�~g~_~�~�~p~7~~�}�}�}�}�}c~����a^^S�~1~'~�~�~�~@�'�~�~7��+�~�~�~�~�~m~`~ [...]
+�B�/�H�&���MP��R
+�~04D~�/y���
������0�����~3�~�~�j�~{~S~�~�~.d�~�~�~�~�~�~�~�~�~�~�~~�~�~b~�}}}�}�}�}�}g~i~)~E~�~�~�~�~k~�~�~�~w~�~G~8~�~~~$~
~<~~�}>}�|�|�|�|b|�{�{;{e{
||�{�{�{!|1|
||=|�|�|�|n|�{�{�{}{S{�{�{|'|m|U|G|||G|Y|~|�|�|}�}}|[{<{�z�z�{|,|�{�{�{�{�{�{�{|�|�|�|�|p|A|g|�|~|||T|e|||A|�{�{B{4{�zyz�z�{i|�|�| |;{�{�{>|Q|$|>|E|�|�|�}�~7���I�w�~~�}8}F}�|}k}=}}w}0~�~�~�~P;�~
~�}o~O~.~{~5~G~�~�~�~�}Y}x}�}�}�}~ ~)~�~W~�~�~s~�~�����mD~
~:~~�}�}$~Z~l~u~�~�~f~G~\~`~�~�~�~/�~�~F~ [...]
~~�~�~�~�~�~8�~�~j~�~�~q~z~�~�~�}�}�}N~g~"~�}�}=}�|�||}k}H}i}K}�}F~~
~
+~@~p~A~�}�}�}�~q~o~L~-~S~�~�~u~�~�~�~�~�~�IP? 4�~�~�~ �~�~�~�~�~�~�~�~�~�~�~�~ �~:��Y~�}3}3}�}�}~s~e~Q~;~�}�|�|%}�}3~�~�~�~w��L�~bV?I^�~�~�~�~�}7}�|9}E}
}}�}�}R~�~5�~�~�~Q~�}6}}n}�}�}�}�}�}�}�}�}5~�~�~�~�~g~u~X~~r~RJ�~�~�~�~�~�~�[1�~�~�~�~�~�~%�~~�}�}d}�|p|�|�|�|}B}>}�}/~ ~d}�|�|:}� [...]
+zz{z{{�z�z�{R{�z{�{�{�{�{�{/|A|O|O|�|�|�|�{<|�|�|�|�|v|G|�{i{�z {;|n|x|�|�|�|�{�{�{<|t|�|=}�}�}P}j}�}�}a}�|�|�|o|k|d|�|0}>} }�|�|H|x|6|q|%|�{�{z{N{�zA{�{o{�z�z�z�z;{{�z
z)z
zz�y�y�yoy�y�y"z�y2zbz'zpzkz�y�y�y�yxy`y�y�y�y�y�y�yTy�x�x�xax�w�w'w�v�v�v]wpw�w�w�w�wsw w�v�v�v�v�v�v�w�w�wvw�wyw�w
+xSx�xLxwXvv�uQu�uv#v�u�uvu�u�voviv�v�vOw�w{w
w�v{vfv9vHvNv\vRvvuv�v�v�v�vw8w�v�vv!v�u�uv3v�vjv�vw�vMv�u�uv�uv�ufu�u
v�v wGw�wrwlw�w�w�v�v�v�vww!w�wxMx�xTyDy�y�yGyEy`y!y
y�x yYy�y$zJzzKz�y{y�yz�yy�x!y�y<z>z�zg{�{|-|T|`||�|�|S|w|�|}}�|�|�|v|�|}�|�|�|�|�|�|u}\}�|�|�|7}�}F~.~G~0~�}�}]}
}
}�|O|t|t|�|�|6}c}�}�} [...]
y"y�x�xjx�xCx-xx�w�wuw�w�w�wzwWww�v�v�v�v]v�u�u�u6v�v5wcwaw�w�wx�w�w�wyxx�w�w�w�w�wAx3x�w�w�w�ww�w\xJx7xnx�x�xLy�y z�y�y�ypzZzFzezHz5z<z/zSz�z{�z�z�z{,{H{v{
|�{�{}{C{D{{F{�{{�{m{�{�{�{�{�{�{||�{�{�{|�{�{�{�{�{
|:|||�{ |�{�{�{
|||Z|�|�|�|�|H|�|�|L}C}�|D}
~0~L~~�}�}�}�}�}�}~�}�}v}�}�}~&~%~�~�~�~�~�~f~k~�}�}X}c}j}�|�|�|�|�|�|�|�}�}M} }�|:|)|�{N|a|�{�{Z|�|�|g|7||{O{�z�z�z{p{({�z�z
{�z�z�y�ysyny{y�y�y�yny)yyyy�x!xx�w�wxx2x x�w�wiw�wXw�v�v�vOvfv�v�v~v#vvrv�v5w�v�v�v�v^vDvvev�v�vfv�v�v�v�vvv-vv�u�u�u�u�u�u�u�u�u�u�u�u?v�v [...]
+x+xkx[x(xjxmx�xHySy\yz�z�zqzz�yWy=yy+y�y|z�z
+{v{�{|�|�|r|D|�|�|�|9|_|�|}�|�|�|}�|�|#}}>}}[}k}}�|�|�|I}k}�}�}�~&`{RkN8�~�~~~
~H~�}�}�}�} ~&~�}(~9~�}�}C~�~i~S~r~g~�}y}�}�}}�|}7}
} }�}�}i}�|�|N|�{�{|`|*|�{�{�{�{|M||{|�|�|;||'|�{�{�{|�{�{
||�{�{�{�{�{�{�{�{n{�{D{[{B{{{�z�z�zhz�y3y�x�xyy�x
y3y�xy�xx�w�w
x�x;y�y*zz[z$z�y
+z@zz�y�y�y]y�yz�ydy%ygy�yz�yey�y�yqz{�z�z{�z2{�{�{�|K} }�|�|�|�|k}�}A}�}�}�}�}V~ ~�}�}�}�}�}�}F~i~�~�~�~�~�~�~�~�~�~X~
+~�~�~�~�~�~W~O~~!~�~�~�}�}�~�~>~ ~5~J~�~d~s~{~W~t~f~p~1~
~�}�}U~W~H~�~�~�~ �~9~4~#;;�:�:w:::@:�:�:�:x:f:�:]:B:K:?:�:�:b:�:�:�:�:�:�:]:@:P:[:g:�:�:�:;�:Z:�:�:�:
;
;�:!;;;E;E;U;F;;�:n:�:�:�:�:;�:�:;;;;�;v;;;�:�:�:�:�:�:�:�:�:�:�:7;@;;+;5;$;>;;E;4; ;9;0;
;�:�:;�:;$;I;?;!;;W;�;>;;u;{;�;i;8;;�:�:=;';�:�:�:{:�:�:5;f;:;8;Z; ;�::�9:N:G:N:.:�9 :H:�9�9�9�9�9�9�9::M:F:%::�9�9�9q9h9X9,9J9�9�9�9�9�9�9�9�9�9�9u9�9�9:::h:T:�9�9
:":J:�:�:�:�:l:�:�::�9::�9�9�9�9}9g9,9
959-99919 [...]
+:&:F:+:v:i:&:�9
::�:r:�9�9�9�9�9�9�9
+:�9b9S9�9::�9�9�9:,:H:r:+:�9�9S:�:�:�:�:�:�:�:\:?:U:�9�9t9:9m9�9z9�9�9�9�9�9�9"::�9!:
:�9�9�9�9�9f9�9�9I9
+9.9Z9-9�8�8
9�8�8�8�8
9[9M9@9�8�8�8c8�8�8�8�8�8�8�8�8�8�8�8�8�8�8�8�8c8�8k8;8U88u8�8�8�8�8�8�8t8k8|8d8s8�8^8�8e8+8�7�7�7�7�7�7�7e7
7A7
7�6�6�6�6�67�7~7X7B7_7�7�7�7�7�7s717F787@7�7�7�78�7g7�7�7�7�7_7W7^7�78�7j7S7r797<7�7�7�7p7Y7�7�7�7�7�7�7�7(8�8�8s8A8q8�8�8q8�8�8�8�8�8�8[8O888&8W8�8�8`9W9`99b8X8�89�8�8949�9�9�9�9�9 :):�9�99�8�8�8�8 [...]
88888N8�8�8�8�8�818@8l8�899�8�8�8�8`8�8�868�7�7�7�7�7�7�7o727<7j788�7�7�7�7�7�7�7�7�7�7
+8�78�7X7�7�7{7E7l7q7u7v7�77�7�7C7H7�7�7�7�7�7�7�7�7m7�7�7�7V7�6�6�6�6�66W6�6�677'7
7707$7Y7�7�7�7�7
8�7Z77�6777j7i7[7
7.7w7�7�7�7�7+8S88#8Z8S8%8�78"8W8@8�7�7�7�7�7�7�7�7�78;8I8O8T8{8�8�8�8�8�8�859#99*9>9
9:94999�8
+9�89X939
9�8f9z9%9#9�8�8�8�8�8�8�8�8�8�8t8x8�8�8�8�8�8o8d8�89�8m8[8\8_88:8J8?8Z8;8/8U88 8885848
+8N8'8
8848U8
8<8�8q8,8)818
8 88�7�7i7-7 77�6W6#6<6I6h6�6�6�6�6�676S6 6�5�5�5�5�5�5�5�5�5�5�5j55�5�5�5�5t5E5�5�5�5�5�5!5�5�5�5�5�5�56�5Z5R5P5`5K5t5.55+5;5P575�4�4�4 5*55�5�5#6&66�5
6646p6�666<6L66E6�6�6�67c7_797q7�7�7�7}7�7t7A7T7-7*7E7m7D77�6�6777�6�6|6l6�6
7#7�6!7U7�7�7g7�7�7k7U797;7�6�6�6�6�6�6�67E717�6�6�6<777d7�7�777�7�7X7m7g7g7�7�7e77R7n7
7N7�7w7<77�6"7$7q7�7�7�7M787�7�7;7!7<7�67.77�6;7p7x7h7W7g7S77�6�6�6U6g6a65606f686�5�5�5�5v5=5�4�4�455�4�4�4�4J44a4�4�4r4@4v4�4m4j4�3�34S4;44!4 4 [...]
6
6
6P6
6�56p6�6g6|6�6�6�6�6�6�6�6�6G7?77�6�6}6�6�6�6�6�6�6�6A6?6�6b6 66�6D6�5�5�5 6�6�686L6L6
6 6T6s6!6�5
6
6�56-66�5�5�566�5�5�5�5�5�5Y5
5
5"5J5Q5k5f5z5P5J505'5�4�4�4�4�4�4�4�4�4�4�4�4q4�4v4b4�4:44_4^4$424�4�4�4{4d4s4d4{4�4J5E5�4�45P5w5�5�5�5�5�5 6
666!6D6�6�6�67(7 7�6�6�67A7i7\797:7�6�6�6�6(7�6�6�67D7�6�6�697�7�7k7�6�6 [...]
+676�6�6r6�6�6G6H6�6B6�5
616Z6�5�536K66�5+6�56'6P6 66!66�556y6=66�6|6l6�6Z6"6R6�6�6`6h6v6�6�6�6i6�6�6�6�6a6a6P6 6c6�6�6�6�6�6�6
7�6�67.7787�6<7�7�7�7
737%727 77
77*7�6�6�6�6l6e66�5�5�5�5~5}5�5s5>5'5!5�5�5�5�5�5�5R5E5M5%5I5q55�4v4�4�4�4m4]4p4k4�4&5
5�4�4a4h4�4�4
5�44w4�4�4�4�4{494t4u44�3�3�3�3�3�3�3�3{3?3�3�3�3�3J3_ [...]
4E4,4�3�3�3�3�3�3%4;4A4
4�34�4l4K4�4q4u4r4.4R4\4�4�4�4�4,5�45U5S5^5�5�5�5�5�5�5�5�5Y535z5�5�5�5�5�5
6$666#6616
6�5�5�5�5�556166�5�5'6F66�5H6`6[66�5*6
6�5-6�6�6t6X6�6�6b66�5*6D6h6Y6R6-616r6�6H66
6}6�6`666&6A6H6K6�5'6c6k626�5�56�5�5 6W6�6R66[6�6�6�6(7�6�6l6�6�6�6^6~6f6!66&6
606C666�5�5N5R5F5~5�5U5b5J5h5]5P5=55�4 [...]
+�
�'���ÖȖ��������ז�ŖՖЖ�����Ȗ��ޖ����n�Y���ʖ����ۖ}�o�Ŗ��ۖ�֖��������C�x�H���]�V�U�$�����!�"��6�9�W�'�U�3�K��1�i�O�A�_���������������ԗ��{�b�����s�X�2����v�}���B�E�
�4���t�2���ߖ�����8�U�X�O�&�C�x�^�ږi���і��*� ����Ԗ���̖ΖݖۖƖ���
����������ז��w���֖���������ܖ����`�����Ֆ�ǖ͖����
����(�Ֆ���і!�і��ɖ�6��v� [...]
+����������I�d�G�)����і�E�X�G�S�t�G�y�r�
���
+����ߖȖ��ޖ�ז�s�W�����d���z�}�����|�����h���^�=�����(�%�J�]���*��� ���ڕ���P�@�_���ԕ��<�U�o���9�v�x�,���ŔՔ"��
�D�'�*�|�s�,�6�U�j�
�����Ȕ9�/����
�
�Ĕ������c�~�����A�H��Փ̓����ݓ
�.�m�P�B���ٔȔ����������s�O�x�ߔ ������ǔ������ڔE�����i�Q��ϔߔ-�R���o�3�z�#�ޔ��=�S��a�k���}�m�v�˕��x�������ĕ������O�]�������ޕٕ�!���[�\�� [...]
��"�������ҕ��Z��4��������Õ��������֕ߕҕЕ������˕�������������f�O�S�}�t�}�Õ֕n�����f�*�y�����Օ����x�2�3�f�T�i�(�Ԕ��ݔє����6�A�M���ٔ���T�4�Q�����ȔÔs�n�������6�6�R�*��=� �E�p�X�ғΓK�u�`���r�9�+��>���~�����������D� ��~�A����N�P�5�k���������������"�(���&�
���R�_�Д$������Ҕ���+�
��(�����k��������4���
�]�$��Ӕ<�J��7�������a�`�z�f�l�x�v�����������ܕҕ���&�ٕ����Õ����
����(�1��Ǖ�������}�^�,�)�O�m�5�G�m�a�O�L�X�}�c�7�^�d�z���8�
�)���A�@�� � �˔�֔y�u�˔Ŕ
�G�0�_�}�]�%��������~�e�����[�������H�4�h�֔w���ɓ��J��Гٓ�<�
�+����œ��=�����t�Q�c�x�Ó������Q�e�s������ߓ����g���a�*�U� [...]
+�1�]�V�}���2�2�*�ȓߓ��Γ��ٓ
���͓����
�ߓؓܓē��_���Г����ϓǓ���������Óœɓ��œړ������.�I�
�ߓ�����������������˓
����!���������̓������ӓ��v�r������������k�����ؓ����ؓȓ��y�����������8�~���W��,��Ԓ-�~�8��Z�\��������ǒ�������v�����b�
+����E�D�}�E�
����ّ�����.�0����������������ԑ����~�ݑБ��������,�ؐ��U������h���Ƒ�����ȑ̑ؑ������7�֑��~���ԑؑ����`�*���ב�ёΑ�F�e�%����?�������8�8������
�����(��בƑ�������ۑ�,�/�ʑđ�n�F���ǒT�>�N�~�������z������^�A�5��I��r�������ߒ������ �[�;�Z�F����
�]�A�
�
���ޒ�(��1������ܒ�ْ��ݒ����ђ��������Ò����ђ�ג������������u� [...]
+�[�Y�[�Z�
�ܒ��:�7�5�6�>�B�)����,�^���;�0�v��Вܒ��0�F�]�R�B�&����������u�������ڒגӒb�U���7��
+�C�֒\���ْo��&�n�}�P�G�5�A�*�!�"�ɑ���1�)���!��N�e�?���0�e�<�D�G�'��M���f�B�*�����*�� �0�+���#������:�\�������2�h�/�#�F�����C�������F�T�\���H�
�<�4�6�0�
�b�Z�,�d�/����/�#�M�z�����=��2��+������������y���ڑ�4��͑��Ñ��\�z�=���ߑ�������ґ�u�1�� ����_�5���
+�ʑ�����p���g�N�}�Б�����
+�%�B�n���������,���d���������w���͑��ב�%��ȑ������=�'�
���
�&��Q�E�n�j�r���k�
��ڑ
�p�A�
+�%������Y�<��$�>�B�_�Y�h�1�6� �������w���X�l�E����ԑ�I���v�
������������ȑˑ�z����ё͑�������&��������ȑ��e�@�d�����A�]�g�|���������������ӑڑʑӑߑ����e�=�������w��������ؑ����,�
+����c�0�o�=�L�2�+���*�C����'�7�<���ΐ9�����t����
�����K� �ސ�Ր��$�%�&�̐���@���ېڐ���א�����5����Đ���(�L�(����&��ؐА)�B�L�
����ǐ"�7�|�~�!������������ƐА�f�^�(�9�-��
�
�7�>�Z�,��$�k�S�e�1�E���t�h�n�M�s�����^�j���������ߑ��ґ����ё����w�������H�5���Α����������̑����s�����v�������Ñő��ˑȑ��������ݑ��ۑ%�s�Q�
���
�ȑ������Ց
�7����
�������ܑܑ����ߑ��6��h�Y�R�p�{���L�M�{�J�q���d���O�
��4�_�U��*�
�א�
�#���^�B�1�[�>���Đ��7� ��<�5�Ґ
�I���\�(�#�N�����A�V�`�9���b�`��=��ؐ���3�/� �!��ސ����������&�U���Y�!�:�%�]�"�:�*� �,���I�>��ڐ�� �����Ɛ��K���D���$�P�+�U�f�a�@�d�<��#�g�����4�y���K�(�E�h�Z����a�a�d�(�1�D��ސ(�l�h [...]
+�D�o�
�����
�1��)�A�6�g�d�B�L�������i���h�������x�D�,��������V�3�N�h�8��M���d�:�/�E�����������
+�m�N�f����� ���3�)�I�j�S�����������������Z�j������������!�����;�<�8�G�<�
�����
�G��������� �^���7�]�k�/�B�;��������
���u����
�������=�1��������������������������������
�M�O����������~�����*�������������������������
�����$�6���
������������������/�"������������&�T�;����������
�
��������
�
+�z�����v�t�}�������������������*�`�7�������0�=��������
���)�9��������������������������r���������������������������~�4�
��"��L�I����������
��������������1� �������������J��=�g�O�N�M�+�a�������w�f������/�������~�������������������������������������j�|���������n�r�a�����_�'���3��������q�@�@���������g�����a�q�����������_�f������]�G�:��J�|�u�j�y�����h��n�����������9���V� ���
�������A�w�E�7�1�(����������6�y�.�����������G�������������� [...]
�8�b�(�+�O�5�M���4������������������������Y�^�s�l������������������������H�+�
+�������7�H�����L�#�/�8�L�y�K�"�
+������� ���������������������������z���n��B�.�$��
+�
+�
����������������������������������g�������r�f�O����v�������#�`�_�����Z�T�~�~�M���� �5�D�[�@�C�!�7�n�����|���2�����l�P�������X�����������T���%�.��+�M�v���o�C�K�����>�?�)�)�-�U�����v�������p�\���s�%�%�(�P�]�n���d�M�0��������&���R�,�7�����������������������U��3�6��N�@�J�����������&�5�`�N�n������������������������ [...]
+���������T�?��������������������F�Z�=����5�������
+���u������������������_��"�<���������~�v����������������S�#�!���������!� ����'�E�|���;�c�J�S�z�]�,��������:�8�����&�J�E�N�������������)�k�g��)�x���������������d�z�)�E���&�Y���j�h�v�Z�Z�Q�������9�
��������������������q�2��n�,�Z�����z�~�c�h�n���������|�����s���4������������������������8�
�����������������~�*�J [...]
�����n�J�C�K���8�#�-����9�&���������������������X�y�����I��
���+�%���������e�k���L�4�o�c������� ����%�I�S�o�����$�7� �������q�������������.���;�p������������������������������&�,�(�p�����r�����������{�����j�f���
�
��������(�=�������@�b�W�m�����c�x���~���R�Y�]�d�������������
�Y�}�<�����R�>����<�D�������.�
+��<�
������b��#�
�j�]�
� ���������������������������|�������W�8�H�9�K�;������������T�H�M�r��������
��������������������{���l�H�G�
�L���<���������������w�L� �
�-�i����������������������������������������0�6�r������������5�O�g���q�o�����;�m�����������&�c�S�s�������
�\�����.�&�C�~��������������������������������������� �G���������A�\�\�h��� [...]
+����
�������������8���������
�
+���r�}�������������]�v�������������������������s���%�-����+�
+�����
����)�*���#�m�0��Z�
���������E����������������������
+������
�
������6�{�-�������� �������
��������
���8�d�.� �^�y�S�6���F����E�k�T�����
��(�
�&��:��
�!�����
������������7���
�-�>�+�P�a�5� D� 9� >� 6� $� ��
� H� Y� "� �� �� �� �� � [� g� �� �� �� �� �� �� �� � � ^� � � K� �� �� �� u� �� �� �� �� �� �� �� X� ~� q�
+� �� �� �� �
� �� C� 4� 4� -� �� �� t� �� �� �� ��
� 3� �� 4� �� �� ��
� �
� �� �� �� P� � �� � �� �� 5� R� ]� 7� b� c� &� }� .� G� r� � z� �� `� O� �� � +� d� �� �� �� f� Z� 3� !� �� �� �� E� �� �� $� �� �� v� �� �� � |� � �� ;� � b� M� �� �� �� �� �� �� C� � � �� 5� :� � �� _� "� 2� �� �� �� � z� ;� I� B� � &� >� Z� � u� �� �� � �� �� �� �� #�
+� �� �� �� �� �� �� �� �� �� j� G� �� �� �� �� )� 9� �� � i� 6� �� �� �� &�
� �� ��
� V� 6� (� ��
� V� �� �� H�
� (� �� ;� P� � �� ,� ��
� *� �� �� �� B� �� �� �� a� e� �� �� �� � �� M� �� {� �� �� �� �� t� � �� � N� >� 9� � � � "� E� e� �� �� �� �� �� �� �� ��
+� �� V� J� y� �� �� �� �� m� "� � � -� o� u� 0� � ?� �� �� �� �� �� �� a� ^�
� |� Z� �� �� � w� @� �� �� �� "� �� a� 2� �� �� �� �� �� �� z� g� �� �� �� >� � 0� ��
� �� {� � B� �� Z� �� �� �� F� � � �� �� �� �� �� n� q� A� �� �� �� �� P� R�
� $� �� �� �� � b� k� o� 2� �� �� l� s� �� �� m� �� � w� �� �� �� �� M� _� {� t� ?� P� y� �� �� F� <� b� T� �� �� �� L� �� � �� �� �� ,� "� �� �� m� �� �� �� �� F� �� �� �� %� �� �� �� �� �� �� �� �� �� �� �� �� �� C� �� H� �� 8� � H� |� u� a� s� +� �� �� ]� �� ��
+� �� /� k� �
� � �� � �� �� �� ]� � �� �� �� M� � #� X� *� � � @� �� �� �� �� �� �� _�
+� � �� �� !� �� �� �� �� � � �� �� 2� �� #� �� X� �� v� � �� V� �� �� �� �� �� f� P� x� �� d� � � i� �� �� � @� i� �� �� �� S� � �� �� �� �� � �� �� �� �� �� �� �� b� �� �� � �� l� �� �� T� K� =� � [� ^� �� [� 1� �� � �� C� ,� =� 6� �� �� a� �� �� �� x� H� E� �� _� �� �� 9� }� �� �� � �� �� �� 6� � Q� �� �� �� 5� � � �� �� �� �� q� �� �� � R� ;� � �� �� �� v� �� �� {� <� f� �� �� �� �� �� �� �� �� N� G� ]� �� %� �� �� �� "� �� � >� �� �� �� V�
+� �� -� �� �� � g� �� �� ��
� �� K� ,� v� �� �� �� w� �� l� �� �� �� t� 6� �� �� � ?� (� 3� 7� e� ]� �� � .� �� Z� � � `� �� �� 2� F� � [� �� �� Q� �� K� �� �� �� �� � K� R� �� � 4� � ��
+� 1� {� � �� v� �� Z� � �� �� �� .� � � ]� [� i� �� �� �� �� � �� �� �� ��
� ~� �� �� �� �� �� �� �� �� � � �� �� �� �� �� &� � �� � �� �
+� K� �� �� i� [� �� ��
� |� ~� �� _� �� � � �� J� ;� �� � �� �� R� M� N� �� �� �� s� �� �� �� � .� � �� �� � f� K� �� � �� �� �� �� +� �� h� �� �� � Z�
� �� �� �� {� b� j� I� �� c� �� �� :� � "� �� �� }� x� �� �� S� � �� \� :� `� O� �� �� 3� � �� �� �� ��
+� �� �� �� w� �� k� `� �� `� ;� M� �� � �� �� �� �� &� �� +�
� � �� �� �� &� � /� ~� �� �
� � �� �� &� �� &� �� �� �� �� �� �� �� �� �� �� �� >� � �� j� U� �� \� �� �� �� U�
� � � � �� �� �� �� �� � �� �� �� �� �� |� �� �� �� �� �� p� c� �� ��
+� Q� X� E� �� �� � � *� _� � �� � � ��
� �� �� 5� J� �� B� -� �� �� � �� �� �� �� f� =� \� �� ;� �� |� `� S� S� s� M� E� R� �� �� �� f� K� �� � � � �� �� �� �� i� l� �� �� �� �� �� �� �� �� ,� �� � � �� �� �� �� 8� /�
� �� �� �� �� �� �� �� �� *� � �� �� {� h� � ��
� 9� t� }�
� 9� }� V� %� � � ��
� �� �� �� �� �� �� �� �� w� j� �� � � � "� t� �� `� �� �� �� �� �� �� �� �� �� �� �� �� p� �� �� �� �� �� |� %� |� 6� �� � �� _� �� �� l� y� 1� �� ��
+� <� �� r� N� U� f� �� �� � � � �� �� T� \� �
+� L� |� �� �� �� 1� �� [�
� `� e� -� �� �� t� J� b� �� � � ?� �� �� �� �� T� �� �� �� �� �� �� �� �
� �� �� �� �� X� � .� �� �� V� s�
+� �� �� �� � �� �� �� m� �� h� +� � �� Y� �� �� [� �� �� �� \� 8� )� W� B� �� �� (� � � D� q� �� �� �� v� g� �� I� #� n� �� ��
� � �� �� �� �� �� �� �� � 7� �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� b� � �� �� +� �� �� �� �� k�
� �� ^� �� � �� �� �� �� �� � �� �� � �� � � � H� ~� v� N� �� �� �� h� L� \� �� �� �� �� &� ;� u� �� �� �� �� u� �� �� �� � u� �� � Y� �� �� �� � � "� � �� � �� :� =� 1� N� �� �� �� �� �� �� �� �� ��
+� � �
+� �� �� �� �� �� �� !� �� �� �� �� �� �� 6� �� � �� �� �� �� �� G� 9� K� w� X� �� �� ~� 7� � �� �� �� �� �� �� �� �� � J� �� p� g� b� :� L� �� �� �� �� �� � r� �� ;� H� \� (� [� �� �� �� �� �� �� �� �� �� �� '� � �� !� D� :� :� ]� q� 8� �� �� �� �� �� � � �� 0� [� L� @� 6� $� �� � �� � C� � �� � �� �� �� � f� � �� � �� � 3�
+� U� *� �� �� �� #� u� �� g� �� �� �� �� �� ��
� 8� N� � �� �� �� S� w� �� �� �� U� a� ~� ~� �� �� ^� � �� � �� � �� �� �� �� �� �� �� ;� 4� �� V� � �� �� �� �� �� �� �� �� �� �� �� �� �� s� |� �� �� �� � � �� �� p� Z� r� �� �� �� I� � �� �� �� �� o� S� �� �� a� a� 6� �� �� �� �� �� $� 7� �� �� �� �� ��
� � �� �� � �� �� � �� �� �� �� ��
� �� �� '�
� L� �� J� E� t� �� �� � o� �� ^� V� �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� � <� M� -� �� �� �� � 8� a� '� �� �� � ?� ;� [� 0� G� S� � � � �� 8� �� �� u� �� �� �� �� �� �� � �� �� �� �� �� �� �� �� �� X� s� 9� 6� �� �� � � �� � y� I� M� &� �� � N� � �� �� !� 7� � �� �� �� � %� �
+� %� ]� � %� �� �� �� �� a� c� �� {� x� �� � �� $� �� k� � �� �� �� � L� ;� �� �� �� ��
�
+� �� q� w� �� E� � �� �� �� �� B� �� �� �� =� �� �� � �� �� �� �� �� �� �� Z� o� �� x� ~� �� �� �� ]� Y� g� 9� ,� 9� �� �� �� �� �� �� � � �� �� � �� �� � ��
� P� �� v� /� 6� ?�
� �� �� � )� � �� �� � F� N� T� L� �� �� [�
� ]� �� [� &� �� � T� �� �� �� �� �� �� �� �� � �� o� �� �� s� �� �� �� @� X� � �� � v� � n� �� W� {� �� �
� ^� �� �� �� � {� D� 1� � S� �� �� �� �� �� �� �� �� �� �� �� &� � �� �� �� �� �� �� �� � #� �� �� � #� S� 6� @� l� *� \� d� �� � J� 5� � [...]
R:�
�
�
�
"�
�
�
�
�
9D`�~EJl��
�
�
�
,��Qr��\Q��A� ��/=K����������| ��Q%���
��^^��Wt�����c&�
�
,�
�
�
e�����
�����O�
�
�
�
�
B!�
�
�
�
.JYB���@am�>&�
�
�
�
S�
�
�
Qx~�#�
�
�
�
�
~
�
�
o
�
�
�
�
�
�
�
�
t
�
�
�
�
�
�
�
y
i
4
o
V
,
�
�
�
R
U
�
�
�
�
�
�
�
z
�
�
_
V
�
3
�
�
p
�
?
�
�
�
�
m
�
�
�
�
L
L
E
�
�
g
B
7
L
B
�
�
�
O
-
=
�
�
�
�
�
�
�
�
$
!
p
�
�
�
�
c
�
�
�
}
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
<YM
+I
+�
�
�
:
�
�
�
�
�
�
�
�
(�
�
�
�
�
w
8
U
�
�
R
i
C
�
�
j
#
�
h
g
�
!
!
w
�
)
�
�
�
@
:
�
�
�
A
�
�
�
�
�
�
�
�
'
�
�
�
�
�
�
(
<
�
�
�
�
�
�
�
�
�
�
r
�
�
�
�
�
�
�
j
�
u
O
_
T
G
h
j
<
!
�
l
f
h
,
J
�
�
@
0
�
5
�
8
�
+�
+�
+�
+�
+�
+�
+o
+�
+
6
f
�
+�
+�
+�
+�
+�
+�
+
z
\
4
B
+
3
�
+�
+�
+�
+�
+8
�
+
i
�
�
�
�
�
�
[
o
�
�
B
�
�
B
j
.
�
�
�
M
�
�
�
+
V
�
�
�
�
�
z
�
�
�
(
�
�
�
�
�
!
M
�
c
�
�
%
L
+
c
T
�
�
�
�
�
�
�
�
�
J
-
P
k
�
v
s
m
�
{
�
�
�
�
�
�
�
�
�
�
U
o
�
G
_
�
�
�
�
�
�
%
�
2
A
�
+
g
�
�
�
�
�
�
�
�
�
�
�
�
q
*
�
i
%
u
5
{
�
9
�
N
�
+�
+�
+�
5
�
+�
+W
+�
+l
+� $
+6
+� � � � "
+N
+�
+
�
+�
+�
+W
+�
+�
+�
+&
+
�
+�
+�
+
�
+@
�
�
�
�
j
0
}
�
�
�
�
4
M
X
�
�
l
�
�
l
�
�
�
�
l
?
�
�
)
k
�
�
v
�
�
�
-XM+
+,��^����nH`@��������aU�
�
"����������\n^(�
�
�
A�z��sN�?�
�
=4�->��}gIj��mW>�
�
�
�
e
�
�
F
o
�
f
�
�
�
�
�
�
�
�
�
�
�
�
�
1
�
+
�
Y
8
E
�
�
�
�
z
.
�
+�
+*
S
D
'
6
=
�
+�
+
�
�
�
�
{
K
�
+�
+�
+�
+q
+�
+1
U
�
g
D
�
�
&
}
�
�
�
5
�
�
f
�
i
]
J
2
'
�
3
8
�
�
�
�
�
�
�
q
~
5
X
N
�
#
m
�
W
t
1
�
�
�
+
`
�
�
�
�
�
�
�
�
�
�
�
#
�
M
�
+
�
t
`
{
�
�
�
�
�
�
'
�
8
a
�
�
�
Q
A
X
(
.
�
@
�
�
u
i
�
&
�
�
M
�
�
�
�
�
�
�
�
�
?
U
_
W
�
�
W
�
�
�
8
�
�
�
�
N
^
1
�
+E
�
,
�
+�
+�
+�
+�
+z
+1
+J
+g
+E
+1
+� � � d \ L
���v��� �����@��WA�<>�����}t������ �]<S���������
C � � � � � Y � X g X Z v
+a
+� =
+u
+K
+5
+�
+�
+f
+�
+w
+J
+� � V
+�
+�
+<
+G
+6
+p
+�
+
+
�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+
c
2
�
+�
+*
c
6
�
~
�
+I
l
�
�
�
�
}
f
�
+u
�
�
a
_
�
�
�
�
;
9
�
�
�
l
V
U
�
�
&
r
L
/
L
�
�
�
P
x
�
�
�
�
|
�
�
�
�
Q
.
6
�
+�
a
�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+O
+m
+q
+f
+�
+G
+�
+C
+� � 4
+)
+
+a
+n
+s
+9
+� �
+� =
+
+� � � � �
+� � #
+� � [ � � � j / + ��-����9<4=X �
���?.�
'%� ��� B + ��J Y � >
+� �
+D
+�
+U
+�
+�
+�
+
+
M
�
+�
�
�
�
5
h
b
�
�
x
b
�
�
�
�
�
�
�
"
0
I
�
�
�
�
7
b
!
�
�
�
�
�
(
�
�
k
�
�
V
P
+
]
u
&
a
�
�
�
a
=
C
�
�
�
T
�
�
�
�
�
,
4
G
(
(
�
%
5
X
T
�
5
J
.
L
�
)
�
�
�
�
�
�
�
�
+
�
�
�
5
y
�
�
�
_
4
p
T
%
r
�
O
?
�
�
n
�
a
�
E
(
%
I
}
�
�
h
�
#
,
!
�
(
E
i
�
}
�
J
�
=
�
+
U
[
i
y
y
5
-
>
n
J
�
+
�
+
^
8
�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+u
+�
+c
+_
+i
+�
+�
+�
+
+
+`
+Z
+J
+W
+�
+]
+h
+G
+$
+
+� � � � ~ q ` ^ � `
+ � N N � � @ _ P � u 6 l $ �! 9 _ Y o � � u O � + @ � � � � � � H
+�
+�
+�
+z
+Y
+�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+�
+
+
�
+�
+�
+�
+S
�
+�
+�
+Z
+M
+�
+{
+r
+v
+w
+�
+�
+�
+�
+�
+
�
+�
+�
+�
+�
+�
+d
+�
+�
+
�
+�
+�
+�
+�
+�
+�
+
?
�
+�
+�
+
�
+�
+�
+�
+�
+
?
l
A
0
{
S
�
v
�
+9
|
g
�
+�
+'
�
+�
+�
+�
+�
+
9
G
O
T
N
(
�
+�
+�
+a
+'
+{
+�
+g
+�
+�
+�
+_
+�
+�
+g
+G
++
+J
+� � �
+�
+s
+
+4
+1
+:
+)
+5
+O
+
+!
+� �
+
+y
+A
+8
+k
+�
+�
+@
+� � � � � �
+
+� � � � � � S ] , _ R ' V J 8 d . > % " 0 ��C T W ! $ ! @ � � ` Y [ 9 D
( b u � � � s B � � ~ = � V i =
+ ! 9 % I b � u u e � � D � � � b � � � %
+� � � �
+
+� � � � I
+^
+
+Q
+�
+�
+u
+~
+�
+8
+
+� �
+
+
+
+Q
+Z
+B
+�
+�
+T
+U
+e
+[
+A
+�
+
+� '
+�
+�
+�
+}
+I
+�
+�
+�
+,
+�
+�
+�
+�
+�
+�
+
�
+
�
+~
�
�
�
]
z
�
}
�
+F
>
#
~
�
�
y
p
�
[
|
�
�
�
�
�
�
�
�
�
+4
�
J
(
R
+
�
+l
�
h
?
�
+�
+�
+�
+�
+�
+�
+�
+l
+g
+�
+�
+�
+�
+|
+q
+v
+K
+�
+�
+�
+g
+�
+(
+� � � � � � �
+
++
+
+� � -
+
+� � � � � � � � � � ] � � = � �
+� ] Y
' ? � � � � � l � � � � � � � � � � � U L � H ; �
+� A
+R
+-
+
+�
+�
+9
+� �
+!
+
+� �
+C
+� � ;
+6
+J
+>
+� � � 2
+� � � )
+7
+� � � � � � �
+
+8
+
+3
+f
+]
+.
+
+
+� � � � L
+q
+� � o
+�
+(
+
+c
+-
+v
+j
+[
+�
+0
+F
+>
+&
+�
+'
+$
+x
+s
+q
+m
+
+2
+e
+k
+o
+y
+��
����H����������������������������%�&�:�������������o�����������������������
������������]�U�R�g�.�����)�a�B�8�p�B�C�6�C���������Y�Y�E�Y�U�P�m���t������
������%�7�#���������%������������3�D�g�d�������~�t�/�9�<���
�����
�+�6�#������0�R�0��Z�����J����@�x�L�@�Z�7��U�}�2��-���������������-�d�8�������������������������;�G����������������0�W����������������N�L�6�
�
�������m�����������������������q�Q�����o�T�����
�T�n�]��'�e�M��������1��
� �������)�=�]�4�&�����s�x����������������Q�U�A�B�(�A�f���k�����%�4�0�@�j�~�$�������@�/��������6�<�S�8������*�I���c�M�M�>�b�P�g�q��
�@�,�:�Q�D�/�I�m����!�H�[�6��1�����
��������������������������G�������������}����3������ �9�`�e�C���� [...]
��
�C�
+�����i�����B����x���G�J�>�$�<�`�=�I�����+����K���^�D���p�Q��M���G�N�k�u�����=�:�I�L�^�d�h�@��%�/� � ��������X��������9��M���t�a�(�������^�'�5�H�/�D�E��'�7�&�%�[�N�<�2�T�3��-�V�/��+������o���V�V������������������h�`���`�O�B�H�F�{�����J�(���R�����}�y�v�W�]�[�A�W�#������2�Q�j���������~�$�)�i��}�s�w�����t [...]
+�����b�=�"�`��������������������
+���������D�)�7�L�#�f��������������v�m����������� �����q�����|�����
�����������������K�r�����o�8�����j�_�������M�d���^�
��������6�����8������}���"��������h�\����������J�4��L���S�@�4�3�=���������v�����������������������.���'�
�
�E�r�A�k���q�l�w�l�g��f�������������������������l�R�|���������
�������-�F���o����������_ [...]
+�2�#����:�&�����������U�^�������������"�6�8�;� ������������~�������g�H�V������u�����Q� ������
+�����?�o��7�N��$�6������*��������A�$��O�5�>�m�y���j�O�������������������������������%���������������d�\�z�e�c���������������.�F�����2�����Y�T�V�h���������e�W�g���Z�,���x���Z������������f�S�l�I�
�:�G�m�~�<��@�k�n�v��������������������������������t���������v�o�M�.�v�������������~������������� ���E�;�D���������g�a�?���� [...]
�'�
�����������������������
������)�g�w�z�a�Z�i�6�~�0����������v�8�#�2�}���h���������������������i������������(�.�,������������������������������������P�
���������q�s�q�n���N�3�d�k�����{�k���m�G�|�����\�����������������������m�������������-��������������'����f�6�x��������������s���y���������������������
������������.�������������������� �=�+�8�������
�����������������������)�`�������������������.����������������������3�
�-������:�i���]���{�R�9�
���=�O��������[�z�B�.�2�G�+���:�3� ��� �N���)����5�i�P�m���v�i�}�������������0�������������������'�
���f�h�S�H�n���}�I�@�h���������4�7�/�}�|�/�����;�]�r�A������������ [...]
�,�_������������ �F�U�/�=�?�J���
�K�%���������;�^�]���Q�6�A������ �
�:����b�7�:�A�c�w�O�t�t���{�
��P�����(�&�8���������������
���������
�3�h�}�����j���`���� �
������]�Y�����7�v�}�b�v�q�]��N�c�b�Y�:�������8� �A�\�L�5�C�}����������i�i�i jj�i�i�i�i�i�i�i�i�i"iki�i�i�i�i�i�i�i�i�i
j�ili�i4iDii�i�i�i�i�i}i�i�i�i�ibi.ioiSili�iWiki�iGi�h�h6ivi7iCiPi�iFi�h�h�h�h ii�h�h�h�h!iFiLi
i i�h�h�h�h�h�h�h�h�hOh�h�h�h�h�h�h�h�h�h�h�hyh�h�h�h�h�h�h8i�h�h|h�h�hyh�hVhhhh�h�h [...]
+i�h�hiBi�h�h�h�h�hsh�h�h�h�h�h�h�h�h�h9h�g^hKh>h6h?hshKh�g<g�g�g�g�g%h
h�g�ghhhKh3h�g�ghShAh.hWhDh
h!hh0hGh hh�g�g�g?h6hhIhh�gh�g?hWh
h�gh&hh0hHhh*h�g�g�g�g�gh
h<hNh�h�h�hi�h�hKhkh
i�h�h�h�h�h�h�h�h�h�h
i�h�h�h{h&hMh�h�h�h�h�hxh�h�h�h�hii-i�h�h�h�h-i
i�h�h
i,i�iLiFipi�i�isiVii.i�i�i@i�h�hXi/iiLi�iviDi_iEii�i{i i�iwi3ii�hii�hiDiEii�h�h�h�hlh8h/h�h�h�h�h�h�h�hUh8hyhihhhh)h.hh_h.h
h�g!h(h�g�g
+h�g�g�gDggDg�g�grgFglgwglg0gXg
g-gkg9ggg�f�f�f�f�f�f�f�f�f�f�f�f�f�f�f�f�f<g3g
gif_f�f�f�f�f�f�f�f�f�f�f�f�f�f�f�fg
g#g6g�f�f&g�f�f�f�f�f�fzf�f�f�f�f�f�f�f�f�f�f�f g7g�f+f f3fbf�fTgg�f6g>g�f�fhgxg�gxgHgpgGgjg^gZg�g�g�g�g�g�gg�g�gAg8gdg�g�g�g_g�g�gLgpgHg`g/ggJg)g[g�g�g�g�g�g�g�g�gygyg�gwgTg�g�g�g5hh�g�g�g�g�g�g�g�g�g�g�g�g�g�g�g�g�gGgg8g�g�g�g�g�gEg�f�f�fg�f�f�f�f�f�f�fg
g�f�f�f�f�f�f�f�fsf�f;g�f�f�f�fQff�eBfmfxfmfVf0fXf<f�e�efff�e [...]
+f�e�e�eBe9efe�e�e�e�e�e�e�ekee�d$eqe�e�ef:f
f#fCf>fEff�fXfGfGf2f�e�e�eff\f�fPf�f�fIf�f�fgf�f�f�fg.ggHgBg%g(g%gggg�fg�fgRgg�fg
g�f�f�f�fg&g$g8gBgXg7gSgSg g(gg
g@gBgHgXg%gRg�g�gkgKg>g1g*g g4g�gQggg&g�f�fGgTg8g$g7gg�f?gegQgggBgg�f�f�fg�f�f�f�f ggg�f�f�f�f�f�f�f�f�f�f�fbfff\f�f�fwf_f)fFfcf
f�e�e�e�ef
f
+ff
f�e�e�e�e�e�e�e�e�e�e�e�e�e�e�e�e�e�e�ege�e�exe�e�eze�eff�e�e�e�eff�e�e�e�e�e�e�e�e�e�e�e�e�e}e�e�e�e�eff�eGe{e�ere�exe�eee>eFe!e:ee�dBe]e{e�e�eye�e�eff�e�eRe�e�e�eKee'ePe�ePe)e.e�d#eceZe
eVe,e�d�d ee�de4eXeDejeFe-ede�exe�e�e�eye�e$fPfmf]ff�e�e�e�efOf
fef�fjf6f�f�f�f�f�f�fWftf�f�f�fg�f�f>g:g�f�f�f�f�f�f�f�f� [...]
g�f�f�f�fg�f�fggg�f�f�f�f�fgg�f�f�f�f�fJf@f
f�e4f5f�e�e
+ff-f>f
f#fGf�e�e�e�e�e�e�e�e!f f�e�e�e�e�e�e�e�e�e�eleZeQeue]e_eVe�eeeVeze�e�eiee�d
ejeAe$ere%e�dee�d<e7e�d9eeje�e�e{e�ese�e�e�ere(e�d�d�d�d�de!e'e�e�eRee
e�de�d�d�d�d+eTee�d
eRede�d�d�d�d�d�d�d�d�d�d�d�d�d�d�d�d�d�d�d�d�d!e�de!e�d�d$e�dHedePe#eNee�de-eleHe4e�eleKe]eKe�de�de9e e�d�d�d�d�d�d�d�dee�d�d
+e�d�dee�dReXe/e�dJe0e�dee6ee e5e�d�d�d�d�dcdRd�d�d�d�d�d�d�d�dbd8dRd�d�dyd<ddd4d�d2dd5d�d;d�c�c�c�c�c�c�c�c�c�c�c�c�c6ccAc�c�c�cecpc�c�c�c,c
cc:c
c�bcctc�b�b)c�c�c8c�b�b�b�b�b�b�b�b�b�b�bnb�b�bhbybnb�b�bib�b�bc�b�b�b�b�b�b�b�bMc c~b�b
c�b|b�bckcjc6ccXc<c�bc�b�b:cJcc.cc�b�bcfcc�b6ckc�b�b5c3c+c�b c cFcc�b!cc�b�b�bc cc�b�b�b�bc�b�b�b�b�b�b�b�bc
c c�bcUcAcc�b�bcc�b�bc#c.c]cKc9cYcPcOc8c�b�bBc�b�bc>c�c�cTcWccQc^c�c@ccScAcZc#c%cyc7c�b�b�b!c�b{b�b�b�b�bHcGcc�b�b�b�bc7cc�b�b�b�b�b�bc�b�bcLc
c�b�b�b�b�b�b�b�b'bb�b�bxb4b9b
b^bWb�b�b
c�b�bubQb`b�b�bob^b*b+bSb�b�bWbrb�b�bgbcbZbb9bBb�b�beblbub\bb\b�bQbpbKbPb\b=bJbb�ab�bb�a�a�a�a�a�a�a�a�a�a�a�ab�a�a�a�a�a]a�a�a�a�a�a4b?b)b�a�a�a�a�a�a�aNbsb7b b�a�abbb~btb�bGb>b�bMb�bmb�a bNb�b�bob5b`b�b�b�b�bVbRb�b�b�bLb�b�bTbEbeb�bc�bmbDb\b�b�bSb�a
b)b
bb
b�abb�a�a�a�a
b [...]
bNb@bb-bVbNb�a�a b
b�ab bb
b
+blb�bQbb
bb.b-bbub�b�b*b�a�a�ab
bb
b�aGbb�a�a�a�a�a�a"b�abb�a�a!b&b�a�a�a�a�ab;b�a�a�a�a�aa�a�a�a�a�a�a�a�a�a�a�a�a�a�a�a�a�a�a�ata�a�a�a�a
b:b�a�a�a�ata�a�aza�a�a�a�ataQa�a�a~a{a�a3a~a�aXa�a�a�a�a�abb(b�a�a�aVa4aala�apa8a�`�`,aBaEaa#a.a[aTaJa_a/aCaLaBaMaLa�`a<aEaXaEaCafaKa�`a@a5aWa=a;ara�a�a�aka�aTa�azafa�a�a� [...]
+b(b�a�a�a�a�a�aoa+aQauaha=aqaJa�`/a]aba:aa�`�`�`aaa�`�`�`r`n`�`�`�`�`2a�`�`�`k`b`W`�`�`�`}`�`�`U`6`0`&`C`e`U``w`�```�`�`K`G`L`n`C`C`A`I`�`�`�`�`�`�`u`�`�`�`�`�`�`Q`O`G`X`<`9`�`�`�``y`J`y`�`�`�_`�`�`_`j`^`G`3`R`f`�`s`*`;`�`\`:`C`f`�`|`I`h`�`�```P`�`�`�`�`v`�`H`"`^``` `�_�_�_�_�_�_+`�_``I`:`�_
`f`�
+)�
+��
+:�
+j�
+:�
+�
+�
+�
+��
+��
+��
+��
+��
+��
+��
+9�
+%�
+H�
+"�
+
�
+T�
+W�
+�
+1�
+B�
+@�
+ �
+�
+��
+��
+��
+�
+��
+��
+\�
+1�
+��
+�
+��
+��
+��
+��
+��
+��
+��
+��
+ �
+��
+��
+��
+~�
+c�
+v�
+��
+��
+o�
+|�
+��
+��
+M�
+
�
+�
+,�
+.�
+9�
+a�
+J�
+7�
+��
+��
+G�
+��
+_�
+V�
+%�
+;�
+��
+��
+P�
+��
+g�
+��
+��
+��
+V�
+��
+��
+|�
+��
+��
+��
+��
+s�
+�
+3�
+1�
+'�
+^�
+\�
+q�
+��
+��
+��
+��
+��
+}�
+e�
+��
+r�
+=�
+.�
+
�
+��
+ �
+��
+��
+��
+��
+s�
+f�
++�
+S�
+t�
+��
+4�
+N�
+��
+��
+��
+t�
+[�
+h�
+v�
+f�
+~�
+��
+U�
+y�
+��
+y�
+O�
+��
+��
+��
+'�
+;�
+��
+-�
+R�
+�
+��
+
�
+@�
+��
+��
+��
+��
++�
+��
+��
+��
+.�
+O�
+J�
+7�
+i�
+x�
+q�
+N�
+G�
+�
+!�
+0�
+,�
+z�
+��
+��
+�
+%�
+��
+��
+��
+��
+F�
+Z�
+J�
+f�
+��
+��
+��
+o�
+��
+��
+�
+��
+g�
+��
+��
+��
+�
+��
+��
+��
+��
+��
+d�
+N�
+��
+��
+$�
+j�
+,�
+�
+G�
+��
+��
+��
+��
+i�
+j�
+��
+�
+=�
+�
+S�
+��
+��
+,�
+��
+��
+��
+H�
+$�
+Y�
+��
+��
+��
+��
+��
+��
+{�
+@�
+��
+.�
+5�
+
�
+�
+�
+�
+|�
+��
+ �
+��
+��
+t�
+^�
+]�
+H�
+��
+]�
+'�
+3�
+S�
+Y�
+!�
+�
+b�
+i�
+�
+��
+��
+��
+��
+ �
+$�
+9�
+X�
+4�
+
�
+�
+Y�
+W�
+|�
+w�
+6�
+��
+�
+J�
+X�
+J�
+O�
+]�
+N�
+�
+8�
+��
+\�
+$�
+5�
+1�
+?�
+��
+�
+6�
+�
+p�
+U�
+
�
+��
+��
+1�
+%�
+0�
+��
+_�
+a�
+W�
+��
+��
+h�
+��
+��
+o�
+V�
+P�
+\�
+��
+��
+��
+�
+H�
+b�
+��
+��
+��
+w�
+i�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+k�
+��
+��
+��
+s�
+1�
+�
+��
+
�
+��
+��
+��
+��
+p�
+��
+F�
+��
+��
+��
+��
+��
+��
+�
+��
+��
+��
+<�
+�
+��
+�
+Z�
+[�
+]�
+%�
+R�
+��
+��
+��
+S�
+A�
+r�
+q�
+t�
+o�
+[�
+"�
+1�
+n�
+>�
+L�
+��
+��
+��
+h�
+��
+��
+R�
+%�
+��
+��
+'�
+�
+��
+��
+l�
+A�
+�
+��
+ �
+'�
+J�
+;�
+Q�
+:�
+�
+��
+��
+��
+��
+o�
+��
+��
+��
+��
+�
+t�
+��
+%�
+z�
+��
+3�
+��
+��
+��
+��
+��
+&�
+
�
+��
+��
+��
+��
+��
+��
+��
+]�
+A�
+��
+��
+��
+�
+&�
+��
+��
+��
+��
+��
+l�
+v�
+��
+y�
+��
+��
+c�
+*�
+(�
+9�
+t�
+E�
+r�
+w�
+G�
+�
+��
+i�
+
�
+�
+m�
+q�
+n�
+�
+��
+��
+&�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+;�
+��
+��
+g�
+��
+x�
+5�
+&�
+P�
+��
+��
+��
+
�
+4�
+��
+��
+(�
+��
+��
+��
+��
+��
+��
+��
+��
+�
+O�
+�
+�
+P�
+@�
+��
+�
+_�
+��
+y�
+b�
+#�
+��
+��
+��
+��
+^�
+��
+�
+��
+��
+��
+��
+��
+ �
+�
+U�
+D�
+��
+�
+��
+/�
+H�
+��
+Z�
+x�
+m�
+~�
+��
+��
+��
+S�
+v�
+m�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+_�
+y�
+6�
+�
+S�
+j�
+��
+�
+K�
+j�
+��
+��
+�
+
+�
+�
+��
+��
+��
+��
+��
+4�
+��
+e�
+��
+��
+C�
+��
+��
+
�
+r�
+G�
+��
+�
+�
+��
+��
+D�
+��
+)�
+e�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+J�
+
+�
+�
+3�
+(�
+��
+��
+ �
+$�
+��
+��
+C�
+/�
+��
+��
+��
+��
+��
+��
+��
+C�
+��
+h�
+��
+k�
+�
+7�
+C�
+�
+��
+��
+��
+�
+ �
+��
+��
+h�
+��
+��
+M�
+/�
+�
+��
+�
+��
+��
+��
+z�
+��
+��
+7�
+a�
+&�
+!�
+
�
+
�
+��
+��
+��
+&�
+<�
+�
+
�
+<�
+t�
+��
+��
+��
+��
+S�
+A�
+J�
+O�
+��
+��
+��
+��
+ �
+��
+z�
+C�
+��
+
�
+��
+M�
+�
+u�
+��
+z�
+t�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+�
+��
+0�
+��
+��
+B�
+��
+��
+F�
+��
+��
+{�
+��
+�
+
�
++�
+-�
+1�
+��
+��
+��
+��
+T�
+D�
+b�
+��
+��
+��
+��
+s�
+��
+��
+M�
+~�
+��
+��
+��
+��
+��
+�
+'�
+F�
+��
+��
+��
+��
+��
+a�
+��
+��
+2�
+t�
+��
+|�
+~�
+��
+K�
+L�
+��
+��
+��
+��
+��
+x�
+��
+i�
+2�
+��
+��
+��
+��
+��
+{�
+L�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+{�
+~�
+��
+��
+��
+k�
+{�
+B�
+�
+
�
+q�
+��
+f�
+��
+��
+��
+��
+ �
+�
+��
+��
+��
+��
+��
+��
+N�
+��
+��
+��
+a�
+��
+��
+��
+e�
+��
+��
+v�
+W�
+>�
+K�
+7�
+6�
+;�
+F�
+��
+��
+�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+r�
+��
+��
+��
+��
+��
+��
+l�
+2�
+H�
+d�
+v�
+��
+��
+~�
+��
+��
+��
+f�
+�
+��
+��
+��
+��
+j�
+.�
+�
+��
+I�
+M�
+^�
+�
+��
+��
+n�
+p�
+�
+p�
+m�
+��
+��
+��
+t�
+��
+��
+��
+Y�
+��
+K�
+1�
+
�
+��
+��
+��
+��
+c�
+��
+��
+��
+�
+N�
+w�
+��
+��
+h�
+��
+��
+��
+��
+o�
+�
+ �
+\�
+_�
+��
+<�
+!�
+L�
+d�
+��
+��
+Q�
+B�
+�
+3�
+k�
+��
+x�
+��
+V�
+K�
+I�
+Q�
+F�
+[�
+��
+��
+��
+��
+��
+��
+�
+�
+n�
+��
+��
+��
+
+�
+��
+
�
+��
+K�
+.�
+��
+p�
+5�
+`�
+C�
+H�
+^�
+��
+M�
+��
+��
+��
+��
+a�
+��
+��
+��
+��
+��
+�
+@�
+3�
+g�
+��
+��
+��
+��
+��
+
�
+��
+��
+��
+��
+��
+��
+��
+X�
+��
+��
+��
+z�
+��
+��
+��
+��
+k�
+z�
+��
+b�
+��
+��
+��
+��
+��
+��
+e�
+U�
+E�
+)�
+�
+E�
+h�
+)�
+4�
+��
+��
+
�
+��
+w�
+5�
+`�
+��
+i�
+B�
+U�
+K�
+o�
+��
+��
+
+�
+p�
+��
+
�
+0�
+�
+��
+��
+�
+�
+��
+>�
+J�
+��
+�
+��
+��
+��
+��
+��
+l�
+P�
+z�
+O�
+1�
+
�
+$�
+��
+��
+��
+)�
+��
+��
+��
+)�
+��
+��
+��
+o�
+=�
+n�
+��
+��
+��
+��
+^�
+*�
+��
+U�
+*�
+��
+��
+o�
+��
+��
+��
+�
+9�
+��
++�
+��
+��
+��
+��
+��
+?�
+%�
+��
+��
+��
+��
+��
+��
+��
+'�
+
�
+;�
+@�
+��
+��
+�
+��
+��
+�
+��
+��
+�
+��
+��
+.�
+V�
+��
+k�
+%�
+3�
++�
+��
+�
+��
+��
+B�
+r�
+h�
+/�
+b�
+g�
+p�
+��
+��
+��
+��
+��
+��
+��
+
�
+�
+��
+��
+�
+��
+��
+i�
+��
+��
+��
+��
+O�
+S�
+��
+}�
+��
+��
+{�
+�
+��
+��
+��
+��
+j�
+f�
+n�
+��
+��
+w�
+ �
+=�
+��
+��
+8�
+F�
+D�
+O�
+c�
+j�
+D�
+G�
+��
+��
+��
+j�
+d�
+k�
+��
+c�
+=�
+�
+a�
+U�
+��
+��
+`�
+#�
+�
+L�
+|�
+�
+��
+�
+��
+e�
+Q�
+M�
+��
+n�
+;�
+��
+��
+W�
+6�
+
�
+�
+�
+�
+%�
+��
+��
+D�
+�
+�
+b�
+��
+R�
+E�
+F�
+G�
+E�
+
�
+��
+��
+��
+�
+��
+�
+��
+��
+��
+��
+��
+��
+c�
+'�
+"�
+g�
+��
+.�
+��
+A�
+^�
+�
+�
+��
+��
+��
+��
+��
+P�
+��
+��
+��
+~�
+��
+��
+ �
+�
+��
+4�
+`�
+?�
+0�
+c�
+R�
+]�
+y�
+��
+}�
+g�
+�
+^�
+V�
+P�
+U�
+��
+ �
+O�
+>�
+��
+��
+��
+��
+��
+��
+\�
+��
+�
+��
+�
+i�
+
�
+��
+&�
+��
+5�
+O�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+a�
+p�
+��
+��
+z�
+��
+��
+��
+��
+��
+�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+�
+��
+��
+��
+��
+��
+��
+��
+�
+��
+�
+M�
+n�
+X�
+E�
+�
+�
+��
+��
+��
+��
+��
+��
+�
+<�
+X�
+h�
+@�
+�
+��
+��
+��
+�
+��
+&�
+��
+��
+w�
+��
+]�
+��
+��
+�
+
�
+!�
+��
+~�
+��
+��
+��
+��
+��
+$�
+��
+^�
+e�
+��
+��
+��
+��
+��
+��
+��
+��
+�
+�
+��
+��
+��
+��
+��
+��
+��
+��
+j�
+T�
+[�
+{�
+��
+��
+��
+��
+��
+��
+C�
+#�
+��
+��
+��
+��
+��
+��
+��
+��
+t�
+S�
+w�
+��
+��
+V�
+c�
+��
+��
+��
+�
+�
+I�
+�
+
�
+��
+��
+��
+��
+��
+��
+��
+g�
+��
+��
+�
+��
+��
+��
+%�
+�
+��
+P�
+1�
+��
+<�
+J�
+��
+��
+��
+��
+��
+��
+H�
+R�
+��
+v�
+��
+��
+��
+��
+~�
+��
+b�
+f�
+��
+�
+F�
+��
+�
+<�
+��
+��
+�
+.�
+A�
+O�
+�
+0�
+L�
+��
+l�
+
�
+��
+�
+#�
+��
+��
+M�
+V�
+u�
+*�
+��
+��
+��
+j�
+��
+��
+��
+Z�
+j�
+~�
+
�
+Q�
+��
+��
+��
+��
+0�
+ �
+�
+��
+��
+t�
+��
+��
+��
+h�
+��
+{�
+ �
+c�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+g�
+��
+7�
+�
+��
+��
+��
+�
+8�
+�
+��
+/�
+�
+��
+
�
+��
+��
+��
+{�
+~�
+��
+L�
+G�
+W�
+h�
+�
+�
+?�
+��
+7�
+P�
+G�
+4�
++�
+2�
+��
+��
+��
+�
+�
+��
+�
+��
+��
+��
+3�
+K�
+�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+;�
+E�
+�
+'�
+��
+��
+
�
+
�
+�
+1�
+9�
+A�
+ �
+��
+��
+��
+��
+�
+��
+��
+��
+��
+��
+��
+j�
+w�
+p�
+K�
+c�
+��
+^�
+��
+��
+}�
+j�
+{�
+��
+w�
+B�
+c�
+B�
+j�
+}�
+j�
+�
+=�
+�
+��
+��
+��
+��
+��
+��
+��
+��
+�
+�
+��
+��
+��
+��
+��
+�
+��
+��
+��
+��
+��
+��
+��
+
+�
+��
+
�
+�
+-�
+a�
+�
+��
+��
+��
+��
+��
+��
+!�
+K�
+��
+�
+
�
+��
+��
+��
+��
+��
+��
+
+�
+�
+
�
+��
+��
+(�
+B�
+\�
+&�
+I�
+W�
+2�
+!�
+_�
+��
+g�
+�
+{�
+a�
+�
+/�
+��
+��
+��
+��
+'�
+m�
+j�
+��
+�
+�
+�
+��
+
�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+k�
+h�
+��
+~�
+��
+��
+��
+��
+�
+X�
+W�
+�
+�
+�
+?�
+
�
+
+�
+0�
+N�
+i�
+��
+��
+��
+��
+��
+��
+1�
+@�
+x�
+��
+)�
+o�
+j�
+��
+��
+��
+
�
+(�
+��
+��
+��
+��
+��
+��
+D�
+�
+9�
+��
+�
+<�
+f�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+�
+�
+��
+��
+�
+F�
+�
+�
+��
+
�
+��
+��
+ �
+��
+]�
+V�
+�
+��
+�
+B�
+q�
+5�
+9�
+<�
+��
+��
+��
+
+�
+ �
+��
+T�
+�
+>�
+3�
+Y�
+
�
+��
+
�
+��
+�
+2�
+x�
+C�
+�
+
�
+9�
+,�
+��
+��
+��
+|�
+��
+��
+��
+��
+��
+�
+��
+}�
+��
+��
+��
+v�
+��
+��
+e�
+��
+��
+O�
+��
+��
+��
+��
+��
+��
+��
+j�
+��
+��
+��
+��
+��
+��
+-�
+�
+��
+��
+��
+��
+�
+��
+��
+��
+��
+k�
+|�
+x�
+:�
+h�
+��
+��
+��
+��
+��
+��
+�
+��
+=�
+��
+��
+��
+��
+��
+��
+��
+��
+��
+��
+
+�
+��
+��
+��
+�
+�
+-�
+.�
+Z�
+��
+K�
+�
+>�
+l�
+M�
+
�
+-�
+f�
+x�
+��
+��
+��
+��
+��
+��
+Z�
+��
+c�
+�
+9�
+(�
+��
+��
+��
+��
+�
+��
+��
+6�
+�
+�
+
�
+��
+�
+�
+�vCwJw�wx�w]xwy�yz�z{�{�zy�w�v-v�v4ww'v5s%p�n,nPn{o�q�s�ugwx
x�x�y+z&z�y�x3x�w�u�sOq�mZk�iSi�jl�lm�mcn�npo�p#rs�st�t�usv\vGvCv�v7x{�}L�~�}�|�{:{%{/z^yRy3yZx1wdv�u�t�s�rxq�p�p�o^l4iohh�g�hdi�jHl�m o)p(q�qEr�r�sv{x�y�y*yvxgxLx-xFx�w6v�t�t�u0v�t0sdq!pp+p&pApPp�o�oCpLq�q�q&q�o�o�p�qLr)s�s8tu-v�v-w�w�xycy�z1|$}z} [...]
w�utu�u�uLuu�u�v�v]v
v#vJv<vAv]v�u/u�s�p;n�m�m�m�n5opop}p�p�p4qDq�q�qap�n�m�k!k�kUmxo�p8q�qqsp�p�q�stuWw3y�z{{t|=|�zz_z^{w{2{�z@z�y�x�wKv�tsq�o(o0o�oLp"p
p
ppNp!q�q�q�q6qvqr\r�r�r&s�s<s�r�r�r
s�s�trt�s5s�s\t'ts�pBnWmJm{mHm�lzkFjSj�j�k�l.n
o)oKo�n�n�or�s�t�t�t
uu�u�vwlv v
v�u5u1tmssqro3op�pq
q�q�q�q�r�s�s*s�r}r�rIs_s�sIs�r
s3t]u�u!u�ttisVszt.u$uvu�u6vwvSv�u(t�q�omo�o@o
m.jTh�g�g6h�iLkPmZnMo�q�seusvBw�w�w<x�xxZw�vcu
u�uvYv�u�u�u
v�v�vFvvdu�sjrUr�q,q�q�rLsosSsVs�r�qjr�sStu�ts�p:nZlZl\n$q<s�s|rBq�p�p`pq�q�qDrTsOs8s�st9ttVs�p�mvk�i�h&h
fjd$d�d�e�ghjfl�m�orks_t?u�v7w
+x=y�y�y�y�x�w�u5s�ppo$o�oYp�on�lDll�k%l�ln�npo�ocp[q�q0r�r�rsqp�o�n;nAn�n6o�oKq-s�sZuVwzx�x;x�w>x2yJyy?x$w�v�v�v�v�wx+x
+x�w�vv1uttr�q�r�t�v�w*x>w�t q�n{mPm�mModq�r�sdskr�q�q�oMn�nyprq�r�tWw�y9{�|�}6~w��р
�������́��b���_�?��~|�z]z�z�{g|L{�y�wWw�w�w�w�x�y[z�z�{�{Q{OzyWx�x�wIv vcv�vew�x�y{}�~:~:}{|�z�v�qCo�nn�m�l�l&m�nLp�q�s�u]x�y�zl{|L}�}-�G�7�ҁ)���E�Q���T� � ����~�~�~�~L�~O}={gy�x
y�z|w}�~#�~�}R|Kz7x�vAv%vov,vgv�vQwxxx�x�x�y
z�y [...]
+j�g�e�e g
h�h�i�j�l�m�n:p�p�qyr�s�tt�s"s�rur�r ssBs^s�r�r~sFt�t5uYt�rhrs�sxt�u�w'y�y�y�yy
xx�w�us�q6qq�q�q�q�q�q*qVp�o]p{q�r�s�sUt�t�t�t�t�t�t�s�r�r�r�r!s�s�tu�u�t:sdq�on�lrkl�lrlRl�j�g(f�e�e�fQh�j
+n p�pyp�o
oWnnn|n�oSpp�p
q�p�p�p�p�pq r�r�r2rqpuoQo�o�p�qJr�rrdq�p�p�p<qrrAr�q�p�n�m)mhm�munGnUnn<n�n�nbn{n�n�op5p1p�o�o�oKpq�qnr�r�rDr�q
q]o�lk�i�i�i�i�h�g�d�b�a�aja<a�a�bzdaffhjk�j�i�i�iijk�k�k�l!mjmSn^o�op�p�p[q�q�qr�q�qrPr\rjrq�n�m:m'l�k�k�k�kk�iKgee�d0d�d�e�f�h;j�k�l�m�m&n�m�lik�j�k:mn�nMo�ojp�p�poq�q� [...]
o�n o�o�o"q�rws�s�sgsZs1s�r
r�q�p�on�m�m�l�j|ij�jkakBl�m&n�m n�m�m�lNl
+l�k�kKlnp�qs�st�t�tGt3tkt;t�sls�r�q7q�p�p�oo,o�oFp%pp�oGnk�h
h�gg
fe�e�f�h�j"m�n\o�nnAn�n+o7o8n�m�mynkn�mxl l�k�jEj�j&j�h�freee=f�fQgrh�i�j%l�m�n�nun�n
+oo�oSon�l�kPjsi�i"j_j�j�k�m�nMo�o�pzqsr�r3s�sxt<t�s#s�r rq5pJoMn�l�k'k<jDiOhTh-h�gf�c�b�b2bNb�bTcPd;elf2h�i�j�k�l~m�mn�nkoTp�p
q�q�qq6p�n�lqjmi,jOk$lEm�n�p�q�qr6r0r�q?q�o�mJlilrm
o�psItNt�s�s�sLs4r�q
q�p�p�pbpq�qr�r�rs�r�q�q8qbp�o:n�l�l�l�l�l�k6j@g�d(c@c�d�f�g�h#j]k�l�n�o�p*q�pqjq�q�q�q�q9r
s�s�sys�s�s�s�sgt
u+u�tR [...]
���x�7�����*�`�����=����������������������������
� �5���|������u�M����������
����������#���z�������'���������F�{�N��������M���������{���N������h�����o����������������o�����`���.�����4�G�������|�{�����^�#�+�{�}�j���Z�(�i�(�L���������~�#�
�e�d���x���i�����=�A���
���W�d�������N� �o�,�l�G� ��� �����:���v�B���������E�>�,�6�����A���������R�����[�r��������������<�c�a�a�������-�)�L�����0���)�����s�������$�l�����%�����p�*���������|���������0��Y���)���������$������
+���2�.�����`�����7�l�:�0�)�������
��?�����Q�Y�i�c���^�u�|�F�M�'�\���������8� �������}�O�{���������"�����:����#�������s�����
������,�f��W�s�v�A�%�����R�
�B����������������a���U��0���V�T���1�`�����@�������J���m���������������������D����)���������.����$�~� �\�x�I�H��
�|������F� �(�����X�[����L�^���e���1���8�@�Q�o���2�
�t����������(�����������Q���[�(� [...]
�K�X�"������6��z�e�4�����5�F���G�
�g�����>���������
+�t��������%�V�Q�(���:��������v�L�����������d�K������������?���u���p�������������b����
����q����2�-���l�s�������n�^�1�e�?�����?�����:�k���
���U�����e��Q�����������Q�(���?������J���1��#���_�}�Y�Q�����<����=���
�9���9���L���b���Y��|�������#�-������������&�����`�>���S���I������"������E������������������������ [...]
+�y��U�~�/���C�1�����������h�������N��q���9�(���
������d��������������>��a�c���,�#�_���8�n�������C�R���t��� �w�}�X�`���z���������E�+���<���B��t�B�W��#��� �+�=�4�����v���_�������9�������c�J���>������� �O���[�&���y�������e�S������
�2�H�S��v���o����D�����]���������
�}�P�����������a�����>�n���+���
�Z�����H����� �����0���� [...]
�=�/��������L�����(�n�]����{�]��h�W�V���7���`���s���Q�
���L� �������������W�����y�^�V�[���i�/��������'�W�����P�3�������
�
�p���
�p� ���� ��U�k�t�
�s�,���G�]�����O�M�Z����d�X��0�&��������S���M�Y�t�4������G���b�<��1�Y�������q�C�
�l�����^���������������������N���������V���Y�R�Y������q�����
��������j�����.�$��������������U�9���]�Q��������Q�����O�
�7�d���>����'�{���~����ٹg��3�����N���v�������u�n���s�����������B���J�3���}�2�j�����A�����������3�v������V���0�}�����������������������\����k�����^�!������� �t�W�v����=������X�B�(���v����� [...]
�>���W����K���?�Y����&�u����������<��������o�����
�����,�����
+�E���b���?��������L��}���\�f������s�R�<���C������k������r��������p�I�=�|�X�&���"���R�S�������������������Z�U�*�}������#����<�@�[�����_����� ���2���
�c������#�P�����7��������y���r������s��������������d�ܽ���^������@�����3����������"��j���j������� ���}�7���������n����� �������a�����;��[�f���R���c������������ [...]
~~j~"Ee��:4o(�f0�~�~�}�|�{\|�|}I}�}�}G}|�{|�{B|s}�}.}l}\~6Q�����Y���o�����Єk�^������υp�/�����d�����~�}�|�{�z>y'x�w�wx~x�x�x�x�x�x�ypz�{}�}�~���_�~9~�}�}<~�~X������4�e��m�~T~~}�|-|j|}|
}W}�|5}R}+}
|�y�w�v�v`wfx�ys{{}/������~�������-�e��Y�~<~H~��j;
,���@�������P�ʁ�����~�}8}�|#}~� �K�i�Ȅ�����t�р1~�{}y�xgx�w#w�w�yX{'|P}�~~
+~@~w~l~}~�
+��i8�~�|�z�x�v�uOuu�u�v�wzyJ{�|�}�~����R����ց��7�݀����ۀ�8������a�Հ%��~�|){�x}v�tFt�t�v�w�xyy yxx�v�u�uRvDvvOv�v�w�x1zl{�{�{h|�{({�z�yXy�y-zP{U|�}z��`�ȁ��ˁ��ρb����� ���-�q�\���o��T�~�~.~3~�}s}J~�~�~�~
�
$~�}�}c}�|�|;|�{�z/z�y~zc{�{{�y�w9w�v�v�wy%z�{o||F|
|�{�{�{%|4}g~f-�p�~�7�у��r�&�����������Ձ�@���Y��)�}x}%~%~>~�}�|C}o}@}D}C|0|�|G}�}G~�}I}�|�{�z�z�z�z�z�zRz�y
+z�z�z�z�y�x�x�x�x�x.y�y�y7z�z^{R|}C}�|u{�y9x w@v
+vFvw�x�z\|G}�}�~s~[}j}>��ŀԀ�����~I~�}�|�{�{�|�}c~T~�|Iz�w"u�r=r�r�s�t�tHt�t�u�wby�y=z�zr|n4�K�F���$��}�|�{j{t|�}�~t��~|~�~`
+�
�ׁ�
�d� ������
�+�J�!�Z�\�����:�����
�ہ��M���
+�h�"�������y\^�~?������
���ʅK�q�V���:�3������8��������������o����+������f��
qY�]�N�ր_��łقӃB��>�����߅݄���7�-���N���.��=��@����Շ
�2�g�t�����b�0�ޅ�
���
�������݈���5�������ʈ]���z��&�2���ňV�|�c�p���-�w�R�˂W�փ��܃��ƃ+�)��"��������������Ӄ����y���5�Ć�؆��
�����܉I���F�����$�X��݇5�s�����������֊�9��)�4���ψ^����9�����2�����2���<���Ò����֑��=�K�g�/����K�ג��ݒe�b���#�ŐŐ��1��$���e�f��[�c� ����˒w�8�U������r���Ɠ���ܑO�H�;�����|�S�������*�=�����̖&���ޘ�����#��G�.�1�%�ܖ�������֔a���j��?�r�t���Ԗ|�Q��� �{����e�G��������V��f��x�C��I����C���H������B�R����g�Q�!�͓)�(�'�T���4� [...]
�5�������<�x�$���،��͍_���X�������ҏ
+���B�f�U��h��.�K�g�C�ϗ�E�Е�ɔ������!�"�[�� �5�:���Z�Η���(�֕w��=�c���$�p��� �ߕT�����Q���������(����U���P�����V�������y��͉����������(�����C����ȏ��
�b��!�����������p�T�����b���/�k�͔
���\�͕ϖ�
���;�
�̗����n�Ֆ����� ���z�Ӗɖ�;���a�]������%�b�ڏ��v���2��҈��
�J�O�ԃ�=��7��������J�����o�*�����ׅ��x�Ƈ�����ԃ�G���{� [...]
+���ׅ>�͆-���8�)���D�h�?���
��������������وˇJ�ń�͂���3���|� �A�d������5��~�}}�}�~}Z�������r~ ~�}�}�}�}
~~}q|�{�|
~�}�|~|�|-}I}S}�}'~�~(���<�f�)�u�Q�(�M�i���>�܁��(�h�
��~v|�z�yMz�y�y�y�ySz�z
{�{]|#}~h~~v|`{y{{f{`{^{7{{�z�{}�}�~
�~�} }�|�{
{){U{�{�{\{mz}y�yz.z�zq|B}�}_}m|�{�zEy�w�w�w�wmw$w�vsw�w'x3wPv�u�usv6w�wex�xMy?y}yz�zN{�{E{"{�{�{6{{%|�|�}�~���p�w�S���D�� ��� ��U�8�]h~~�~$���x�ǀJ���~"~�|�z�x�v�uu-u�u�vFw�w�x{xlw�v�vwv�u�t�t�t�t�tAsircr�rus�s�t�t'u�u�ulv�v�v�vwYx� [...]
~
~�}�||�{�{�{+||_{�zrz}z�z�z�z�z�yGy�x�x
x�wqw�wmwevu;ts2qp�oRo(o�nsn�m8m`l�k@k�jIi|hWh)h�hZjjk5lAminIo)p q�qRr�s�u�w�x0z1{|�{*{�z�y�y�y�ymy^y7y�xtx8x~x�x�w�vEv]v�uat�ruq=p p'pjp�pOq�rt�tcuUu~u
v�v�w�w�wWy<z�z�{�|H}
}i|�{�z�y�x�w�v�u}t�r�q?qqq\q�qr�s�t�t,uu�uLvQvv'v}vw�w
x
x�x�xy�x�x�x�x�x8y�y�y�y�y�ywy4y$y�xy<y [...]
{�{|�|K}�}�}E}}�|�||�{|�{O{�{A{mz�y0y�xuxx�x7x�v�uvavlv3v�u�t�s/s2s.s sUs�st]t�t%uv�vbw�w�w�w�v�v�vwiw�wxCxhx�xMx7x:x�w�v�u�t�twt�s�s�tbv�w+y#z
{X|9}�}B~�~�~�~�~`~�}
}�{gz4yySyy�x�x�x�xwx�wew�w�w�w�w�w]x�w�v�vv�ttss�sBt�t�uvvv9v�v�v,wwpu�s�r�q�p�o
n|l�k�k�k6lnl`l7lYlHmTn�nCo�oIq�r�s;t�t!v�vrvYv�v�vw6w�v�v�vUw&x�x�y�z�{�|X}�}�}y}/}}p}~W~^~
~k}�||�{�zdz zYyQyiy�xPx�x'x�w�v�u4u�t
t�s�t�t�tu>u>u�u7v�v`wCw�vlu t�sjs�rbr�q�S@T�T�U�U
U�ScS�R�R�SRTmTPT
T"T�T�T2UrU�UEV8V�U?U�S8R�PBP�O�O [...]
+PjO
O
O�NWOPPP�PQ<Q6QlQGQkQ�Q~R�RS
S6S7S�R�R-S|T�UU�S
SRO!LFJ=IPIsI�H�HJ�K�LmLL�L�L�M�O�PQoP�P�P�P�P�QGR�Q~Q�P$Q�Q1RGR�Q�Q�Q�Q�R0S]T�U>U
+U�U�U�UsU�T�S�R
SMSXS�R�RSS�S�S�SU&V�V�V�U�U�U�T�S�SS�R�T�V�V�S!Q
P�O]O0OPsQPR�RaR�Q�Q�R�RERR�QQQ�P$QuQ�PHP�P�P*P
PxO�N3O�OwP/Q�Q�RS�R�QrP`NbL(KbJJ�I[JJJIsI�I�I
JLJK�K�K
L�LhM�MN�N`OP�P�PTP PKP�PBPP�PUQ)Q�PGQpR�STWT�TT(T0U�V�X�W#U R%P,O�MPL2L�M;P�PKP:ON�MrM�M�N�P�R�SUS�Q
P�N
+NNN�N�P~Q�Q�QxQ�PaP�PKQ�P!P�O�O�P�P�PbQ�QlR-S�S�S�R8RwQ)QQQ�Q�Q<Q�OP�P�PQ�PP�P�QzR�S.T/T�R�P�O�OP8P�O�O�OP|PoP@P�O�NCM�K
KIJsJ&KYKDMJQhU�ViU:T�R�Q�R�R�R�R\R�Q�Q�Q@RdRpR�R�R�RS�SRS
+SS�R}R�RaR1R�R<S�S3SRGQ�P�PPP�OcO
+O�N�NMO�O�O�O
O)O0O=O�NN�M"MtLXL}M�O{QEQPO�N�M�L9L�L�L�M\NNN�N�N�N�M�K�J�I�H�H�I�J�L�N�N�M�L�K}K)LMO�RT�S�R@R�Q�Q�Q�Q�P|P�Q�S�T%UU�T�TgT�SS�Q�OMYK"J�IDII�I+K^L�LOL!K J�IIJuJJ�JoL�N4O�N�MMuM
N
+OQlR�R[S#T�TET�TJU�U|V�VsWdW�UkTSWR�R�S*SnRcRmS8U�V�V�UgTSURR�Q_Q QaP�PoQ�Q�Q]QgQ*R�T�W~XpW=V�T&R�P9Q�QrR�R�S
T�S0THU-U�T.T�ScS:T�U,WmWWWMWsW;W�V�V�U�U�U�T�SoSdS�S�T�U�V<W6WkV
U|T7T|S�R{R�R�R�R�R�R�R�R�R�RuR�Q�ON,LWKdKtK�K L�LM$LdK�K�L�M�N&P�QeT�U�UU�T%S�Q+Q�P�P�P�P�QLR�R�S]T7UU�T~T�T�T�T/TT>T�TeU~U�T�TU7U V�VUW&W
W�V�UKU�T�S�S)S;S�ST2S�R�R�QOQ�QQS�T�U]V�VkX!Y9Y
Y�Y�ZdZ�Y�Z�[�\�\]�\]0\�ZA[k\D]�]E]K\�[�[u[e[N[([�Z�Z^Z�YXY�Y�[�^�_s^�\�Z;YY�X�X)Y�Y�Z�[�\0]^w^,^Y^L_[`�`�`Da�a|a�`�_�^�]�\�[�[�[�Z�[1]:]#]&]D]�\�[�[�[�[�[�[M\�[a[�ZTX�UYT�SLT%U V W W�W
X"YZ�Z1\v]G]�\R]^^;^^�]]]�\\�[�ZYZgZZ�Y�YvZ�\p_F_�];\-[PZ]Z�Z�Z]ZgZ�ZZ�Y�YRY�Y�Y�Y [...]
ZYZ[�[�[ \�[�Z�ZZ�Y�Y�Y�Y_Z�Y1Z�Z�Z2ZbYWY�Y [�\�\�[~YX4W
VzU�U�UV�U�UfUlU1V>X�Z0[�Y�WqV�U�T?S�R~SgT�T�T�TS�PO�M�MwNjN1NGN�M�L�KJlH�G�G�H2JbK~LbM�N�OmPEPnP#QR�R�S�S�S�SBS
S0S;SS�R�Q
Q�P�P2Q�Q�QQR#S�S?T�TfT�S�S�TTVWWX�X�X�X"Z5[3ZXXmVhT�R�Q�QFR�RST�TAT�T�T�T�T�T�T�T{TCTFTT�TQU�T�T�T%T�SiS�S�S)T�S�S�T
+U�T�S�RsQ�O�N�NNN�N�O>O}OBP�P�P�QaRPScTV\W_X�X�XYY�X�W-T
Q�O�NNbN�N�NIN�M>MMM�L�LN�O�P�Q�P�O�N�M�MdN3OQO�O8P�PtP"P;QWS_TNS�QHQ�P�P�O�N�MtLaKK
KoK�KiLM�M�MrM�M�MXNO�O�O O�NNOO�N�N)N�M�M!M�L�L9M�M7N�M�M�MMkLEK�IBI�HI�IXI1II!H�G>H�I�J�K
L�L!N�N
N�MuN�NO�O�O2N�M�M�M�MLM&MM�M�M�M^N?N�MXN�N\O�O�O�O�O�P&Q�PhPgPYPvP�PNQ�Q�QDQ5Q�PSP�O�OyP6PTOPNN�M�L�KK�K�M�N�MXL]L�L7L�K�KL�LPM [...]
+M�L�K�J�I7J4J�JL�LZK�H�F
FF�FcG�GGGF�D4C�B�B�C�DBE�E�F%GGBGNHtIJ�J)LMN�NyNN�M�N�O�OLON�LZL�L�L�K�I|H�G�F�F#G�GBH�G*H(IRI�H�H�H�H^I�I
+J�J,K
K�J
KaKcL�L�L�LIL(L3L�L�M�M%N'P4R�R�Q�P�OvN7N�N�N OO�NSN2NnN�NNN�M�M�L�KuL�M�N�NNN�M-N7NNN(N;M|LoL�L�LMrM�NIP=Q�P�P�P�N�K^H&F�D�C�C�C ERF9G�GYH�I�J!L�M�N�N�M�LLYK�J
K�J�J�K�K�L�L�L�KJGH�G/H�H�I�JLVL�K�JuJ�K{L{M�N�P9R�P�N9MLrK�JRK�K�KhL�K
K�J�JRK�K�K%KJlI�H�G"H�I�JTK�K�J=J�I�I�HsH=H�H�H
+IwInIrI�I�J/KxK^K.K\K�K�K6K\J�IuIJI�HPH�H�IHJyJ�J&J�IoI�I�I�I�I�I�I�I�HPH7GDG�G�G<I�J�K
L�L�LL�K�JZJK$M�NO�O,OM�J�H
G�FG3GGGG�G>HUI=J/KxK-J�H?H?H�GH�H�I�JxK�KL�K�KQLsLL+L�L�M�M�N|O PkPoQR�Q
QJP�O+OO�N�N/N�MaNOPzP�P.QQSQ�Q7R�RMRQnOANYNRN�N8O�O�P8S�V�V�TR�O�M�K\J�I�H�G$HH�H�I#J�I*HsF[E�DaE�FIH�HpH�GiG;FYEzE
E� [...]
+K�K�L�LLM�NP�O%N�L�KmJ�H,HfHImI�J]K;K)K�J�JwJeK)L�L�LzL�K
K�J�JGK�KgK�K�K�KRK�J�IdI�H$H�H_I�I�IJ
J�IqIqIJJOJ�J�J�K�KTLWM|M�LVK�JYJhJ9J�I�JKfK�KL�LN��R���{��|����J��z����������������D���"�5������{��}�[�b�y���X�!�J�h������
�����D��������T�g���*�1�����O���!�������+������E�Z���b�0���>�����-��������e�6�����������������/���6�<�����V��<�S�����[���}���������������P���f� [...]
�)�@���/�A�����m������7���
+�3��O�(� �6�P������������0�����-�W�H�
�Y���#�s�z�������`�2���
�r�j���������������q������<����m�I�{�t�y�a�W� ���������������������7�^���E����� �R���t�;���������������N�������:���]�������j������\�����y�+���1��}�����K�,���~���D���������O���.�����9�����V�����������N�������������!�������������5�f�^���������t�������������C [...]
+���
�N�|�q� ���������r�z������������@�����l���p���*�j���!�������q�������O����������
���������'���������������������E�������
���������.���R����������h�����=���]���K���&����o�����������%������T�J����������������u�!�E���}�)��������������e�x��������� ���8�C�����*�����o�i�]�L�b�����������
���e� ���g�����N�����[�j�W�*�� [...]
+���/���������D�����0���}������\�����y��������A�l��z���T�����\�>�����X�����������N�#���
���x�4��y�,�����k�"����������������f� �����{�n�A�h��������f�
�!��!�r������������g��x�g�
�A���O�'�����)�;�P�.����p�����>���/������r�����4�������w�d���Y���o������!���.������p�1�`���-�_�����H�������A�;�������������;���E�����2�� [...]
+�$�Q���������k�8���q���V���|�
���l�A�
+���#�0�
�0�b���������������S����Z�
��������l�*���������
�v���������J�
�+�����`�{����� ���������I�$�7�����1���
+���
��i�@�k�
��Z�F����Q�Q���_�
+�����}�����I�^��@�i���������w�%�p��
�������F�D�������)�����������<���B���������������e�4���)��������{�f�n���s�����D�
���e�������)���k�p���#�I�����9�����)�)��-������*�3����������������
������\�7�+�|�T�#���n�������F�j�����x�y���e�j�M�������r�������M���������W���}�����|�U�$�
�o�x���B���Y�����@���������
�d�f�Z�}������-�r�x�������o���������W�X��1��������_�f���������
��������\�?�w�������[�f�.���5�����r���6�K���
+�.����=�
�����Q�G��� �����U�.�
���t����y�I�p���~�
����������������������v����B�K�����6���<���M�K���������P���K���4� �{�����B�?�x�����e�|�b�f���m�B���~�#�x�~�R������������/��E��������l���1�������b�.����[�2��
�s�h�j�Q�������f����e����������������������O�����#���l�������
�!�����z�����=�{�k�k���������.�&���!�����H���?���9���+�������:�O���������u�r�T���Y���I�����D�x�R�-�R�\���E�N�B�i������k�}�������H�p�������������� �����n�����
���������]�{�e�R�<�� �#�������4���]����0������$��3�'�������C�����m�����������'�.�����
+�,�!���T��������(���D�T�R�!��������
���C�#�������W��X�:���S������6�z�����a�c�H� ���G�?�%�Y������)�f�������!�Y�J�������2�r�%�J�_�.��� �]���;�H�!�B�������S�����:�T���|���{�j�M�����p��m���"�e�������J���'���K����������!�9�
�������������������;���������������H�E�*�4�|��s�U���������K�W�[�����b���{� �~����������:����� [...]
+������0���|����������A�������
��������������t���$������� ������������>�O�C�������[�$�
+�J�d��������}��}�
~�i~�o~�?~�E~�J~��}��}�\~��~��~��~��~��~���l�S�9�@�h�O�x���~�B�D�f�}�=�*�-�y���X�M�����
����M��~��~�T���<��������K��<��)��������z��~��~��~�e~�>~�9~��}��}�
}��|��|�}��}��}�)~�t~�<~�*~�!~��}�U}�}��|��|��|�r|��|��|��|��|�_|�r|�w|��|��|��|��|�x|�|��{��{��{�|�]|��|�}�}�F}��}��}�2}��|�J|�7|��{��{�T|�|�&|�||��|��|��|��|��|�f|�I|��{�u{�f{��{�!|�D|�7|�(|�d|��|�2|��{�H{� {��z��z�{��z��z��z�b{��{�w|�'}�"}�}�3}�4}�%}��|�t|�|��{��{�e{�� [...]
+}�&}��|��|��|��|��|�}��|��|�}�f}�=}�}�P}�~��~�v���H��~��}��}�t}�|}�~}��}��}��~� �'~��}�~��~�r�u���~�7~� ~��}�v}��|�p|��{�\{�_{�r{��{��{��{��{�|�`|�m|��|��|�i|��{�/{��z�
{�{��{�T{��z��z�Jz�%z�
z�,z�Pz�z��y��y��y��y��y��y��y��y�z�
z��y��y��y�!z��y�7y�!y�y�3y��y��y��y�$z�=z��z��z��z��z�J{�v{�F{�{��z��z��z�{��{�H|�l|�O|�-|�K|�B|�d|�s|�
|��{��{�S{�{�
{�{�{��z��z��z�K{��{�T{��{��{� {�'{�Q{�t{� |�C|�3|�9|�
+|�d{�&{��{��{��{��{�6|��|�v|�|��{��{��{�3|��|��|�A|��{��{��{��{�L{��z��z�F{��{��{��{�B{�<{�s{��{�|�.|�9|�d|�;|� |�:|��|�}�0}�A}�_}��}�~��}�)~��~��~�R~��}�q}��}�d~�
~��}��}��}�a~��~�>~�~��}��}��}��}�S}��|�w|��|�r|�m|��|��}�L~��}�{}�2}��|��|�.}�%}�G}��|��|��|�Y|��{��{��{��{�`|��|��|�|}�~�I~�&~��}��|�V|�|�|�;|��|��|��|�R|�Z{�{�-{�O{�F{�;{��z�|z�$z��z�!{�.{��z�Qz�z�9z�zz�-z��y��y��y�by��x��x��x��y�Ly��x��x��x��x�Fx��x��x��x��x��x�#y�xy��y��y�Ky��x��x�]y�Uy��x�x��w�!w�_w��w�x�&x�. [...]
�����ԃ��m����ق����$��S��Ԃ����w��K����a��n�������������S��w��������N���|��r���������������Q��
��g��}��<���������
����C���� ������
+����7��~��~��~��~��~��~��~��~��~�.��~�E~��}��}��}�#~�|~��~��~��~�u~�$~��}��}�~��}��}��}��}� ~�Q~�Q~�G~��~�y~�v~�~��}�Z}�j}�J}�}�}��|�@}�`}��}�~��~�����@��~�
�:����~�/�����������l�����������`��h��?�����6��f��~��~�
��~�^~�l~��~�~~�K~��}��}�E~�~�n~��~�-�������d��������i��������g����������k�K�^���$��a��J���������
��M���������ހ����"������)��K��O��ـ�Q��K��N�����=�����ނ������������%���l��B��������`��
��ˁ�������������܂���Ԃ���������ۂ�*��D��܂�'��R��}��o��D��O��u��Z��������f�����l�������1���������͂������q��d��.��Q�������������������À����I��E������� ����3��ʀ�$����8�<�q�������'��������x�3�1�/�H�C�
�
�0�S�\�-��w���������9��~��~�{~�$�|�}�����)�y~�b~��~�V�����i�6��~�<~��}�v}��|��|��|��|�6|��{�Q{��z��z��z�h{��{�{{�{��z��z��z��z��z��z��z��z��z��z��y�Ly�?y [...]
w��v��v��v��v�w��v��v� w�Dw�Kw�w�Vv�3v�Bv�kv��v��v��v�gv�Qv�av�!v��u�
v�Tv�Xv�1v��u��u��u��u��v��v��v��v��v�Qv�v�!v�@v�;v��v��v�5w�6w�6w�\w�4w�w��v��v��v�8v��u��u��u�;v��v��v��v��v��v��v��v�2v� v�?v�Gv��u��u�)v�@v�Ov�4v��u��u��u��u�
v�gv��v�Xw�Yw�5w��w��w��w��w�[x�Cx�%x��x��x��x�nx��x�y�Vy�{y�Ay�My�*y�2y��y��y�py��x��x�y��x�Ny�
z�Vz�kz�+z��y��y��y�_y�3y�4y�y�
y�Vy�ny�gy�oy��y��y��y��y�iy�#y�:y�}y��y��y�My�y�y��x�zx�ux��x��x�Nx�Mx�<x�2x�7x�Ix�
x��w�x�0x�]x�Fx�9x�Wx��x��x�zx�Jx�]x [...]
w��v��v��v��v��v��v��v�
w��v��v�`w��w��w��w��v�.v��u�Xu��t� u�~u��u�1v�gv��v��v��v��v��v��v�Xv��u�Gu�]u�7u�>u�su�Bu�u�au�ru�v�Yv�\v�Hv��v��v�Av�
v�Wv�Wv�)v��u��u��u��u�$v�Rv�Wv�}v�/v��u�
+v�v��u��u�2v�Vv�Zv��v�Zv�yv��v�w�w��w�x�$x��x��x��x�ux��x��x�
y�Fy��y��y��y��y��y��y�<y�
+y�y�Oy�y��x�x��w��w��w��w��w��w��w��w��w��w�Qw�*w�w��v��v��v�w�tw��w�Ww�+w�.w�w��v�)w�|w��w�4x�2x�Ex�.x�Hx��x��x��x�Kx�x�-x�Dx�Zx�qx��x��x��x�8y��y��y��y�z�Tz��y�z�.z��z�-{��{��{�_{�{�{�s{��{�+|�|�_|��|��}��}�R}��|�n|��{��{�?{�{��z��z��z��z�Fz�"z��y��y��y�'z�
z�z��y��y��y��y��y��y��y��y��y�ey�dy�ky�dy�ry�;y�qy�y�{x�Gx�:x��w��w� x��w��w�x�x��w�jw�>w�7w�Ow�Ww�w�w�w�w��v�'w�w�'w�7w�9w�+w�iw�uw�_w��v��v�w��v��v�Xv�kv�`v�v��u�v�#v��u��u��u��u��u�9v�`v�Av�\v�Cv�<v�6v�/ [...]
��^�����u��z��S��������@�������*��E��ư�Ӱ�j��h��D�����ӯ�6�������������������
��ְ�E��k��d�������ϲ����w��0��.��5��
��r������"��$�����E�����L��ܱ�]�����n��ܱ�������ɱ���W��h�����������
��[�����n��@��\��ϳ����.��M�������� �����6��G��������
+��h�����+��I����Ƴ�ȳ�׳���?����ٳ�������V��y��U��e��o�� ��b��ӳ�ó�����������v�����|��ñ�R��H�����ȱ� ��v�����������E�������
+��������`��"���������g�����o��߰����u��X��������|����
��˰�a��M��G��"�����;��1��
+�����������,��ï����S��$��,��̮�j��������'����'��$��j�����P��*����T�����6�����1����.��~�����������ͮ���X������������y��H��&���������1��o��̮�u��D��v��������°�P�����G����"�����+��k��z��������I����ǰ���6��Z������0��"��!����(�� �����U�����M��C����I����������������������w�����)�����������L��������������c��Z��±���
��r����u��Ƴ����
�����H����ֱ���
����ܱ�[�������~��n������W��]��Ʋ��������������������
��K��C��R�����
��7��;����j��\�� ����k��
����0��y�������������q��b��y��S���������\�����(���N��w�������o��W��U��������4��5��:��ɰ�ݰ�(��R����������x��Z�����ձ���������������������-����������ݰ����W��K��������(��į����������F��Ӯ�{��}��`��[��h��~��®��������ծ�ή����U��_��o�������^����������$��į������������������#�����q������������������ݯ����)���������N�������b��Y��\��U��I��
+����G��dz� ��I����W��������m��[��]��
��4��%��ϴ�Y��_��q�������ߵ�ӵ�������ǵ�������ǵ����ǵ�8���������ն����=��+��z��������@��q��B����ж����������]��|��
+��k��c��
��2��C��l��������a��z����e����������`����������>�����˶�Ŷ���>����ƶ�.��N�����4�����)�����������d����������������ط�k��ٶ����=������H��������������������������ȳ����ٳ������I����Z��Ƴ�h�������a�����������o��e��$�����C��>��)��-��+����������F���������³����k��F������,��b��1��e��y��������
�������Ǵ����Ĵ�۴�����������D��@��b��������$��K�����k��
����|����U��@��ڵ���������g����׳����
��ճ����
��L��}����� ����������
��Ҵ�������,����������������F��F��,��
��J�������k����J��3�����+��u��q�����������v�����������H��C��7��W��Ѷ����*�����)��p��ĸ�ָ�ڸ�˸�������b�����˷�������ӷ����T��6����0�����η�ʷ�
�����J��s��}��-����������7��^�������������������x��d��������<�����ַ���H��:����������b���������}�����b��E��G��S����h��8��
�����$����@�����}��R�����������߳�_����1��dz�.����;��U����>��<����߳����������������W��J��
��������"��~�����e��L�����������������2��
+��ղ����z��IJ���_�����g��Ѳ�B��(��ر�������x��ı���I�����R��U��}��J�������������
��6��Y�������ѱ�ñ����C������}��@��4��A��%����)�����̯�������+��<��>��'����Ů�s��������6��ѯ����1�����S�����˱�ӱ�ֱ����2��ǰ����a����������������T�����l������t�������v��J��7��e��������α�����H�����������̲�������m��w��ܲ������������p��p��l��G��ű����<����߰�;��`�����������±����Ʊ�ݱ���&��o��y�����Dz����������Dz�^�����������|�������f���������������<����Ұ���3��i�����`�������W�����Y�����k��V��5��
��ܯ������Ϯ����R��A������ [...]
+�������C��A������ϫ�«�ȫ�������������������ɫ���ϫ���� ��������������I��d������s��̪���8��[�����J����������&�������������Щ�u�������Ҩ�c��.��t��+�������c��ͨ�x�����è�.��t��s��6��#������+��I��3����������t��t��A��D��t�������I�������A����<��ܩ���>��}��=��[��,�����ԩ������Ω�u��G��Q��\��X��[��S��s�����������
�����2��~����-��@��0�������
��ϫ�G��¬���n�������;��-��̭�m��Y��2��%�����;��������z���������X����=��ɫ�V����B�� ������<����$��R��2�� ��
��ҩ����թ�-��I��Ϫ�+��i��Y��N�����
+����������%��7����)��������P��ì�H��
��
��h�����������*�����֮���z�����ޯ���I��;��;��=�����O��0��ǰ�^��ȯ�Q�����������Ϯ�ڮ�Ʈ�`�����T��$��G���������������g�����ϭ����[�� �����(��ҫ���
��
����
��ʫ�}��H��-��Ū����ʪ��������������
����������ԩ�Ʃ�ɩ����������ĩ�ȩ�����.���� ��L��Щ�J��c��w��7�������X��I������@��
��������������R��M��?��j������$��Z��q�����ũ�h�����E�������������������̪�}���������Ъ�������ު�J��ة�$��f��
��ͫ�������:��2����e������,��Ū�O��=��٩����������/��1������������B�����5��ū���۫ [...]
+����*��`�����������t��A��o��l��o����������]���, O ����
�����N /$� #���
++�p�j������8h�F��w0� ���f�F =�������!�� �U�����U�P �o��B���-������H������������������������ Y�Jc ��������f�7�b�0�������c�.���
���d7;� � ������ ��V���E�X�����m� �m�,���o � � :���� *���+�s��������}���(�t� � � � i ����
�#�����
���n�!���>�����K�����r�6�m��E������O�����
: . ���������
���p�f���'����� ���4P��_�:�( %������ �T�����J8E���HC�,�������#������
���������<�������p�<�u��������.�9���������g���e�.���a�����������`�����I����������� �'�
�������� �����
�!�
���^�;�f�<������������W ������W�������>�k�K�1������!9�xw�;���������H���( f ����#�N��
�6�I�)�G�����!�����%����%�
���=�B Z�t�o������������O��
�/�*���� � � t ;��o�A�h��������}���a1 ��KY�N�f��`���%�
�����_ ������c�h�����w����������T��y�`���#�5������y�R � � � � �����/�*�������5�|�_���=�J��������%���B�����������H�����[�
���t�;�������� �Q�����i���$�����9�k�a�S�y�_�t�^�� X ����( � ��N�� ���
�
�����5 #� ��N����� � �
):��������j�����������O���~���T�l���������>�H�O�s�
���
�;
+x
F
+�,P ������>
t�����`�W����d� � � ��� [���X�1`�K����� ��e�{����F����� u�~� ���f�� �]���\� ����c�:���T������}�%���a���zh� - *
�~u� ��_���(�����U����������.�3�����R�d�y�/�������
���������I�$�����l���������o��t(��8�����6���w������ �@�@�=���
�.�)FT��
�S�� [...]
+� � � ;
+�
+� ����g���6� �
/}<�
�
b
+r
+�
+�
+�
+�
+X
+� �% � j ������� � �J��J�����
+l��
+.�� ������[1+����j;A�9
��� SpSK�2
+����b�v���7��[���V<���>r^Z 3M�H�����x/0 �@
*> y��k��n ��(�8�4 ��a�/c�jkS�
+�O���
LB���Q�b�^D�h�����{���9m����L �
+]
`�
�
J
+_��'F�n��
� �
+�
+�
+� ��
+�
+?
� ��R00)Js�����e
�z�?
�%��>E�����q�
�
�
�
+ ��p�|2B�� ������~G��>d��z~��N�5�t
+
+
+���6���
�B o��� ��~���F `w��� r ? � � /��[����g��������� �=V���s��o����{PC��M ��7�!�L���m�E��������������������������� �����[���+�_�b���E[� �
I
`
+��k � %� � ��5��K�Z����������Y��gD��s��������b,������ , ��, � �
���6��� j������
�=�I�����G���������E�������i���- � � � � r � � / G���&�������&������^����.�v�d���O�����Z�'���lf
����K���)���6�g�v�$���A�E�����K����N���
�
�`���u������������
�����z�/���v��������������� �x���y���L���)���D�"�t�7�������������.���^�)�����������������M���������d���������� ������)��� �L�L�I�1�y���
� � l��x���� c�x�u�����$�c�T�������������)�/������K�G�� 53X������j���*����@�J�I�|��e�&���c�F����B��F���c�������a����b���7� �c�>�`�b���9�����������f��>�K��������������P� [...]
��U�������������V � �c�=��>�^�f�0 �
2#"�
�la53
+
���.�Y������������ ��G\��0� 7�s�����&���
�������$�V���M�����|�7�7���1�=�u���������a�W�������B�����PQH���m����L�.�$�����������{�j�@���o�H�=�~� �b��,��\�a�&���
+�S�P�������������������������f_�(���
+������������S���}�E���{���������"�����d�f�q�����"���������\�N�����4�?�h���3� �D���c�
�a�% N�] >��5���:���G���\�]�����`��� �� � x� �� � � �� � t� .� �� �� �� �� �� ^� &� �� �� �� /� � �� F� q� =� 7� @� �� �� � /� � �� �� � +� �� �� �� �� m� <� t� �� H� �� U� `� "� V� �� �� �� u� �� 7�
� l� � +� �� g� b� 4� _� �� �� w� ��
� �� �� �� �� T� m� �� �� B� � e� ,� �� P� m� �� �� �� V� �� �� �� �� b� j� �� �� �� �� � [...]
+� �� �� � 2� �� �� w�
� !� K� R� � K� �� p�
� � � �� �� �� !� �� �� *� �� H� � @� �� � �� ?� �� #� �� �� �� �� �� � T� �� �� t� ~� � �� �� >� :� l� �� �� �� d� �� � �� �� /� 2� �� e� U� w� �� X� �
� �� x� v� �� B�
� �� �� � �� �� �� �� K�
� �� D� �� �� � @� �� u� R� \� � @� i� /� � �� >� � J� � �� ^� >� H� p� �� �� �� �� �� �� �� C� E� �� 9� C� +� �� �� w� �� ;� k� J� Y� �� X� � |� �� �� �� ;� � W� �� � q� � E� T� W� �� 0� �� ��
� �� Q� � n� c� 7� �� �� �� �� �� [...]
� F� �� �� �� �� � �� �� �
� �� � ��
� �� �� �� � �� � �� �� �� �� 2� b� {� � � �� �� -� � 5� J� �� �� �� Z� �� �� �� ~� �� \� � �� n� � 0� � �� H� �� �� �� �� E� � y� �� Z� 5� +�
� � �� � �� �� �� � �� l� U� �� � 8� �� �� �� \� �� �� ,� �� 6� Q� �� �� �� �� �� � �� H� �� +� �� G� �� �� 8� �� ��
+� }� �� �� c� �� � R� �� �� D� P� {� "� �� ]� �� �� �� �� +� �� �� �� �� \� �� �� � F� @� �� ��
� C� �� M� &� �� h�
+� �� /� ,� � :� �� �� C� �� �� �� ?� �� �� `� -� �� �� �� �� o� �� �� �� 4� h� �� �� z� �� �� �� �� X� �� }� �� �� �� �� g� =� '� !� @� �
� � ��
� �� �� 6� �� f� �� �� � 7� �� � � d� k� �� �� �� �� �� �� �� �� �� Q� `� q� �� >� j� �� s� �� n� �� �� �� �� $� �� U� � D� �� �� ]� �� �� �� �� ]� �� @� x�
� �� � � �� �� �� �� �� "� {� �� x� 8� ;� D� �� Y� h� %� l� .� � �� �� �� u� �� �� �� =� �� $� �� �� �� � I� P� � ��
� �� �� �� � 0� � �� �� � �� � &� �� t� �
� _�
+� I� � �� 8� {� �� � s� � �� e� �� �� �� 5� g� ��
� �� ��
� �� �� �� � � �� �� s� �� � *� v� U� �� y� �� �� N� "� �� n� )� �� r� �� �� �� �� �� �� �� ��
� �� �� �� �� 4� �� �� �� �� �� �� L�
� �� �� S� �� �� 7�
� �� �� �� *�
� �� '� �� #� �� d� Y� �� �� �� �� �� �� �� �� �� � �� �� �� �� �� H� �� �� o� c� l� �� b� � �� (� �� h� >�
� �� �� \� � � �� �� �� �� ��
+� �� �� � �� �� �� �� �� 2� �� F� 5� �� �� '� � y� � �� �� >� �� V� G� �� 8� �� 4� J� V� �� �� q� �� u� ��
+� � 3� _� �� +� b� �� �� � r� f� �� r� {� � � X� b� 8� d� �� ;� �� �� �� �� � �� h� �� �� �� q� c� y� y� �� �� �� �� �� z� � �� &� �� �� � d� ��
� t� ~� �� �� � �� ~� �� � �� �� �� �� �� �� C� �� P� �� �� ,� �� � �� �� �� � �� �� � \� 8� �� *� �� �� �� ~� 8� s� �� �� �� !� r� C� �� j� `� K� �� �� �� �� � �� �� � � �� � 5� �� �� �� R� �� r� � �� s� �� �� �� :� �� �� W� � �� B� �� �� �� 4� 7� �� >� �� Q� � �� �� � C� �� -� o� �� � �� �� S� �� I� �� �� �� � .� � ~� � [...]
� U� �� �� �� s� �� ֿ � ��
+� 7� S� �� �� � ,� �� �� �� L� k� G� � }� P� �� � � n� A�
� ߾ $� :� w� &� ��
� ߾ Ҿ 8� � �� � 3� �� �� 8� M� �� R� �� ɿ � �� o� .� (� �� �� ]� �� �� � N� e� �� �� l� <� � R� p� � B� �� �� �� l� �� �� � �� J� �� � O� �� ;� �� K� j� 4� |� �� �� r� �� �� �� �� �� ^� ��
� r� �� �� o� R� f� �� g� B� �� T� O� �� �� �� ^� �� J� v� �� �� ܾ .� ҿ @� �� �� c� 1� )� �� 7� ,� � � �� �� �� � 2� E� d� �� L� �� �� �� C� �� �� �� �� K� 2� �� �� �� � �� �� �� �� Q� }� �� �� � #� �� �� @� Ǿ [...]
+� � 8� m� -� � .� <� U� � Ի z� l� � 5� � +� �� Z� ȼ � Ҽ ˼ -� � �� �� c� Z� I� � �� l� ݿ �� {�
� P� �� O� U� �� d� �� � F� �� � �� ܿ � ۿ ܾ "� �� �� �� }� ǽ پ �� /� r� �� �� � � ��
� ϼ �� ս
� �
� i� %� �� j� �� E� � � 2� �� �� _� K� �� �� �� &� � +� '� � � �� R� � m� |� �� �� C� Ծ K� e� � � �� g� �� ý �� �� �� �� �� ~� �� �� �� �� � F� �� -� �� � �� ��
� �� �� N� j� L� �� �� Y� \� L� �� �� �� y� Ŀ
� � ,� C� �� �� S� �� m� u� � � �� �� �� c� � H� �� �� �
+� ]� ;� �� ~� !� G� �� �� �� � ?� �� ]� N� �� y�
� �� �� �� ø �� *� ,� (� ˼ ,� �� ;� ̻ #� � �� �� Ż (� Q� �� W� ۽ G� A� � �� l� 3�
� �� �� s� � 1� �� P� �� 3� � �� T� �� s� � �� v� )� ּ �� �� @� .� 6� |� � _� .� F� ��
� A� ��
+� /� )� b� �� |� F� � �� i� �� w� �� g� �� � k� � � �� � g� /� �� �� ʾ 4� �� � ۺ '� |� �� �� p� � l� �� G� �� >� J� `� l� � @� � �� � U� w� d� � �� ȿ �� K� z� �� �� �� o� ܾ � "� ?� G� � )� �� b� � �� L� �� �� �� 5� �� �� �� �� �� �� 9� t� � �� {� `� l� �� �� � � �� �� n� �� o� Ŀ � �� 1� �� �� �� �� B� � #� �
+� �� u� O� � ?� ��
� �� � � �� � y� ��
� �� տ
� q� �� B� 8� �� g� 7� �� �� Ǽ �� � �� �� n� u� � �� � �� �� I� J� �� �� � 2� �� �� @� �� � Ѿ �� �� #� Ҿ ־ þ ڽ �� ̼ �� �� 9� O� �� �� �� |� �� � Q� �� !� � 4� L� �� �� � ɼ �� ۽ k� ۾ � �� � � {� ɻ � � �� � �� � 9� �� V� *� }� g� �� �� �� �� J� � � H� a� �� }� ˾ Q� d� w� ^� �� B� *� �� �� ��
� !� y� �� n� �� �� p� <� �� /� B� �� �� �� �� �� �� �� ,� �� �� �� � q� �� �� �� �
�7���G�����5�(�
������Q�N�
�I�m��C�
���g�h�9�
������%�-������3��Q������X�����H�����l���#�I����������M�����������
�y�������V���Q�=���$��-�<�t�:���t�q�d�]��� ������)��s�O�_�v�����.�-���������!�d���������A�����f���������@���f�0�b� �9�.�^�,�=���+����x�N�z�5�}���������q�
�;�^�������q�J��:�c���1�9�����[���S�����������R���,�T�n�C���� [...]
+��[�0�h�6���m���������������g�6�!���G����m���]�>�����L����=����u�g�R�������?�����w�����R�������������9����~�J�)���y�j� �n���o���d�*���P�������[�F���F���������������0���i���*���r�
���7��@���N���S���
+���0���B���m�~�M�n�������]����������:����/���R������N�O���v�{�U�0��������
�m��������\�����������������W�#�v�
�����)���������������N�������~��������8�J����� ���{��M�(�����������������s�������s���8�����}�h�K���c���������&�V������������a�;��g���K����������������
���-���
���=�d�J������������v�����p�2���^��w���5�����d [...]
+�����1�W�G���<�^�������7�K�������� �������s���������\�9���T���3�������*���������u�0�
�V��������������������������g�������E�1���I���`���h������s����� �C�����I���A���A���$�������������+�0�R�1������T�Q�\���}�y�<�����|�|�k����������=��������}�"�o����e�N���.������}�E�������������� �@�y�0�]����������N�"���������������� [...]
�����M�Z��=�����
��0�������
�8�����������4���k�
�$����=�������{���.��������������,���8�a�w���/��������� �����.�J���T���T��!����������������K���b�N�
�����7�9�����x�5�����������9�����g�w�����(������������R������q�����'�����
�:���������-�����g�����v�����{���������
���f�1�Q�H�B���?������,���]������(�]���v�&�y���
�� [...]
+���&�h������������v���j�������d���u���������v���w�����k�
+�}������c�������Y�
���M�.�H�9�������H���m���?�y����������8�F�I���\���(����=�����)���9�������S����g�������e�����[���������J��������+�d�x�r���I���������3�����������)���l���y�������=�����Y�_���3���6���������$�����Z�z��������������P�3�
+�~�����p�X��b�����B������R�
����,��Ɔ`���k�������I���h�s�
����P��T�B�/��
�Շd��t��e���6����� �քm�p���������������҄Ń�р0�@D}�z�z
|Y}j~Rf�ÁԂ�:�����l�������N��������Q�����c��ˆ���V�9����)��V�ց��G���"���!������G��%�����+��+�ۂ
+�\��������t��ӂ9��o�|���X���'�����^\~?~�~F*���T�Y�{�Ҁ����ρ���ȁ6�w�����Ăڂ�����݅~�T�j�H��ą� �̓҃�=�̃������$�d�����t����΅���
���
���0���W���ڄ��������L������z���o���g�4��������������~�~J^��$���+�������3�?�ل˄����C�C������;� �
����˅� ���h�1��ބF����'�Ɂ<���)�ʁ��ށ���Áہ�������v����h~B}g|t{vz�x�wy�z�{;|�|�}�~C%���*����������n���.��������ĆV���t���t�I�u�ޅ;�-�х=�������̂>�x�������x�k��>�v���K����.���N�ׅ0�7���e�σJ�g�U���'���ـ�>�$��/����%� [...]
�z�A���-�����������^� �πZ��K~�}\~`����~�}�{�z#z�y-z�z�{�|~|݀5� ���g��� ���X�Á��Tv~~
+~�~������X�
�m�����C�9�Ƀ!�'���҂�X�΅U�(�ہ������� �Z�I��&���h���i��������#����u�=��9�/�R�#�1�1��r���Y��k�|�D��T�+�����k�9�҅|���F�E���׆��V���ށ>���Łt�U�S�����Q�n�����w�@�:���O�h��ȅ�ׅ�����)�O���LJ
+���#�+�J��U��i�i�u��܄'�����F�/���J�����L���~�~�
�+�� ���~�}D}f}�}
~�}�}#~�~r~w~3-����3��Ā����~]}�|�}�~��V��?�<���́��i��������A�ԁ
�[�=�]�����ȁv�u�5���|�l�U�&�s�Յ�Ʌ����Džm�^���i�����
���o�N�܃'�f����=����م[�>���΄
�������y�e�Ѓ��d�j�����m�}���}�ʇ����
�ψ���
�^������i��#�Ԋ��,�
��:�������$����|�������I�$�Չ,����'��;�ʈ��j� �
+���n��`���B�ɅD�Ѕ$�P�u�܂A�V�
��O�҄�"�w�����܅���3�p�̄��5�C�ʅ���х���˄��������Ӆ���j��ڃS���
����Ƀo�Ղ������5��v������`�̀�K��m�&�'��~!}<|�|�}�~�
�������5���݄$�0�u��f�����k����ׅ�� ���ʄ�������T�V�����=���(�������d��փ��߃W�[�C�?�?�ʄb�����K�2�z��P�����Ƅ�����ʁY�~����҂��� ���ǂ�"���e�N����ք
�����u� [...]
�H�A�����b�S�����~ ~�}�})}
|�z�y�y�zg{G{�{|4|q|\|M|`|}�}�~?Z�8���ׁ��d���y�#��j���
��ހ��P�U��������������OM}-|�|�}�~������D�р��n�ր����*�?�~t
�+����5�����=�����
�?���ׅL����G�����W�$���ȃ�u�с�P����~E~�~�ɀ>�܁���y���m�t�e�K�i�ށl����d�ǃǃƃ{��|�&�����T
Oq@�~(~e~}~�}�|�|�|�|�|�|�}�}�}
~Ne���ɀ [...]
+~]~�~�~�H�3�9�������B�G�����ƀ�;�?�E���������ԁh����Ԃ��'�����M��ǀĀV�����cp~�}�}B~
~�~�~Q~~Z~�~�~�~�~�~�~
+�}�ɀ
�R�a��n���B��{���~�}�}O~�~�~�~�~,�~"�h�L���~R~�}�}q~?~%}V|{uz
zZz�z{�{�|�}�}�}�}x}}p|%|T||�{�{|?|�|
}q}�}G~�~
+T~�|�{�{K|�|I}�}~�}O~�~:
6H ~d}(}�|@|B|T|�|F|�{�{'{Nz�y-y�yz�yey�y!zbz'z�y�y.z
z�ycz�z�z
{A{Z{^{{�z
{�zkz�z�zvz�y�y�y-zHzjz�z�z�z{O{�z`z�y�ySz�z�{�{|J|}|e| |�{�|^}�}�}�}N~N~D~(~=~�~�~�~�� �<���a��c���.�~
+F��4�d�ƀe��Z����<~�|�{ {�z
+{s{�{�{�{�{�{�{S| }3~�~[&�~�}�|�{�{ |Q|�|�|�}y~�~rX���O��~�}�|�|�|
}�},~�~
HpE o\�~x~�~"9�~�~�~d~L~9~A~�}�}�}Y}�|�|�|}L}
}%}�}
~b~[~Y~b~3~�}�}�}�|�{�z�z�zOzhz�z�z�y�xAxYx�x}y?z{�{B|W|Y|b|�|/}}�|G|E|�|�|{(y�x�x�x�w�w�wxox�x�y�z�z{�z�z
+zyEyRy�y2z�z�zD{�{�|�|�|M}�|�|�|�|�|z|
|�{�{<|�|B}�}E~%�~�}
}�|�|�|�|}}�||{|�|}�}�}}�|7|�{�{�{|�{�{[{�z�z{:{�{�|g}N~/~~(~%~{~�~|�
�x�ۀ��a���ԁ1����a�Q������)~$|�z�zT{|}J~�~).�
����o~�}�}h~�~rn�%�����B��Z������̀�����w������z �
�ƀ � �
�׀{�V��p���u�V���~�~�~�~�~-`P�~1~4~g~U~�}�}�}n}2}�|!|J{�z�z�z+{{?{�{�{�{x|
}�|'|�{|&|N|\|||T|5|�|�|�|w}~=~%~�}8}F|�{{+zy�xy"zT{�{�|l}2~�~�b�~
~T}�|
|b|�|�|�|�|�|�|J}?}�}~P~�~B~_~� [...]
��C��r��k��{��>����y�����H��������?��a��N��]��{��2��#�����-��`����
+��=�������������������I��i�������o�����������`��;��K��������t�����������������<��������������������������a�����7�����:�����������{��������:��8�����������������+�������?��h�����������=��r��(�����m�����g�������T��p��s����������������������z���������������� ��������������������N�����I����������C��m��V�������l�����f��{��i�����d�����'�����A��������������������������8�����V�����
�����"��������a�������f����]��k��������C��Z�������������������2����������r��������)��T�����*��l��������o [...]
��o���������]�����������#��r�� �����V��a�����
+��_�������$�����;�������� ��������n��Z��������8��%��������������b�������r��������x��X�������������a��������.��e��X�����������;��f�����_��L��Y����������������V��;��v��g�����m�����r��M�����u��M���������������<�������w�����p��}����/����"����������o��k�����������������3�����l��u��i���������������z��A��A�����b������������w��r����F��
������������������
�����h��X��z��+��e��g�����I�����P��������F��l��9�����R�����������������#����u��
+��������A��������������-��������w��������������C�����������Y����\����9����9������������m��E��������%��'��;��4�����\�����9�����������������������l�������������N��A��7��<�����������������G��Z��=��������������"��x��������;��������+�����M��������T��������'�����m��I�����-��0������������_����������u��4�������3�����������~��&��O��Q��2����������l�����������������������������{��������s�����4��`�����������I�����i��������������t���������������������������I��L����������k�����������Z [...]
�����������i������g�����D��[�������n��a��h��H��j��h�����v��������
�����i����"�����
������������S��(��e�����q��������
��H�����l��L����������g�����[����L�����R��������8�����!��~����������������������w��'��������R�����q�����=�����������t�������������������
��X��������C�������*�����P�����R�������K��������������:�����������������!�����b��u��������|�����g��[��������&�������������z��-�����������r��E�������������g�����y��h��r�������� ��$��������:����������������k�����
��.�����
��>����x�����Y������������
��&����e�����"�����e��b��6�����������������0�����������^�����
��M��������z��
�����T�����L�����������
+��������
��b�����j��������1��L�����p�����l�������j�����9����|�������z��
�����
����)��n��>�����������R�����������&�� ��L��N��u����� ��������R���������������� �����������g����������<�����F�� ��������=��7��*��T�������_��i�����Y�����F��V����������N�����)���������:�����.�����J��������S��������g�����-����S�����e��O��H��L��Y�����-��s��O�����5��s��
+��#��Q��t��?��d�����
+��������v��V��_�����7��������2��G��������[��������f��C��{����������J��@����������� �������X��������
��$�����������)�����|����������W�������W��*��+��������e�����>��������V�����R�����<��}�����F��5��������K�����8��}��L�����������������������:��\��d��1��������@�����H�����l��2��������=��O��1��/��S��������q��������������e�� ����������������������8��������F�������*��]��������b�����~������������������������� �����������m����������1��������h��x��$�������r��
�����%��+��|��������������� [...]
+�����J��-���������������������!��0�����0��<��V�������X��I�����
��������������
��+��������������Z�������4��G�����&���������������������k��d����� ��%�����U��H��
�����m��������������2�����n��8�������~��p�������w��������{�����t�����$��'��������������r���������������6�����`�������������D����������,�����e��������
��[����������������i��"�� �����I��u��R�����������������������h��������
��������m���������������� �������}��������L��P����X��������g��P��T��������������5��]��j�����#��w [...]
+�����N��_��������'��z��F�����*�������>�������%��M��i�������������������z��I�����!���������������������i�����
+��������h�����x��/��8����������=�����j���������G�����8��������G��p�������M�����r�������������������
������������������������p�����~�����������(��k�������b��
��d��������U��)��������k�����^�����
�����w�����>��.�����/����X��������W��C�����t��`��n�� �����5��������w��9���������������������������N��o�����������������������������z��=��,�����M�����L��C����=��������������������J��_�����S�����H��1�������������@��a�����8��V��������������.��������������������1����?��D��
��������e��<��������E�����;��3�����������"�����b�����Z�������������������x��-��U�����h�����
�����^�����Q�����)�� �����8�����������&��C�����o�����������������
��_��������S��������o�������������������$��j��a���� [...]
I�uI�I�%H��G��G�-H��H��H��I��J�2L��K��I�"H�dG�~G�WG�@G�^G��G�FH��G��G�wG�G�5G�{G�uG�8G�G��F�rF�1F��E��E��E��E�F�G��G�WH�I��I�6J��J��I��H�(H��H�|I�EI��G�
G�YG��G�?H�.H��G��G�"H��H�TI��I�sI��H��G��F�F�}E��E�.F��F�mG�zH�I�I��H��H��H�
I��H��H��H�I� I��H��H��H�\H�
H��G�hH��H��H��I��J��J��K�lL�4L��J�RI��H��H�WI��I�cJ��J��J�=J�YI��G��F��F��F��G�DI�OJ��J�
K�K�KK�jK�L�
N��P��Q�@P��M�/K��I��H�_H��H�cI��I��I�BI��H�wI�
J�dJ��I��H��H�
+I��I��I��I�`I�7I��H�4G��E��D��D��D��D��D��D��D��D��E��F�G�$G��F��F��F�DF� F��E��E�F�=F�%F��E��E�RE�iE��E��E�F�.F��F��F��F��F��F��F�pG�-H�xH��H�I��H��H�=H�uH��H��H�tI��J�JK��K�yL��L�M��L��J��H��G��F��E��E��F��G�pH�TH�
H��G��G�UG��F�QF�pF�{F�jF�nF��F�;F��E�E�HE��F�H�ZH�nH�VH�H�H�@H�jH��H�lI�nI��I��I��I��I��I��I�1J�JJ��I�,I�lH�*G��F�eG�I�JK�rL��L��K�4J�VI��H�AI�=I��H�PH��G� H��H�J�'K��K��L��L��K��I��H�H��G�KH�fI�
+J�?J�nJ��J��J�J��I�wI��I�J��I��I��I�
J�KJ�?J�J�
J�"J��I��I��I�J��J�K�BK�SK�6K��K�GL��L�eM�O��O��N�jL�9J� I�H��G��G�bH��H�
I��H��H��H��H��G�jG�sG��G��G��G�uG��G��G�TG��F��F�
G�
+G��F��F��F��F�;G��G�H�[H�bH��G�SG��F��E� F��F��G� G�qF�JF��E�?F��F�G��F��F�%G��F��E��E��E�xE�3E�BE�6E�xE��E��E�'F�cF�LF�$F��E�oE�bE��E��F��G��H�I��H��G��G��G��F�dE�\D�:D��D��E�$F�qF�G�
H��H��I��I�"I��H�H�zG�TG�^H��I�rJ��J�[K��J�I��G�G�SG��G��H��H�I��H�HH��G��G��G��G��G��G��G��G�-H��H��H��H�H��F��E��D��D�=E�qF��G�FH�<H��G��G�5G�<G�G��F�`F��F�YG��G��H��I��J�WK�tK��J��I�jI��I��I�I��H��H�
I��I��I��I�J��I�UI�I��H��H��H�wH�vH�H��G��G�7H��H��H��H�I�.I��I��I�I�gH�&I�DJ��J��J��J��K�HL��L�M�HL�
K��J�KJ�*J��J��J�LJ�J�$J�<J�^J�=J��I�6J��J��J�1I�YH�&I�-K��L�DL��J��I��H�0G�@F�KF��F�9G��G��G��G��G��H��I��I�cJ��I��H��G�G�=F��E�OE�
E�E��E�<F��F��F�mF��E��E��E�\E��E�7F��F��F��F�4G��G�5G��F��E�,E��E�QF�PF�F�MF�6F��E��E��E�sE�oE�YE�sE�E��D��D��D�E�F��E��E��E��E��E��E�
F�@F��E�qE�gD�FC�&C��C��E��F�QG�fG��F��E�%E�
E�NE��E�EF��F��F�hG�JH��H�QH�$H��H��I��J��J�OJ��I��H��H��H�hI�,J [...]
+H�fH�hH�DH��G��F��F�fF��E�F��F�G� G��F�}F��F�7G�]G��F��F�F��E�rE��E�
F�ZF��F�G��G�dH�
I��I��I�J�4J��J��L�hM��L��J��H��G�bG�gG��G�UH�tH�?H�VH��H��I��J�L�M�M�LM�|M�M��K��J��J��J��J�J��I��I�*J�]J��J�LJ��I��I�bJ�oJ�#J�J�
J��I�dI�I��H��H��H��H��H��I��I��I�I��H�-I�J�4K��K��K�/K�,K�ZK��J�;J��I��I��H�WH�_H�AH��G�H��H��H�)H��G�`H��H�rH�gH�;H�H��G��H�I�.I�#I��H��G�+F�ME�\E�DF�)G��G��G�H�LH�;H��G�HG��F��F��F��F��F��F��F��F�wF�lF�oF�4G��G�:H��G��F�hE�D�C�cD��E�pF��F��F��F�GF��E��E�bE��E��F��G�YG�7E�'C��A��@�vA��B��D��E��E��F��G��H�<I��H��G��F�E��C�7C��B��B��B�C� C�[C�bC�gC�C�ZB��A��A�<B��B�DC��C�RD�$E��E�xE��D�_D�D�D�'D�eD��D�CE��D��D��D��D��D��D��E��F� G�2F��E��E�F��F��F��F��F��F��F��F��F��F��F�G [...]
G�*G��F�{F��F��F��F��F��F��F�~F�|F��F�%G��G�;H�I��I�7J�%J�nJ��J��J��I��H�G� F��E��E��E�;F�F��E��E�F�RF�
G��G�EH�KI�8J�DJ�EI�
G�IE�ED��C�+C��C�E�uF�G��F� F�<F�2F�HF�BG�KI��J��I�xG��E��D��B��A��A�"B��A��A�YB�@C�
+D�$D�9D��C�C�aB��A�;A�,A�~A��A��A�mA�FA��A��A��A�B�AB��A��A�JB�VB�_B�<B�WB�oB�XB�@B�#B�
B��A��A��A��A�*B�
B��A�.B��B��C��C�xC��C�=D�.D�D��C��C��C��C��C��C��C�rC��C�D�tD��D��D��D��D��D��D�3E�*E�6E�E�MD�xC��B��B�C��C��C�iC��C��C��C��C��C��C�D��D��D�.E�`E�~E�[E�CD��B�LB��A�B�DB��A��A�wA��B�+D�E�E�@D�nB��@��?��?��@�SA�B��B��B��B��B��B�VC�cC�[C��C�HD�YD�D��C�xC�LC�C��C�qE�hG�|H�DH�G��E�$E��D��D��D�E�@E�<E�sE��E��F��G��H�!H�KG�F�0E�zD�0D��D��D�SE�|E��E�eF��F��F��F�mG�4H�H��G�G�BG�G�G�bG��G�0H��G��F��E��E��E��E��E�fF��F��F��F�xF��F�G��F��F�eF�F�E��D�qE��F��F��E [...]
+E�ID��C�9C��B��B�C�2C�eC�5D��E�H��H�\H�gF�{D�-C��B�AC��D�ME�fE�.E��D�D��B��B�mB�KB��B��B�eB�AB��B��B��B�NB�@B�SB��B��B��B��B�gB�OB�C��C�?D��C�7D�TE� F��F��F�gF��E��D��C�C��B��B��B��B�0B�`B��B��B�C��B��B��B��B�C�OC��B��B��B�%C��C��C�:D��D�E�#E��D�*D��C�hC�[C�uC��C�D��D��E�9F��E��D�[D�|D�&E��E��E��E�F�XF�TF�F��E��D��C��D�G��H�I��G�<G��F��F��F��F��E�\E��D��C��C�yC�RC��C�^D��D��D�
E�SE�KE�;E�>E�aE��E��E��E�<F�
G�^G��G��H�[J��K��K�_J�dI��H��G�G��F�uG��H�@I�GI�.I�bI�zI�{I��I��I�=J�MJ�QJ�J�TI��H��G�yG��G��H�I��H��H�MH�bH��H��H��H�NH�eH�CH�H�IH��H��H��H�rH��G��F��F�G�@G��G�gG��F��E�TE�4E�?E��D��D��D��D�
E�hE��E�rE�6E�3E�E��D��D�
E�E��D�=D��C�0D�7D�
D��C� C��B�)B�"B�C��D��E�OF�
F��D�/C��A��A�DB�UC��C�D��C�
D��C�5C��B��B��B�,C�]C�GC��B�;C��C��C��C��C��C�|C�D��C��C�D�vD�E��E��F�G�=F�.E�jD��D��E��G�rI�@J�&J��H�SF�8D�C��B��B�D��E�`F��F�GF�~E��D�2D��C�rC��C�nD�!E��E��E��E�E��C��B�C��C�D�D�WD��D��D��D�E��E��E�pF��F�F��E�NF�]F�OF��E�!F��F�G��G�G�EG�%G�#G��F��F��F��F��F��E�F�rF�lF�|E��D�6E� F��F��F��F��F��F�+G�5H����Ϥ���R��s��A��
��0��R��S��|�����\����������]��g�����ƥ���N��U�����
�� ��ڦ�~��K��1��2������*��b��Ѧ���%��[��8��E��<�����������������c��B��o��R����������n��#��"��8����� [...]
+��)��6��<��>��[��!�����W����������������5����+�����c���������
��m�����������
�������¤�O����������\�����K��/��s��ɤ�����ߤ�����������������������������x��N����h�����W��k�������Q��O��ʦ����'��'����� ��/��ߥ�ܥ�����ƥ�������j��u��y����������.����������٤�ʤ����a�����;�����ע�����ע�֢�w��
��Z��2��$��آ�ɢ�������H��T��C�����������M��V�� ����͡����n�������I��f�������������f����������'�����Σ�������գ�/�����ͤ�Ȥ����l������������[����٢���]�����ۣ�ͣ����$����X��-�����٢����x�����ޢ��Ӣ�Ң�Ѣ�<������������� ��̣���z����� ��
����>��8��2��F��J��Ѥ����u��_�������_�����p��
��n��[��Ѥ�s��L��-��s����������|��
�����]��̥����B�������������H��-��z��ť�٥���=��y��e�� �����̥�,��;��&����H��r��������y��'����ڥ����o�� ��������x�����X��+��S��O��=��Ѧ�
�������M�������V�����,�����}��m�������ݥ�\�����P��H��d��s��������Ф����q��j��������M��O��$�� ��
��\��ѣ�������Z��I��������:��8��}�����G��ӡ������,��4����+��J�����R��,��m�����\�����������͡�����������������ߠ�������w��ˠ����ҡ�š�¡����֡�ӡ����O��&��9��h��{�����9��U����?��������آ����^��I������a��O��e��C�����9��G��R��H��W��T��m��G��� [...]
��U�����������N����������Z��Ĥ�
���������+�����ɥ� ��������%������������(��ާ����������s������N�����˧�
+�� �����������
+��˦������K��~�������
��7���������~��>�����*��s�������ͩ�P�����#��Ѩ�������֨����>�� �����/��������Ũ�C����<��F��7����ħ���c����;��?�����������Ϩ������������=�������h�������g����V��̦�
��ɦ�������X�����������P�����l��b��h��'��3��Z����Ҥ�p��W�����ä����������j��F��7��P��������������t��M��e����������������ԥ�Y��{��������n��V��M��%�����ԥ��������ӥ����e��6��0����������[�����W��ť�W�����������ӥ�3�����=��?��\���������[��
+��O��n��{��6����� ��������ɤ�t��¤���������X��Х���ԥ��������-��_��#����������������ĥ���_��{�����������X��;�����Φ�֦�������������������צ���%��(�����P��ǧ�������������7��4���� �����\����� ��i����^�����֨�E��x��_��P��Ũ�ب�)��M��<��l��~�����������Q�����{��Ȩ�)��q��u��L��)��9��s��e��O��+��
��G��x��(�����0��P��k��O��A��
��u��
��������-����n��5�����I��������i��A��&����������
��7��o��������o����� ���������*��
��8��g��;��^�����i��l��m��E��3��
��=��O��������A���������y��]�����I��ǥ�إ�ޥ���J��O��;��ҥ�ҥ����������e��������I��9��������ޤ�֤�>��L��/����̣�
��c�����٣�S��i����� �����)�����������u����������#�����)����ˢ�ڢ����آ���X��}��g��-��Q��q��S��D��
�����d�����̢���'��^�����@��ʤ�E�����f��y�����ǥ�,��K����h��%�����S��]�������'��ˤ����̤�-�����1�������}��u��e��M��\����P��"����Ʀ�x��c��������Ҧ�t��X�������O��i��b��1����ʥ����}��'����V��������������������ե�I��q�����f��Y [...]
+�����������ɢ����������������������1���� ��O��A��4��2�������1�����á�(��P��������W��1��E��B��G��x����I��!�����~��ܡ����������P�������9��+�����M��s��~�������������u�����������s��s�������������Ϟ�y������� ��=������S��=���������Ҟ�V��,��u����������r��֟������������w��7������
�������ڟ������=��s��Ơ�������ߠ� �������X��
��؟�������������+��=��2��
����r��o��c��f��'��2��\��y��{��R��S�����+�����t��r��������y��������
��J�����������
��v��e��ߞ���b�������
��ܟ�(��S���������b��ɠ�y��9��S��J��1��
��G������������+��`�����}��N��m�����$��B��o��(��e�����B��������f�������������ء�֡�.����������������y��b��L��f��x��]��D����"��9�����Ȣ����G��G��*��\��w�����z��h��{��v�����v��g��������M������)�����p��>��}�����V��Z��P����f��������w��
��+��f��Q��e��D��d��;��#��j��k�������
�������T����������!�����F��\�����*��e��K��/��K�����'�����@�������Ɵ�˟�����۠�e��t��W��3��ߠ�Y�������������_��Q�� �������������b��t��y��x��l����������u��Z�������$��3���������O��� [...]
��:��%����V�����������~����I��������4����{�������������Z��
��Ϣ�D�������_��c�����
����
����|�����)�������
��-��������Ť�����������l�����f��!�������|�����Ҥ�Ф����V��£�D��9��H��$��
������������ס�ġ����V��T��Z��������Ρ����W��#����������������4�� ��]��.�����>�������ڟ���ٟ�
+��d�����-��؟�&��������Z��ߟ���ҟ�˟�ğ����(�����1��
���� ��ޞ�������
����
��X�������6��2��Q��z��������ӟ�V�����`��F��<��V����������������Z��ɠ������l��E�����V���������ݡ����������n��Ġ�o�����y�������������k��������:��@������3��<�����������-������������������������H�����͢�Ԣ����̢����n�����`��F��
��ҡ�ǡ������a�������
��;��
+��:��P��5��?������R��R�S�<S�_S�CS�$S�lS�S�,S�kS��S��S�mS�US��S��S��S�BT�9T�-T�<T�T�DT�wT��T��T�TT�OT�_T�-T��S�rS��S��S�>T�XT��T��T��T��T�iT��S��S�
T�T��T��T�KT�ET��T�bT�ET�JT�;T��S��S�dS��S�mS�`S�BS��R�gR��R��R��R�S�S�'S�,S�US��S��S�?S��R��R��R��Q�R��Q��Q��Q��Q�kQ�|Q��Q��Q��Q��Q��Q��Q��Q��Q�*Q��P�MP�9P��P�
+Q�WQ�WQ�
Q�2Q�Q�iQ�\Q�JQ�6Q�Q�Q��P��P��P��P�$Q�%Q�/Q�0Q�Q� Q��P��P�VP��O��O�P��P��P��P��P��P��P��P��P�bP�eP�uP�eP��P�dP�P� P�sP��P�+Q��Q��Q�QQ�rQ�fQ�WQ��Q�\Q�Q�Q��P��P�Q��P�Q�Q�Q�XQ� Q��P�QQ��Q�bQ�Q�ZQ��Q�hQ�NQ��Q�%R�[R�>R�R��Q�R�R��Q�R�
+R��Q�iQ�hQ��Q��Q��Q��Q�OR��R��R�RR�
R��R�ES�}S�{S��R��R��R�|R�dR��R��R��R�yR�S�aS�S�)S��S�lT��T��T��T�dT�JT�FT�T��S�^S��R�0R��Q�KQ�Q�8Q��Q�UQ�9Q�NQ��Q��Q��Q��Q��Q��Q�bQ�!Q��P��P�Q��P��P�ZP�#P�7P�MP�LP�FP�<P�+P�P��O�IP�fP�XP�*P�P�SP�}P�gP�8P�(P�P��O��N�O�O�eO��O�P�P�:P��P��P�`P�]P��P�Q��P��P�eP�)P�
P�yP��P��P�.Q�OQ�Q� Q�5Q�gQ�nQ�fQ��P��P��P��P��P��P��P��P�VP�#P�9P�yP��P��P��P��P��P��P��P� Q�?Q��Q��Q��Q�eQ�
Q��P��P�-Q�JQ��Q��Q��Q�&R�:R��Q��Q�*R�$R��R��R�jR�R��Q�#R��Q�Q�Q��P�
Q�[Q�lQ��Q�XQ�
Q��P� Q��Q��Q��Q��Q��Q�9Q�{Q� R�^R�\R�R��R�-S� S��R��R�S�,S�9S�7S�
S�XS��S��S��S��S��S�T��T�1T��S�kS�{S��S��S�LS��R��R�+S�S�S��S��S��S��S�mS�jS��S� T�T�T�[T�T��S�FS��R��R��R�cR�SR��R��R��R�
+S�aS�nS�S�S�zR��Q��Q��Q��Q��Q�gR�DR��Q�6Q�
Q�gQ�aQ�=Q�1Q��P��P��P��P�Q�Q��P�KP�UP�_P�)P��O��O��O��O�uO�+O��N��N�O��N�N��M��M��M��M��M�PN�_N�
N� N�-N�|N��N��N��N��N��N�.O�<O��N�N�RM��L��L�)M�M��M��M��M�'N�hN��N��N�@N�N��M��M��M�+N�9N�RN�'N�LN�JN��N��N��N��N��N��O��O��O��O�5P� P��O��O��O��O��O��O��O�?O�@O��O��O��O��O��O��O��O�QO��O�}P��P��P�eP��O��N��N�~N�eN��N�JO�pO��O�P�IP�&P�!P�6P�UP��P��P��P�Q�
+Q��P��P�tP��P�%Q�\Q�NQ��Q��Q��Q��Q�pQ�9Q�2Q�>Q�_Q�aQ�}Q��Q�eQ�OQ��P��P��P�kP�YP�7P�;P��P�bQ��Q��Q�1R��Q��Q��Q��Q�
Q�2Q�gQ��Q��Q��Q��R��R��R��R��R�)R��Q��Q��Q�tR�R��Q�GR��R��R��R��R��R��R�(S��R��R�WR�#R�R�&R�iR��R��R��R�|R��Q��Q�
R�
+R��Q��Q�AQ�fQ�wQ�dQ�#Q�"Q��P��P��P��P��P�OP�>P�=P�4P��O��O��O��O��O��O��O�8O�
O�3O�zO��O��O�FO��N��N��N��N��N��N�tN�MN��M��M��M��M�zM�[M�]M�BM�,M�
M�
+M��L��L��L��L��L��L��L��L�"M��M��M��M��M��M��M��M�}M��M��M��M�PN�
N��M�%N��M�N��M�nM�rM�
N�kN�`N��N��N�O�5O��O��O��O��O�9P�YP�P�0P�bP�KP�7P��P��P�Q�qQ��Q��Q��Q��Q�\Q�mQ��Q�cQ��Q�R�QR�hR��R��R�S�S�S��R��R��R�XR��R��R�S��R�AS�^S�S��R�9S�:S�S� S�US��S�T�T�KT��T��T�pT��S��S�|S�S�tS��S�XT�oT�ST��T��T��T��T�"U�DU�WU�PU�U��T�|T�ET��T��T��T��T��T�
U��T��T��T��T�U��T� U�_U�@U�U�BU�^U��T��T��T��T��T��T��T��T��T��T��T�
+U��T��T�DT��S��S��S��S��S��S��S�US�1S��R�]R�0R�1R�IR��R�9R�R��Q��Q��Q�R��Q��Q�QQ� Q��P��P�+Q�BQ�BQ�*Q�7Q�Q��P�
Q��P�Q��P��P��P��P��P��P��P�Q�vQ��Q�[Q�Q��P�Q��P��P��P�wP��P��P��P�7Q�9Q�Q�Q�Q�Q�sQ�KQ�?Q�;Q�@Q��Q��Q�hQ�'Q�2Q�nQ�hQ�cQ��Q��Q��Q�R�IR�R�
+R�R�R�)Q��P��P�
+Q��P��P��P��P��P��P��P�CP��P��P��P�$Q�Q�QR�yR�ZR�tR��R�JR�$R�R��Q�Q�Q�OQ�tQ��Q��Q��Q��Q�2R�;R�xR�`R�R�,R�UR�dR��R�hR�VR�JR�
R�R�R��Q��Q�R�!R�0R��R��R��R��R��R�cS� T��T��T��T��T��T��T��T��T�sT�]T�T�T�:T�8T�
T�9T�T��S�FT�\T�[T��T��T��T�U�!U� U��T�PT��T� U�7U�SU�IU�aU��U��U�AU�DU�HU�0U��U��U��U�TU��U��U��U��U��U��U�AU�PU��T��T��T��T��T�
U�U�&U�)U��T��T��T��T��T�kT�GT�_T�<T�
T��S� T��S�kS�uS��S�eS��S�6T��S��S��S��S��S��S��S�`S�KS�'S��R��R��R��R��R��R��R��R��R��R��R��R�xR�WR�R�
R��Q�R�#R�3R�uR�R��Q�}Q�XQ��Q��Q�}Q��Q��Q��Q��Q��Q�xQ�Q��P��P��P�Q��P�RP��O��O��O��O��O�P��O��O��O�P�vP��P��P��P��P��P�BP�
P [...]
M�
M��L�?L�KL�HL�QL��K��K��K��K��K��K�L��K�HL��L��L�kL�0L��K��K�L��K�L��K��K�
L��K�:L�kL��L��L�gL�,L�7L�:L�3L�RL��L��L�7L��L��L�^L�xL��L�M�rM��M��M��M��M��M��M��M��M��M��M�N�!N��M�N��M��M��M�*N�KN��M��M�3N�MN�[N�FN��N��N�jN�{N��N�jN�]N�MN�}N��N��N�0N�FN��N��N�yN��N��N��N�O�]O��O�^O�RO�xO�wO�qO�eO�5O��O��O��O�!P��O��O��O�jO�O��N��N��N��N��N��N��N�sN��N��N��N��N��N��N�O��N��N�GN�N�2N�8N�
N�'N�AN� N��M��M��M��M��M��M�uM��M�4M��L��L��L��L��L��K��K��K��K�OK�K��J��J�qJ�}J��J��J��J��J [...]
K��J�zK��K��K��K��K��K��K��K��K�L��K�iK��K��K�L��K�L�=L��K��K��K��K�K�
+K�1K�K�^K��K��K�XK�mK�LK�1K�K�7K�$K�GK�K�K�4K� K�hK��K��K��K��K�<K��J��J��J��J�>K��K��K��K��K��K��K��K��K�sK�(K��J��J��J�K�pK��K��K��K�fK�dK��K�\K��J��J��J�`K�$K�K�\K��K��K�hK�qK�pK�kK�tK��K��K�L�)L�@L�L�;L�jL��L��L��L��L�HL��L�
M�
M��L��L��L�1M�EM�xM�NM�M�,M�tM��M�gM�=M��M��M��M��M�{N��N��N��N�\N�N�QN�;N�%N��M��M��M��M��M��M��M��M�nM��M��M��M�MM�OM�yM��M��M��M�qM�wM�M�M��L��L�M��L��L��L��L��L��L��L��L��L��L��L�oL��L��L��L��L��L��L��L��L��L�yL��L�M�EM�`M�dM�
+M� M�L�L��K�^K��K�L�L��K��K�+L��K�|K�MK�TK�RK�vK�fK�<K�7K��K�L��K��K�
L�L��K��K�xK�3K�K��J�K�
K�
K�BK�9K�K��J��J�wJ��J��J��J��J��J�iJ�OJ�GJ�*J�7J�J��I� J�sJ��J��J��J��J��J��J��J��J�K�ZK�K��J��J��J��J��J�K��J��J��J��J��J��J��J��J��J�?K�EK�_K�7K�SK�\K�wK��K�L�WL�(L�XL��L��L�HL�tL��L��L��L��L��L�M�<M�?M�9M�M��L�6M�BM�$M��L��L��L��L��L��L��L�xL�nL��L��L��L��L��L�zL�NL�L� L��K��K��K��K��K��K�cK�~K��K��K��K�
L�BL�KL�8L�AL�wL��L��L�bL�PL��L��L��L�M�?M��M��M�
N�N� N��M�
N�<N�* [...]
K�K��J��J� K�K�XK�K��J��J�WJ�J�cJ��J��J��J��J��J��J�ZJ�NJ�8J��I��I��I�mI�&I��I�
J��I�J�eJ��I��I�
J��I��I�FJ�#J�*J�uJ��J��J��J��J��J��J�K�^K��K��K��K��K�XK��J��J�K��J��J�K�mK��K��K��K��K�L�L��K��K�%K�{K��K�AK��J�K��J��J��J�!K�2K�ZK�K��J�
K�YK��K��K�3L�kL��L�\L�6L�FL�L�SL�OL��L��L�=M�IM�@M�4M�QM�M��L�(M��L��L��L�<L�L�L�L�IL��L�sL�kL��L�eL�UL��L�zL�nL�QL�L
L$L]LrLkL4LXL;L2LILmL\L[LJLLlL�L�L�L�L�L�L�L�L�LM�L�L�L�L�LQL$L'LvL�L�L�L�L�L�LcL�L�L/L�L�LL
L<L.LL>L LNL?LL3L�K�K�K_K7K�K�K�K�K�K�K�K�K
L=L
L�K�K�K`KbK�J�J�J�JWJYJ�J�J�JKK�J�J�J�J'J�I�I
J#JPJXJ/JNJ�J�J�J�J[J.J'J!J�I�I�I�INJuJSJ2J�I�I�I�IUIeI�IAJuJ�JfJXJCJYJ$J:J<J/J,J]J J�I&JuJ�J�J
K�J�J�J�J�J�J�J�J�JnJ�JsJeJ�J�J�J>K�J�J K>KK�J�J,K�J�J�J^K�K�KqK0K�K�K\KKwKbK$K<KGK=K=KOK�K�K�K�KrK�K\L@L3L�K�K�K�K�KLL
L1L�L�LcL�L MuM�M�MRM
M�L�L�L�L�LL)L%L�K�K�K�K�KbK�K;L�K�K�K [...]
L^L�K�K�KmK�K�K�K�KcKKKhK�K�K�KL�K{K�K�K L�K�KhL�L\LcLL
L9LcL�L�L�L
M0M*M;M'M\MdM)M�L�L�LMnM M�L�L�L�L�LM|MuMvMLMBMjM�M�M�M�MbM MM�LuLFL�K�K;L�LJLDLrLRL|LL�KtKpK�KjK�KL)L�KCKiK�K{K+K*K�J�J�JKKK�J�J�J�J�J`J'JNJ6J�I�I�IlIhI<I�H�H�H�H{H�HII�H�H�H�H�H�H�H�HIiIJI�HrH�G]GjG�G�G�GH>H_H�H�H�HwH�HAH�G�GDH�HyH*HH�G9HXH�H [...]
+IIITII�HxI�I5IIIFI.I7III�I�I�I�IlI�H�H�H�H�HmI�I�IJ J�I�I�IJJJJgJHJJ�I�IJ}J�JsJ�J�J�J�J�J�J�J#KXK'KAK5K KK�J�J�J�J�J�J�JKpK�K�K�K�KtK7KqKKK1K�KLK`K L+L2LuL�K�KXKLK�K!L�KcK�K�K�KBLSL
L?L|L?L
L�K�K�K�K�KL
L�KtKK
KHKK�J�J�J�J
+K�J}J�J�J�J(JnJ^JJ�I�IWI�I�I�I�IPIjII.I�H�H�H�H�H�H�H�H�H�H�HeHFH;H�GwGAGGG�F�F�F�FtF�F�F�F`FdF%FWF�F�F�FG3GLGRG4G G-GGZGhG#G�G�G�G�GzG0G
G GEG�G�GH<H�H�H�H�H�H�H)I%IiIqI]I"I+IAI�I�I�IyJ�J@JFJ/J
JPJwJ6J=J�J�JKLKSK�K�K�K�K�K�KtK�K�KL�K
L�K`KYK�K�K�K�K�K�K�L�L�L
MaM"MuL6LPL�K�KsL�L�L�LMVMM�L#MM=M:MM�L\LAL�L)MMM;M�L�L�L8MEMpMWM'MXMsM[M�M�M�L�L�L�L)M
M'MM�L�L�L<MM�L�LJLlLZL6L7L�K�K�K�KqK�J�J�J�JK�J�JVJ[JuJWJTJ5JJ�I�I�I�I�I�I�I�I�I�I�IoI<IrIvI5IUIkIIAI�I�I�IgIlI|IbIaIgI3III'I�I�I\IRI+IAI�IiI_I`IRI>I�I�ILI
II [...]
+M�L�L�L�L�L`L�L�LELLL�K7LzL
LL*L@L?LHLL�K�K�K�K\KDKYK5K�K�K�K�K}KZK>KK&K�J�J�J�J�JuJaJ{J�J^J8J�JyJ>J
+JJ�J~J�JDJ�I�IJJ J�I�I.I�H@IEI+IZI?IhI}IUI�IAJIJ�IJ"J�I�I I�H�H�H�H�H�H�H�H�H�HvHfH�H�H�H�H�H�H�H�H�H�H�HkH�H-IMIJI!I\IVII{I�IiIgIlI�I�I�I�I�I�I�I
J�I�I<J`J�J^J�J�JgJJ�J�J�J
+K�J�J�J�J�JK
KlK%K�JK�J�J�JK�J�JK�J�J�J�JkJAJkJiJ�J�J�J�J�J�J�J�J�J�J^J}J�J�JJ�J�J�J�J=JHJtJ#JJ�J|J
J�I}I5III�HnI�II�HI�HI
I�HZH�H{H�H�H7H�GH(HDH
HH�G�G�G�G�G/G�G~GoGwG]GQG#G�F�FzG6G�F#G4G�F�F�F�F�F�F�FoF}F�F�F�FSFNF�F�FuFF>FzF�FF�E�E�E�E�E�E�E�E�E�E�E�E�E�E�E�E�E�E�E FF3FXF~F�F4F�EF<FZFSF�F�FKF�F�F�F�F�F
+G*G)GXGYG�G8G=G\G
G*GRG�G�GjGWG�G|G�GH!HsG�G�G�G�G�G�G�G�GH-H�G�G�G�G{G�G�G�G$H�G�G�G�G�G�GH[H+HH1HCH'H&H
H�H�H�H�H�H�H�H�H`H�G�G�G�G�G�G�G�G�G�G�GH�G�G�G�G�G�G~GkGxGpGaGpG�G�G[GWGG7GG�F
+GG
G G�F G�F8F
F F�E�E�EGE+EEE!E�ErEE�D�D�D�D(E�D�D�D�D
+E�D�D�DoD�DkE�E�EQE%E
E0E
E�DE4EE�D�D#E E2E(EGETErE�E
FeF�E�E�E�E�E�E�E�E�E�E�EFKFF-F7F�E�E�E�EHE+E~EtE�E�E�EoE�E�EkEoE�EjE�E�E�E�E�E�E|E�EwE�EyE�D
+E!EE]EfE9E7E#EmE_E�E�E`E5ETE!E�D�DE^EAE~EpEuE�EtEKEME�EF�EzE�EF�E�E�E�E�E�E0F/F�F�F�F�F�F�F�F�F
G�F�F�F4G(GG�FGjGhGnGiG5G3G�G�GhGwG�G�G�G�G
H;HQHhH@HH�G�G�G�G|G�G�G|G8GjG�G&G;G2G'G�F�F�FYG�F�F�FG�FhFpF�F�F�FsFtF�F�F�F�F�F|F�FPFAFdFhF�FuFmF�FGG�F^F�F�F�F�F�F�F�FdFF�E�E�EF#F
F6F`FF�E�E�E�E�E�EyE�E�E�E�E�E F
+F�EmECEE7EJE�EnE#E
EE�D
E�D�D�D�D�D�D�D�D�D�DoD�D�D�DwD�DE>E�D�D�D
E>E E,E�EXEEE
E�D
EEE
E�D�DEE�D E�D�D�DE{E'EE\EXE�E�E�E�E�EZFkF-F)F5F�E�E�E�E
F6F�E�EFFFRFUFLF�E�E�E
FF FF�E�E�E�E�E�ElErEE�ENE'EhEBEE�D�D E
ENEmE�E�E�E�E�E�EF
F�E�E<FF�EtF�F�F�FG@G_GAGjG�G�G�G�G?HIH(H9H�HaHTH�H�H�H�H�H�H�H�H�H�H�H�HzH�H�H~H�H�HJHiHBH/HH`HqHGH�G�G�G]G|GnG#GGG�F�F�F�F�F
FFFF�F.FF+FF�E�E�E�E�E�E`E�D�D�D�D�D�DjD6DFDBDDHDgD(D�DgD?D
+D�C�C�C�C-D+D�C
D�C�C�C�C�CTCPC-C�BfC�CnC�C�C�C�C�C�C|C�C�C�C�C)DHDODcD�D�DJDdD�D�D�D�DND�C�C
D�C�CkD�D�D�D�D�D�D�D�D$D�C:D�D�DD/D<DD0D DEDwDoDhD�D�D�D�D�D�DEE#EzE�E7E8E�E�EFFAF5FLFF�E�E�E�E�EoE�DEE
EiEjEBEmEKE\E�E�EqE>E{��������������������������Y�J����?�G�_���u�������������[�U�w���`���
�i�o�A��������+��
���S�
�* [...]
�����C��������+��0�T�o�'�F�n�6�����������������7�#�'�#��"�����e���������������H�`�������������������P���x�u�s���w�c�*�p�G�K�W�
�����������j�����g�{�������������i����W���-�f�����x���_��5�X���j�&�(�Z�B�A���q������<�I�l�U�#�Q�9�.�Z�Q�+�T�_�Y�o���L�5���B�
����������"�{�����������E�E�����<���b���t�����
+���)�����2���d�Q�����������{��������~�~���&�b�>�����a�"�E�~���@�
�A�a���s�������B�d�����X����������/�#�_���G�D��� ����������������������¿����[��
+�9�(�����ɾ
�N�e�����ڿ�+�����������[�y�W�Z�R��������
�j���'�����������@���������U����
����������������\�`�����d���@�����f���������W������I�V�K������ �����8�J���:�D�P�K���
+���������[�����1�������7�z�s�-�#� ���c�C������
+����������������"��?�����O�G���������q�U�A����������u�Q�y�����]��������N�#��� �K� �������������G������f�}�[�K�/�����U���8�4�����j�W�m���
+����������N�Q�e�}�����:�A���������i�K�-�@�o����� ����������������`�l������:�|�n�����
�]�
� �������f�����w���?����������&���0�$�
��)���
���P�b�c������(�����o�`���q�L�Z�.�n���~�J���5�"���2���(�����^���������A���Y�9�r�m�5�Y�^�d�����
�V�i�������w���h���A�e�!����h�k�0��������������%���������J���|�k�
���������K���� [...]
�+�1�����%����i��K�������������`����=�K�K��H���O����%�������b�f�K��������1�Z�d�������������$���������������������������s�w�Z��W�������
����7�Q�/�@�/�1�t�~�Q�]�s�8��������������m�v���h�����"����{�@�
+�
��[��O�����L��K�+��,�F�0��/���������������������[�^�0���������w�>���h���������������o�c�q�����w�/�ǿu�!�G�G���6�c���O�����Q�����9�
��=���6�9�,�
����Ͼ������ �\�ۿ���������������Z�r��,�d�%��`�����)�E��I�T�=�:��)�3�l�U�<�+�d�f�������a�3�s�����k���������������������������'���������w�����+���������������/�|�q�s�F�� [...]
�2������þ����������P�j���~�k���
�I�r�u���ֿ�#�ֿ��������ٿ��{�Ŀӿ���ڿ˿����ɿп������d���ڿh��q����������ݿ��g�������w�u�����C�־����� ��)��j���п��^���;�E�?�V��� �M�c�V��� ��������9�п������п����t�������������%����������������+�w�_������k���^��G�N�����p�c���
�����8�8�z���n�j�7�+� �������f�u�8�U���J�U�K�]�����X����������H��B���T�N��ؿ���E�s�Q�`�i�l� [...]
+�
�=�l������������9�E���]�(���
�G�V�H�H�-�7��S�*�/�]�J���������v�Կ�*�(���T�f�
�����n�|�������Q�T�.����'�p�B�#�� �9�T�8�]�'������O�{������d���F�H���|�L��������@�6����������������������������A�����&�4������(������}�������%������T�[�B�[�;�������7� � ������ �����������������"�
������m�K���z�P�
���u�[�\�3�%�<�#�(� ��T�
���+��������9�������Ͽɿ�����Ŀܿ*�5�h��ٿ���پN�������o���L�-������Ⱦ �#���p�(��B�/�.�C�g����n�d�5��G�H�X����������^�ſ��|�a�p�����0�������;����¿?�/��� �ɿ��ӿ�"�>�B�5�F�D�T�����
+�"�����
�G�����"�f����� ������x���w�����[� �)����N�u�����������v��������x�����D�����e��?��[��]��Y��}�����2�����^��E��������r��������������W�����u��
��������������� ��/�����S��g��7�����o�����������������d��-����������������������&�����-��l�����������������c��������������������������*��/��������#�����Z��������'��K��������������f��������������U��#�����v��Y��M��y�����}��S���������������3��S��C��������z��2��\�����������Q����,��H��i��
�����������������������Y���� [...]
��������;��f��0��e��$�����������h�����������.����� ��G�����<����,��������A���� ������������������������������������=��������s��|�����i��q��b�����S�������������^�����S�����A��D���������������B��������$��L��@�����
��F��!��9�����������6��J��k��������N���������������������������������e��w��E��Z��j��K����n�����t�����������������3��m��?��)����
�����{�����i����&��9��^�� ��
����x��������������������:�������W��D��#��������s����������B����������d����������t��^��t�����n�������U���� [...]
+��'����h����:��a��X��n����������w����B��K��C��������������q�����������n��������A�����T����������-�����
+��K��v��r�����������/�����=��#��%��0��+��c��������������������C��������l����v�����������X�������'��������d�����0��^��������������d��������������������������.���� ��9�����r�����a��2��)��/�����������*��3�����u��������������f�����m�������������,�����y��O�����������)��������m��e�������������������L�����������Y��2��|�����������������������������������������Z��������/�������������V��������������������+�����"��Q�����\�����3�����C��P�������+��������
�����������������.��5����������"��S�����
��r�����
+���������N��}��/��x��������������������q�����������������R�����������9��z��
��������k��������J�����1�����
������X��t�����������S��������&��<��4��-��,��H��6��������������H�� �����������������5�����V����� ��C��l��/��������k��3��[��2��v��s��x�����7��������������������������'����������I�����6��V��)��������L��+�������[����� ����!��'����
�����C��S�����U�����3��������O��v�����������P��'������������������
��@����������0��u�����������W��-��������������m����p�����U��,��������t��C��R����d��M��3�����F��R�����H�����y��o��a�����������
��������W��J��%��C��l��V������ [...]
+��������[���������������8�����(�����������G��������������`��s��{��T��������������S��7�����������~��.��w��������������������*��d��[��������
�� ��������q��>�������������2���������8��f��������������N����h��G��������p�����������5�����D��a��H��D��<��������-��������������c��������������������t��)�����`�����E�����>��Z��
�����4��l�������m��c��&��S��G��Y����������������V�������"����������������������v��{�����z��������������H�������������C�����o��������$�����W�����������������������F [...]
+��^�����:�������������~������������������������,������������������I����
��e��������x�����������
��z��������H��������������M���������������������6��E��l��I�����l�����5��j��:�������U��������&��+��������������Y����q�����������I��������.�����m�����i��������e��������W��:����x��������
��5��:����������0�����1�������;��Z��R��������������(�����R��v��;�������������������������������������+��:��C��>�������
��C�����������������R��X��-�����!��X�������B��*�����p��@��%����T��T�����) [...]
�����v�����������������������L��>��D��b������������
�����������W��
�� ��<��1�������������?��������]�������b�� �����m�����Y��_��������Y��m�����g�����n��D��(��������z��������B�������������!��8��x��~�������X�����7��
�������Q�������������������C��������������?��������������������Z��;��<��V��������^��O��������B��^��W�������������V��������������q��b����c�����o��������c��7��g��������������e��C��y��������Z��4��.��t�����-��C����������2��H��g��Z�����5�����`��E��
�������A��^������������� [...]
��A��u�����_�����g�����
+��x��������������������������������������V�����������R��y�����y��e��L��S�������K�����i��9��Z�����������U���������0�����������������[��i��c�����-��p��v��~�����6����M��}��A�� ��
+����������[�����0��q��B�����0��D��>��7��E���������������������u����������������L��;��e��������%�����������������������������.��������7��w�����������.��t�����f��f��V��+�������
+��L��������������������Y�����������������������b����������9�����3�����������{��|�����
����
��D�����n����������?��I��R��l��e��~��9��������D��
������%���� �����������R��C��i�����?��������E�����G��'��r����������b�����������Y��\��e��~�����h��A������%��������
��.�����<��������&����������������������
��������'�� ��������������������-��e��s�����\��������v��������p��
����
+������9�����s��@��.��O�� ��!��5�������C��~�����x�������������Q��'��)��?����������"��d����������������A�����������������X��S��K�����������������M��M��?��?��\�� ��������y�����+��\�����X��������p��l������������� ��I��}�����G��#��2��������D��d��R�����*��������]�����J��9�������������������^�������*��&�����Q�� ��������������#��������������������������������M��������.��a�����
��e���������?�����@����������.����Q�����8��?��������������p��
+�����=��N��d��l��]��R��t��������������
����������������^��2�����x�����A��N��X�����������z��K��������������D��J��G��B��f�����Z��?��W��Y��=��b��d��[��,��������������|��n�����������������
�������8�����`����������u��j��������������<��
����������������������h��}��~�����4�����$����������������=��������������������
��t��������Q�����W�����������p��������k�����������L�������t��K�������|��U��!��*������������������������������������H��x��4�����+��������S��i�����4��������������>����������l��������7��������6��
��:�������������$��!��7�����m��FT��S�'T�lT��T��T��T��T�&U�V��V�W��V��V�V��U��U��U��U�
V�V�V�qU�U�U�$U�U��T�FT�oT��U��W�Y�NZ�8[��[�![�.Z�Y��W��V��U��S��S�OT�U��V�`W�OW��V��U��T��T�U�IU��U�"V��V�WW� W��V [...]
Z�ZY��X�BX��W�rW��W��W��W��W��X�Y��X�QX��W��V�uV�
V��U�^U�,U��T��T��T�U�
U��T�[T�"T�lT�U��U��U��V�8W�W��W��W��W�;W�[W�HX��Y�~[��[�'[�%Z�
+Y��W��V��U��T��T��T��T�~T�?T�IT� U�RU�U�nT�zT�~T�DT�@T�T�;S�JR�SQ��P��P�pQ�rR�1T�gU�V��V��V��V��V��U�3U��T��T��S��R�.R��Q��Q��Q�|Q�Q�
Q�%Q�Q��P�dQ��Q��Q�8Q��P��P�ZQ�JQ�AQ�fQ��Q�+R�lR��R��R��R��R��R�eR��S��U��V��W�$X�9X��W��V�
V�dU��T��T��T��T��U�VV��V�
W��V��U��T�WT�`T�T��T��T�IT�2S��R��S��S��S��S�CT��T�/U�tU��U�V�[V��V��W��X�6Y��Y�Y��W�1V�
U�ET��S�3S�!S�[S�S�|R��Q��P�aP��P��P�^Q�ER��S��S�S�)S��R��R�nS�,T�qT�vT�`T�T�<T�zT��U�yV�&W��W�X�9X�ZX��X�tY��Y��Z��Z�[�kZ�7Y�bX�X�
X� [...]
V��V� W�rW�QW�]W�PV��U��U��V��V�?W�dW��W��W�X��W��X�ZZ�x[�E\��\��[��Z��Z��Y�Y��X�dX��W��W�YW��V��U�OU��T��T��T�KU��U��U��T��S��R�2R��R��R�>S��S�{S�{S�T��T�U�kU�zU�<U��T�U�rT�T��S�kS�US��S��S�T��S�JS�S�zS��S�DS�T��T�U�zU��U�V��U�U��S�S��R�`R�gR�[R�_R�VR�uR�}R��R��R�-R��Q��Q�>R�_R�+R��Q�-Q�vP��P��P��P��Q��R��S��T�rU��V�!W�vW�
W��V�FV��U�kU��T��S��S��R��Q�CQ��P�Q��Q�xR�AS�`T�`U��U�)V��V��W�PX��X�?Y�XY��X��W�?W��V��V��W�X�$X�dX��X�xX��W��W�*W��V�qV��U��U�FV��V�>W��W��W�+X��X��X [...]
Y��Y�%Z��Z��[�\�'\��\��\��[�E[�J[�[�[��[��\�P]�!]��\�*]��\�V\�.\��[�T[��Z��Z��[��[��[��[�i[��Z��Z��Z��[�^\��\��\��\�]�:\�f[��Z�
Z��X��X�hX�X�[X��X��Y�,Z�gZ��Z��[��\��\��[�0Z�
Y��X��W��V�RV�QU��T��T��U��U��T�LT�>T��T�VU��U��U��U��U��U��U��U�KU��T�uT�`T��T��T�zT�rT�?T�6T�HT��T�(U�$U�1U�AU�wU��U��V��W��W�@X��X��X�lX��W��V� V�V��V�fW��W�DW��X��Z��\�']��\��\�\��Z��Y��X��W�uV�&V�(V�$V��U��T��S�mS�:T��T�~U�0V�V��U��U��U�DU��T��S�[S��R��R��R�S��S��S�T��S��S�~S�8S��R��S�OS� S�qS�T�*U��T [...]
V��U�&U��T��T��T�tT�FT��T�WT��S�
T�5U�V��U��V�_W�:W��V�3V�EU��T�xT��T��T�2T��S�JS�
S�7S��S�T�`T��T��T��S�S��Q�)Q�2Q�Q�Q��Q��R��S�:T�hT��T��U�8V�DU�U�U�wT�^T�jT�?T�wS�'S��R�IR�R��Q�Q��P��P��P��P�3P�
P�?P�$P��P��Q��Q�3R�;R��Q��Q��Q��Q��Q�YR��R�6S�dT��T�CU��U�V�+V�3V�1V�,V�V��U��T�jT�T��S�OS��R�+S�oS��S�AT��T��T�KT��S��S�LS��R��R��R��R��R�S�gS��S�hT��T�zT��T�U�
U��T��T��T�/U��U��U��U��U��U�2U�U��T��T��S��S�T��T�VU��U� V��V��V��V��V��V�.W�NW��V�V�SU�(U��T��T�dT�~T�
+U�=U��U��U��U��U��U�XV�W��V��V�MW�3X�,Y�0Y��X��X��X�TX�mW�2V�rU�aU��U��U��U�NU��T��T�eT��S��S��S�S��R��Q�;Q��P��O�0O�O��N�O�NO�hO��N�vN�MN�IN��N�NO�8P� P��O��O� P��O��O�P��O��O�6P�lP��P��P��P��P��P��P��P�:P�P��O��O��O�VP��P��P�wP�]P��P�9Q��Q� S��T�V��V�.W��V�oV�tU�~T��S�ES��R�JR��R��R��R�
S�-S�S��R��R��R�CS�/S��S��T�lU�FU��T��S�S�NS�RS��R�R��Q��Q�ER�)R��R��S��S��S�T�T��S�T��S��S�wS�zS��R��Q�AQ��P��P�;P�P�P��O��O��N�N��M�{M�_M�fM��M�wN��N�JO��O�P��P��P��P�CP�P��P�0P�>P�
[...]
+S�%S�dS�mS�S��R��R�
S��S��S��S� T�
T��S� T��S�5S�?R�BR��R��S�eT�xT�?T�XT��S��R��Q��P��P��P�BQ��Q��Q��Q��Q�BR�lR�vQ�yP�GQ��R�2S�6S��R�R�/Q��P�%Q��P��P��P��P��P�}P��O��O� P��O��O��O��O�VP�@P��P��P��Q��R��R�aR��R��S�<T�U��U� V�=U�0T�ES��R�R�AQ��P��P��P��Q�:R��R�S�ZS��S�TT�KT��S�RS�sR��Q��Q�NQ�/Q�ZP�O��N��N��N�5O��O��O��P�WQ�gQ�Q��P�Q�
+Q�QQ�|Q��Q��Q��Q��Q��Q��R��R�uS��T��U�V�yV��V�6W�GW��V�(V��U��U��U��V� W�
+W��V�;V�:V��U��T��S��S��S�jS�3S��R��R�jR��Q��Q�XQ��Q��Q�R�&R�R��Q��Q��Q�%R�qR��R�
S� S��S�wS��S�UT��T��U��V�\W�XX��Y�@Z��Z� [�~[�9[�yZ��Y��Y��X�
X��W��W�FW��V�V��U��U�#U�{U��U�U�qU�QV�W�W�@W��W�rX��X��X�OX��W�W�IV��U�DT�eS�{S�|S�lS��S�0T�T��S�*S��R�.R��Q��Q�*R�R��Q��Q��Q��Q��Q�R��Q��Q�
R�IR�lR�vR�GR�R�@R��Q�=R�%R� R��Q��Q��Q��Q�6R�CR��R��S��S��T�yU��U��U�9U�:U��U��U�U�QT��S��S�S�@R�QQ��P�?P�ZP�9Q��Q��Q�oR��R�vR�eR��R��R�
+T� U�U�zT�vS�xR�jR��R��R�<S��S��T��U�0V� V��U�2U��T�5T��S�!S�hR�xR�YR�fQ�\Q��Q��R�VS��S�S��R�S��R�fR�=R�\R��R�uS�3S��R��R�WR��Q��Q�R�IR�hR�<R�R�IR�2R�R��Q��Q��Q�SR�@R�yR�S�
S�|R��R��S��T��U��V� W��V��V�&V�`U��T�,T�fT�WT�NT�=T�<T�'T�4T��T��T��T��T��T��T�;U��U�BV�?W����������z��^����~����������������������B��F�����x�����[��k��i�����%�����(��������m��������������O��o�����Y�����D��T��P��m��*��K��*��������
�����p��������h��z��M��e�����A��u��Q����P��������������S��7��s��y��o�����
+�����/�����7��,��|��������������������i�������J��������]�����K��?�����M��������}�����������,��}�����m��F��������K�����������������������
��6��/��G��S��a�����t�����!�����j������������M��}�����C������������y��@�����!�����3�����*��)��������t��}��$����������F��������v��q��S���������������c�����������]��U�����`�����$�����`�������������X��~��������������d���������������������������������w��������|����������������������'�������������f��2�����N�������
��!�������� �����J�����c��7��� [...]
��j��������s�������+�����b��E��p��t�������z��:�����<�����������z�����[��������`��������Y�����������������X��k��`�������������y��N��o�������������������X��������
�����f��
��F�����]�����2���������T��������X����k�����������
��E�����$��������%����������
��4��^���������������������������'�����������S���������������~�����8��������Z��!�������������i��b��]�����������������i�������������o�����n�����_��`�������e����������������l����� ��%����e����������������������9��������>��v��W� [...]
��d��U��C��3��M�����S����������B��8��}��p��'��������������������D��M��������������������a��M��������[��:��l�����!��(�����.��r�����z��]�����A��X����������\��H�����������X����
��������
��&�����z��D����������������������.������#��H��8��B�����������;�����������U�����
�����J�����z�����b����<��'��b�����%�����
+��n�������������������������������%��4�����%�� ��{�����b�������������'��$����m��������F��L��:��������?��#�����������W��������������l��B�����
��j����������]��
�����������������������!��
+��
�����������������������}��p�����f�������@�� �����������1��Z��v��q��������
�����B��*��������{�����������>�������l��w����������������p������������I�������������+��A����������������<��>��^�������������b��������g�����l�������^�������������������!��
��!����������������������������������3����������q��������V������������������T������������������� ��;�������������x��������������R�������z��������������������3�����v��3��p�����Z��O��
+��Y��Q��f������M�����R�����������������L��������$������������������4��������4�����_�����y��
��U��X���������� ����>�����7��(�������b�����:��A��z��������������*��������������
������������������\���������������X��n��d��*��D��������x��H��5��t��F�����}��R��r��Y���� ��_��;�����p��������h�����R�����"�����������������R��������������]����������������R���������������������a��F��Q��,����
��/��������i����������������b�����_�����>��0��������8��K�����b�����k����|��W��������<������ [...]
+�������}�����5�����B�������3��r����������w��<�������q��T��"��Y��x�������*����������������A��m�����L�����������b�����,����w��������������"��o��#�����q����������X����/��R�����������@�����������������{��������f��r����]��e��<��������������C�����}�����1��k����������m�������p��7�������������:��]��y��/�����������O�����e��L����������
+��8�����������z��D�����������N�����X��:��
��������k�����W����������
�����M�� ��������(��w�����
��H��&��a��n��V��^��B����)�����
��H�����W��A��������M��%��,�����a��e����������?��8��G��
��\��}��p��C��������!��8��h��;�����������x8>8�7�6_6�5$585l5=67�7�7�6�6�6
7K7g7�7^7�6W6�6s6/6D6�5,5,5d5�5d5�4�4`5{5�5�5�5m5V5�4�4�5�5�5�565}4�373-345�4!3�1�0//(.�-_.$0�2�4�5�5Z5�57�7�7�7c7�6�6�6�6*6>5r4j4h4`4�4B5�5� [...]
+3 3�3�4H5<5<5�4�4]4�3�3p3.3/3�2 2V23�3�4N5�5�5-6
6~5�4�3
3�1*0�.4.�.�/2�4�5A6�6�5�4�4c5�6�7�7�7@8M8�7�6�55)5�4�4�4�4�5�5@6�6�5�4�3]2�0�///�/r0�1�2�3�4b5�5c6�6?7T7x7�7$7�6�6'6*5�4�4>5u5�5�5�5�4�3�3�3�344D4<4F4
4 4�3�3I3�2�2�2'3�3�34�3�3�344�3[44T3G3�2�2�2i2�1*1,11�0�0�0'0�0�1221�/�.�. 0�1�2D3�2d1�/�.S.b.w/
1?35�6� [...]
4�4r5�5S6�5�5�44�3y383 3�2�2R2�11{0H0�0�1\2�2\3{33�1�0A0t/V.�-�-.�./H/�/�/D/�.�.6/�/)0p0~0e0�/�/�/�/�/ 0q0�0z0/0�/�/00�/0�0
1 1�0�00
0�/Z0�0�0611�0�0�0�/�/D/�../�/}0;1�1�1
2�2�22�1�0�.�-�-�- /�02�2�2�243A3�3E4
5�5�5636J6Z6&6�6�6�6�6[6:5
4�2P1j1M2@3r4 6m7�7H7A77�6!6P6�6�6�6b6R6�6\6�5}5r5�4G44�3�3V3�2�3�4�5=7�7�8�8�8�7_7F7�7�8�8+8M7R6L5�4�4�4�4�4I5�5{5G5�5K6�5\5T4p3�21�/`//�.�../E0�1
34:5�566m6�5�5�5R5�4�4�4�4�4
464?4Q4P4(4�3�3L333�3�33�2�232�1�1 [...]
+,�+e+�*v*�*A+�+p,-�-�.�/090q0g0'0�/�.|.�.y.G.�-�-�-k--j,�+
+�*#+o,�-�.4/b/*/�..�-p-�-:..�-�-]-0-�,�,T-:.�.�.�--U,, ,t,�,
-�,,%+d*�*f*�*�+V,?-�-$--
+-�,�,},�,�+,+,�,w,�+U+=++�*�)�(�()�(�(.)�)d*�*�*f+0,],>,�+�+�+*+/+�*�*�*�))�(�'e'O'�'7)w*�+P,x,;,.+<*�)�)P*+,�,w-�-�-O-�,-�,�,
-�,,�+l+�+�+�,�-�./ //�.i.%.�-e-'-�,�,h-�-�-�-�-�-�-'.�-I.^.0.�-7,�*�)�(�'�'�'�'(�'�&�'�)�,s/72x3]3�2�1@11�0�0�0�0�0�01�0�0�0�0�0�0�0�0�0�0�0S0 0�/�/0�/�/�//.�,�+�+�,�-�.�.d.2.b..�.K/� [...]
/P.�-�-E--*-�,d,�+�+[+�+�+b+m+�+�+Y+#*�(
+(�&t%�%�&D)�+}-/L///�.V.%.r.~.x.�.�.�.C.�-P-"-�,L,v,f-{-�,,�+�+,R,�,-�,:-�-<.�.�._.2.].Z.�-�-E.5.�-<-l,�+�*�*�*++,-�-�-�-�-�-�-.�.�/n0[00
0�/v/j/=/@/#/�..�.�.g.D.�.P..%.�-�-x--�,9-�-~.R/A0�0�000�/�/�/]/�/�/000�/./1� �� P� �� � � �� �� n� �� �� y� M� m� P� <� |� �� � �� �� �� � �� e� � � g� �� I� �� �� �� �� �� �� �� Q� S� &� �� t� �� � Q� �� �� �� �� � [...]
�
� K� � �� �� �� �� � f� �� 8� � "� .� (� >� =� � ?� � � 6� &� S� �� � �� n� �� ��
� `� J� ;� �� �� g� �� z� �� �� f� I� %� � w� �� %� F� �� � !� �� � V� �� p� �� �� �� � @� 6� |� � �� �� 1� �� �� �� 1� � �� M� �� "� �� �� �� �� �� U� �� � �� � �� �� �� � �� N� )� �� �� m� �� �� 0� �� Y� �� W� 3� �� � �� +� �� �� �� �� �� �� �� V� �� z� {� �� �� e� �� �� i� #� �� @� ^� �� �� �� �� �� � n� �� �� �� u� �� �� �� >� A� � �� �� �� 4� $� �� �� }� �� &� � �� +� �� 2� � )� K� �� �� L� �� �� o�
� �� �� �� �� �� �� ]� �� �� �� � �� �� �� �� �� � �� Y� �� �� k� �� �� �� �� �� �� �� 7� Q� �� ?� �� � �� �� �� �� �� �� �� �� =� �� �� �� z� 1� v� �� �� A� �� � _� x� �� � � �� � �� �� E� �� X� �� � �� �� j� � \� 0� �� "� � �� Y� R� m� �� �� 6� �� �� H� y� �� 0� �� �� �� p� $� 8� i� d� <� :� )� ,� �� � � P� F� n� �� �� �� �� �� �� �� m� �� �� �� �� �� �� p� �� 9� �� �� W� k�
+� � �� �� �� �� %� >� <� A� 5� �� �� �� �� �� ��
� "� �� 5� �� � Q� Q� l� �� �� �� �� r� �� �� #� �� �� �� '� � T� ,� m� �� �� R� �� �� �� k� �� � � �� +� b� d� |� u� �� �� �� �� �� =� � �� +� �� � � B� l� |� �� �� �� �� w� �� � C� 2� A� �� J� �� �� y� t� j� ?� �� ��
� �� � �� �� �� �� 3� j� �� B� �� p� �� ,�
� �� �� �� �� �� �� � �� � L� �� /� w� �� �� �� i� D� ?� �� @� �� �� d� �� � %� 3� (� � �� �� �� � "� 7� �� �� *� =� � �� �� g� O� a� �� �� �� � � >� �� W� �� �� 7� �� � � D� �� $� J� $� �� � � �� 4� ;� <� K� �� �� �� �� `� �� \� � �� �� '� Q� �� �� � �� �� #� �� �� �� 5� � Q� � �� C� �� �� &� �� =�
� �� � �� �� B� _� 6� =� �� �� �� � +� *� �� �� D� f� �� b� �� � �� N� �� U� �� �� �� @� !� -� �� �� �� %�
� �� 9� �� �� � ~� �� Z� R� o� p� �� �� M� �� [� �� �� [� a� �� C� �� �� �� :� �� �� �� �� �� �� �� ��
� U� �� � .� 7� �� k� 3� � �� r� k� �� '� y� �� �� D� �� X� �� �� �� \� l� �� �� �� m� � 4� �� �� �� �� ,� e� � �� :� �� � �� � �� � )� �� %� V� T� `� T� �� �� *� �� �� �� 8� �� �� ;� � �� p� �� Y� �� �� �� � �� �� � �� �� � �� �� �� �� W� �� ^� �� �� 7� �� �� �� � [...]
+� �� q� m� z� O� � � �� �� #� �� �� g� *� �� %� `� �� � 1� �� �� �� T� �� �� �� �� w� c� �� �� �� �� �� �� � �� � �� �� �� �� �� '� � �� C� �� �� �� �� � <� �� A� �� i� �� 4� �� �� |� @�
+� �� �� � �� �� k� �� �� *� �� ~� b� a� �� �� (� �� _� �� �� P� )� �� �� i� �� 1� 9� �� �� �� �� [� '� =� C� V� �� )� � &� R� @� x� �� %� �
+� � �� �� �� �� u� � *� j� �� � �� �� �� ��
� �� �� �� }� 5� �� �� � �� =� `� >� "� D� �� �� A� t� $� Z� �� ��
� �� �� �� � �� C� �� m� �� �� �� j� �� �� �� �� +� {� *� (� �� �� �� �� �� b� ,� \� ,� d� {� �� �� �� P�
+� %� .� R� �� 5� �� �� X� �� �� � �� _� �� 2� +� p� +� �� �� b� �� +� �� k� �� ,� g� !� B� �� {� [� V� /� o� B� �� � S� � 4� �� �� �� �� @� � V� z� �� �� � �� �� )� U� a� �� U� �� � �� �� *� �� �� �� �� �� Z� v�
� "� �� u� t� �� �� �� �� }� � � �� N� [� �� �� �� y� n� � '� �� � � y� �� �� 9� `� |� _� �� �� *� � >� �� �� �� �� �� h� �� �� �� �� �� F� �� �� �� � J� �� ��
� /� D� L� z� q� �� D� �� �� �� �� �� C� W� �� ��
� � g� �� P� �� %� #� M� e� �� �� �� C� �� �� �� �� �� �� �� �� �� �� K� f� �� �� s� �� � �� �� �� �� y� 8� q� W� �� �� [� "� ~� e� .� �� �� �� �� �
+� ~� (� � K� �� �� �� �� �� � �� �� �� t� ^� L� >� � �� �� �� �� ��
�
� 1�
� �� e� �� >� V� �� �� � �� �� � ?� E� &� �� �� �� �� +� � N� '� r� ,� /� �� �� d� �� @� =� �� i� @� � � '�
+� J� d� �� >� �� V� �� H� �� � 2� �� �� �� �� Q� � � t� �� �� E� y� �� $� �� �� �� �� L� � �� �� �� �� �� � [� 8� �� �� q� 4� �� �� f� y� �� F� � �� �� H� q� �� �� `� x� G� �� �
� � "� 1� �� � �� *� �
� X� g� �� �� �� �� � �� m� A� � �� g� �� �� �� �� j� � ��
� �� H� �� �� �� 9� �� +� X� 0� �� T� y� �� 2� �� �� �� �� ��
+� �� !� � �� �� �� T� � b� e� x� }� R� f� �� ��
� �� �� s� W� <� 3� �� � �� �� R� f� � T� �� �� �� �� k� C� r� �� � �� �� 2� U� N� � �� �� c� E� �
� �� !� �� �� Q� [� =� .� ?� �� �� �� ��
� (� 9�
� �� ��
+�
� �� �� �� g� J� 7� $� �� N� �� �� J� �� `� �� � �� j� G�
� P� �� �� �� z� !� �� �� �� �� ~� �� L� �� � � � +� � ��
� � )� ��
� � �� �� ��
� � �� � �� �� � ^� �� �� �� �� � 5� U� �� �� }� $� � �� O� �� �� a� .�
� t� �� �� � h� � (� �� O� � �� f� l� �� �� {� u� s� �� �� /� �� �� �� � j� U� 5� �� 5� h� � O� 7� W� �� :� �� �� l�
� a� �� �� �� �� �� �� �� �� �� b� �� �� a� �� r� ]� �� �� }� �� g� � �
� L� A� �� �� �� �� �� b� � �� �� �� � �� v� y� �� !� �� �� [...]
� _� �� �� �� �� S� ��
+� I� O� ~� ;� 1� �� �� \� �� �� �� �� �� �� �� �� �� [� � �� l� �� �� �� �� �� �� h� �� �� r� ^� �� �� �� �� �� �� n� � )� � �� {� .� � 7� �� �� >� �� a� �� �� � �� �� I� $� �� �� �� ]� �� �� �� �� �� v� �� ]� K� � �� �� �� �� �� L� �� b� 6� �� E� �� �� �� �� �� �� �� �� �� S� )� � �� �� �� �� ;� O� �� <� ?� � �� � %� �� �� �� ;� � �� �� �� �� �� � C� �� �� �� v� T� �� �� �� �� �� �� �� �� �� �� �� � x� �� �� �� N� �� )� � (� � i� D� l� p� ,� B�
� � �� �� �� �� !� � �� � [...]
�������� ��������t��������������e��{����������������������J��'��������I�����z��������}��c��X��;��������^��z��E���������������Z��������K�����Z��+������3��K��+��B��-��B��������������D��������x��������������}��
��0��������w�����������������X����2��'��������:�����������G��O����������~����������C��W��V��������h��Q�������������N��������x��U��"��[��������k��T��0�������(��=��a�����0��������������������������U��+�������E��������\��J��z��������������/�����C��r��`��#��z��k��6�����C������ [...]
+��;��:�����������a���������������A��j��D�����5�����'�����������������������������V��k��]��'���������������������4�������� �����������1��K���������������,�����r�����������-��3��?��~��������������c��V����������T��R��(��B��u��}��������Q�����
����0�����
�����������9�������������������v��v��|�����-��������>��u��u�������\��e��v����[��
+�����+�� ��Q�������5��������������������}�������x�����D��������L�����h��������?�����������������������p��O��s��h��,����+��J��������������������������W�����s�����������T��������������%��
��b�����y�����������T�����������c��9��������
+��-��
����������������������������������������n��9��O��L��0��[�����q��4�����������������Y��'��X��u��5�����U��H��|��������������x�����������G��;�����,��p��������P�����������������������������������������@��������;����������C��v����n�����������w����������x��������$��������n��������{�������
��^����������
������������{��b���������������>��D��(�� �������������U��&��+�����������������������6�����r��V��B��(��2�������$����$�����������������4�����G��������������������������������������
� [...]
�����������?����O��������m��p��S��h��A��������������������6��-��U��Y��[��}��k��i��c��2��K��������������������~��{��������������Q��d��0��������5��`��������Z��W��������
+��������W��/�� �����Y��#����<��j����������O��<����S��9��j��b��������E�����Y��,���������Z�����M��$��[�����������~�����h��
��������������s��.��r��X��������$��H��������.��S�����������������n��"�������������q��]����������������������������h������� ��-�����f��f�����"�����������������y��>��A��M��:��\����������
����������f��4��D��������I�����|�������
��.��h��\��7�������������������x��n��#�������
�����������u��U��b��r��x��M��J��x��������Q�����h��S��
���������������������m��[��p��j��$��@��B�����������h���������������������������
��=��������������l�������������������������������������������������� ��������������M��~��������������_��N����2�����]��;��3��7��������
����
����������s��]��
�������� ����������������(��u�����Z��#�����������������������������q��q��^��]��B�������)��O�����
��.� [...]
+����3��l��z��`�����}��c������������������������������������Q��n�����������������(��@��T��B��Y��k��7�����B��;��H�������W��f��w�����������������T��R��[��d��q��������������������k��(�� ��������;�����������x��n�����������S�����R��c��L��������������������������+����3��
��-��k��������D��&��&��n��������������
��u��u��F��/��:�������������������������������������������G��p������� �������|��k��J��j���������~�����������`��a��b��@��1��6��+����'��(��>��
+���������������������������������������0��9�� ����<��
����������������r��T��~��������������������'����ÿ�¿�ѿ���v�����������'���������������������������� ��7�� ��d�������������[�����h��+��+��u��d��^��������V��F��{����������������q��}�������������� ��H�����������������i�����������U��������E��
+����������������������r��J��3��V��
�����������
+��������������������������������������������H��[��8��+��2�� �����+���������2��)��W�����y��|�����������������r��������������2��T��|����i��O�����?��=��������&��
��*��O��z�����X��%�����������������4����2��������C����&��տ�����������[��z��������{��w��������
����
��&��g��:��&�����'��j����������������u��%������������� ��]��l��\��h��\��f��g��L��m��~�����Y�������������������Q�����D��R�����������b��(��P��q����������������������������f��=��a�����������������x��������'��"�����a��b��; [...]
��=��)��z�����b�����������������(�����I��C��\��f��������������������������������g��4��+����%��4��7����������
��#��d��������������{��;��g�����1�������������m��������e��,��������Q��?��X��?��8��>��0��?��������E�������������������������{�����s�������������%��G��>��������"��,�� �����m��c��z��������@���������������������������������������
�����
+��������X��W��N�������(��������������������������������������|��.�����A��������������n��s��!��������������E��M��������������z��\��F��V��h��r�����y��Z�����K��3�� ��9��|��Q��?��>��������A��2�������C��R��W��������A��'��3��%����E��������������.�����������������������S��j��� � #� 9� j� W� � >� Z� {� g� n� &� � �� ƥ � T� s� �� �� Ԧ �� �� �� �� �� e� H�
� E� �� �� Ϧ �
� ߦ � � Ʀ �� �� Y� <� `� v� �� ɦ �� �� �� c� '� � [� �� x� a� �� T� � � �� �� 3� ?� $� �� �� �� ȥ ��
� � ̥ �� u� -�
� � � ̤ 0� -� ܤ �� � � �� �� �� �� �� �� {� Z� ?� N� �� ڤ � ä �� �� �� �� {� t� T� � ܣ �� �� `� �� )� O� � � ģ �� �� �� �� �� ͣ � o� �� Ϥ �� �� �� � �� ?� i� r� s� Ѥ �� �� �� �� � 7� �� v� |� �� �� x� k� >� �� �� �� �� �� j� �� �� Z� �� �� z� �� ӥ Υ � �� ӥ إ �� �� � Υ �� P� $� b� �� �� �
+� Υ �� �� � � ҥ �� � � ե ɥ �� ̥ �
� � � �� إ ť
� �
� D� 6� �� ֦ �� y� � |� ɧ j� K� !� � � �� X� @� � '�
� �� &� � � ϥ |� �� � � �� �� �� �� (� � ֤ �� p� Z� �� �� r� d� g� t� �� Ҥ �� �� u� l� r� ~� 9� � .� � �
� �
� � �� ԣ ֣ � ݣ � �
� ,� <� Y� �� � � �� [� n� �� � H� >� W� u� h� a� b� \� W� � � �� a� �� �� �� �� }� Ť �� }� �� �� � �� _� �� c� \� �� �� l� �� �� ˤ � �� �� �� �� w� ��
� f� �� �� X� �� �� v� �� ӥ g� g� �� � å i� %�
� S� �� �� � �� D� �� � 9� �� ~� �� �� � �� � 8� "� "� f� d� � �� ʥ ڥ ��
� � � =� B� W� A� � � Z� r� H� &� =� Q� ^� �� k� "� %� Y� � (� g� ͦ � � ߦ �� N� �� �� 1� �� s� .� �� t� d� o� � ĥ 2� �� w� !� � �� ĥ �� �� �� � ɥ �� �� ҥ � �� � �� ä �� Ǥ �� �� �� �� � �� �� � �� �� �� �� )� ۣ � � w� � P� b� �� �� f� b� �� n� � � � 4� � � *� J� _� T� S� E�
� � Т �� �� �� � �� 1� � � � � "� $� � � �� �� �� � � W� �� w� � � � B� p� �� "� � �� �� �� �� ǣ �� �� �� W� �� �� =� %� � +� X� r� �� u� =� i� f� \� >� c� �� � �� �� I� ;� i� �� 0� �� �� ɣ �
� ǣ ף &� _� V� � � � �
� H� 7� R� �� "� � �� � ٤ Ť �� �� � � � �
�
� �� � �� ^� �� �� d� |� �� �� � � � � � �� �� �� I� 2� %� �� �� Ҥ V� k� q� �� �� ؤ � � Ǥ O� |� <� \� Z� ;� I� � �� ̤ �� �� D� �� � V� �� �� �� �� Z� � � ?� b� G� �� q� >� L� �� �� �� � �� �� {� � �� K� �
� ɢ �� �� � � �� â � }� �� С � o� Ң �� [� x� V�
� ¡ |� �� ס �� ɡ �� �� e� ~� �� �� q� M� U� 7� �� ՠ ݠ ܠ Π à � � �� �� �� �� � �� �� W� u� �� �� � g� 6� *� ̡ �� c� @� O� �� ס
� `� ע ˢ ܢ Ǣ � F� �� �� l� +� '� � �� �� � /� [� Σ
�
� �
� � � .� �� У +� �� ڤ � #� p� � [...]
� � H� � � � 7� �� Ǣ �� �� �� Ѣ �� j� v� =� ̡ � � *� A� (� �� � Z� ̢ � �
� 8� ڢ Ţ ڢ ¢ Ӣ � � � ��
� ٢
� � �� �� �� ��
� �� u� l� �� �� �� �� ǣ ܣ �� ȣ � ģ �� �� �� �� � У �� �� r� >� <� y� r� 0� ?� &� � � � -� � 8� 5� $� -� Z� R� � >� B� � D� c� � �� � &� � �� �� ̢ �� Ѣ �� +� �� Z� �� �� b� 6� ͡ �� � � '� e� �� 5�
� � � �� �� o� �� � ˡ ȡ � �� C� _� �� ӡ �� �� v� ?� � � �� ʠ � � %� � �
� �� �� �
� Ϡ Š � ۠ �� �� �� r� g� Z� 9� %� � � }� t� �� #� e� � �� 2� j� �� b� � Ɵ p� f� z� �� }� Z� �� �� `� � � � � � � � � '� � k� �� ß ՟ �� �� ߟ ߟ ֟ � n� A� �� B� H� � F� C� �� � � � � � Š � � �� ��
�
� � � � � %� i� �� !� � X� �� �� p� x� T� $� D� i� E� K� L� E� � �
� � G� =� .� E� m� �
� A� W� �� Ԡ � ,� ;� ,� � c� |� \� ,� d� �� � �� A� � ܠ �� �� ؠ Ҡ � � B� � � |� ;� 6� n� 4� � � � � � +� N� 6�
+� �� Π �� �� "� � ޠ �� � +� -�
� F� � �� g� D� � ˟ �� � �� �� �� � � q� @� Q� s� ]� n� ٟ �� 3� N� k� u� f� �� �� �� ϟ
+� 4� !� � � � � � �� u� t� "� � _� �� �� �� Z� Q� v� �� � 3� Y� 0� $� �� �� � � ğ �� �� T� q� �� ܟ ˟ �� � �� �� �� j� n� �� �� �� �� �� �� �� �� �� \� Y� R� ğ �� �� �� �� y� _� g� �� �� k� � �
� � � � Ϟ � �� 7� 2� U� }� � � �� �� �� �� �� � מ /� Q� �� ͟ �� �� V� w� �� � � `� �� ǟ �� �� �� � � � � l� A� U� )� _� ^� L� `� �� x� 9� �� Ϡ �� �� �� ؠ Š � �� à �� � � �� �� ٠
� �� �� "� M� ;� 5�
� � �
� � �� �� �� Z� 9� S� {� �� �� @� (� � � ߟ � %� � ݟ ğ �� w� �� c� �� [...]
+� � ˞ Ԟ � � 5� �� ̟ ϟ �� s� �� � � �� z� � � �� 2� h� �� �� �� � %� � � D� .� � � S� �� �� �� �� 4� [� �� �� ۡ ˡ ȡ �� j� l� �� ɡ �� �� r� �� l� Y� �� �� �� �� �� p� f� �� �� g� ,�
� �� �� �� �� �� �� c� 1� �� �� �� �� �� �� �� ~� p� �� ͟ �� ,� '� 1� � � ў � Ğ �� �� �� �� ?� �
� 1� D� B� Z� V� z� �� �� /� �� � ŝ � 1� (� � � ם ܝ ŝ �� �� �� � �� Н �� ѝ
� �� � � �� ͝
� �� �� �� � �� 2� ~� �� �� M� W� U� A� �� l� ]� y� [� '� �� ܝ �� �� �� �� �� Ş � N� �
� � � �� ĝ %� r� H�
[...]
!
!
!� !� � !!&!I!�!�!�!k!�!!L!J!� !� � !� � �
!?!1!!Q!!� � � !� � !*!!� � � � � � � !� � =!�!�!�!�!�!�!V!v!�!g!/!n!�!�!z!I!!�!�!�!�!n!=!?!!o!n!~!�!�!v!�!
"H"3" "4"2"""")"I"M"I"'"�!"�"�"�""
"H"b"3"F"'"6"_"�"Q"B"?"9"�!"X"�"�"�"�"""""M"U"�"�"w"u"7")""�!�!K"�"R"�!�!�!�!�!�!�!�!�!�!�!+"-"�!Z!4!j!�!�!P!A!T!v!�!�!�!�!�!�!�!T!!!� � � � t n �
!L!� � � � � r � � � � ` G � � h � � � 8 J D Q c � � � W $ w � � � � \ I S i � � � u + " / � � � � � !,!� � � � !!Z!C! !� � � � � � � �
+!� � � � l �
!$!� ���K w � !0!<!!!>!L!%!
!� � !� �
!D!y!�!�!�!k!�!k!{!n!z!�!{!�!�!�!�!�!~!�!i!3!! !7!>!x!�!�!�!�!�!�!�!!N!4!!4!F!_!�!�!�!�!�!r!�!�!�!�!�!t!}!�!}!�!�!~!D!m!l!!� � !!Q!�!w!G!!� t � � � � � � � � � �
!!� � � � w � w r � � � r � � ����; | � ? L W 1 ��� �
2 ���������������p R + 9 r M
�" g ` � r Q } ������C | � � � � � � 9!J!.!$!$!!� � U � � � !M!d!l!u!�!�!�!X!7!v!�!�!""d"j"2""." ""9"C"%"" "7"�!�!�!�!�!�!�!�!"1"B"!">"{"_"k"�"�"b"�"�"�"v"�"�"�"�"#�"�"#�"H""�!]"�"�"�"�"P"�!�!""1"b"M"%"e"f"w"�"�"�"�"o"i"�"V"Q""�!�!�!�!";" "" "�!�!�!�!�!�!�!�!`!!8!�!t!3!d!�!a!L!G!I!$!!� A!y!H!B!#!!� � � [...]
!� !#!k!�!�!S!<!'!�
!
!� � � K!,!� � � !%!j!�!c!\!�!�!o!'!j!]!� � � +!,!!!!� � � � � � � � 1!i!{!@!C!t!U!l!y!U!P!'!"!h!T!!!� � � � � � � !=!!� � � � � � Z A � � a r � � � !� � "!O!<!�
!a!r!�!�!�!!� !!� 0!� !:!h!�!�!�!�!
"!"�!t!T!�!�!�!�!�!�!�!"�!�!�!�!
"
"�!"""�!�!"="j"q"�"�"m"u"�"�"r"�" #�"�"�"�"�""�"�"�"�"�"�"�"3""�!�!h"y"["i"x"v"�"�"�"u"O"
" "�!�!�!"U"
"
"="|"a"G"_"q"Y"#">"W"�!|!q!�!�!�!�!"�!�!Q!p!�!�!l!E!!#!0!r!�!a!2!!!Z! !
!U!Y!e!�!�!�!�!"�!�!�!�!"�!�!H!
+!
!� � !q!�!�!�!T!�!�!D!�
!� � � � ! !� � !v!�!f!P!M!K!� � � � � h!q!`!�!h![!F!!� � !
!a!y!�!�!�!G!u!�!�!�!�!
+"�!�!�!�!�!�!�!�!�!�!U!F!{!�!r!H!3! !!3!,!!� � � !� � � � � � � � !� � � � � � !!!F!8! !!Y!=!� � � � � � � !*!� � � �
!� f � � � � � � � � � � !� !3!� � � g � � � � � � � � � � � d � � � _ � � � j " ( ! $ �
Y b , � G j - ��������{z9(#TA,H2N�������� - ��� ����S H t � [...]
% ~ � d & �F _ V k � 7!� � � � � f D Z { @ V p � � � v � � V ��� > d F K - �2 6 5 b N
. ; ����� ����- �����t��" Q 4 n � _ 3
: < �� i � � � � � � � �
!6!� � �
+!
!!� � �
!:!*!� � � <!T!:!K!!r!y!�!A!:!s!�!G!
!v!�!�!q!$!F!K!6!J!$!� � � !
+!� � � � � � � � � � � � � � R '
^ � h � s T � � � y a � d 1 = w � � � � � � !� � � � � � � � � � t � � � � � � '!� u e m N s l r � � g c � � � � � c ` t � � � p � � @ > ] ~ � � � � � � e u � � z � � � � � = q � � !� 9!!� � � � � � � � { � � k o � � � Z � � a > J s � � � �
!!� !!� n Y W � � � h i k � � � � � � � � � [...]
+!x!�!6!!d!e!�!Y!8!c!o!U!�!�!�!�!�!�!�!�!
"a"Q"D"5"M"i"c"{"�"F"Z"w"�"V"h"n"^"f"j"s"�"�"�">"f":">"{"�"�""e"s"O"m"�"�"H"S"/"�!""�!�!�!�!�!@!!7!8!!!!� � #!#!!1!;!� � � � � � � � � p Y 1 r � u � � � � � � { 8 % 7 � � � e � � � Y � � a � r 2 n � � � � G e � L = � � � 6!J!+!�
!'!2!� �
!� !� � � � � ] m � � � ,!!� � � � � [...]
!!� � &!6!7!7!1�/�0������Q���[�Z�P�A�W�_���՚�/�������͛��u�қ���� �ݚ�K���ě����1�����^�p�U���Q����������\���=��������ϛ��w���(�;�
�����|�N�����������M�K�Қ�&�`�t�"�ܙ
�.����יÙ������������������əԙ���k�;�����,��ɘ����
��
�������Ϙ��������� �������������s�Й}�ҙF���p�Κߚ�E�7�(� �ߚ������n�U����'����@�������I�{���Κ� [...]
� �ۙ�<�����������������Q�������y�Q�6�Ӛ��3�@��S������������ә8�_�����?����E��#�R�7�8�=�x�K�^�̙� �ҙÙٙ��̙��6�,�/� �����<�5�)�4�
���-�0�q�b�5�|�Ǚ��ؙ��ߙ�v�ۚך����������К��r�"����Q�m�c�E�H�����������������b�N�T�n���j�n�^�,���3�*��(���� �3�%���������ۙי��������������W�i����
���z�ɘ����)�b���k��s��
�)�<�K���W��ә�c�]�+�p�����ޚm�P�|�z���t�N�]�}�͚ٚ����������������К����������C�Q��ؚ��^�C�^���
�7�������H����#�Q�P�<�
�7�S��H�$�<�'��
�B�f���z�|�d�P���7����e�T�`����0�h�z�����јQ��������ߗؗ���0� �2����˗��g�������T�^�V�N�;�����D�����0���������e�I�חߗ����k�I�T�Ø9���֘������|�5���9�Q�`�s�V�%�+�M�%�ڗ���e���B�{�ٖ���u������`�����b�v����"�ʘ���������ߘH�j���x�����V�(�P�}���i�z�n�h�;�i�T�A�?�֘Ș��ܘ� �S��������� [...]
�W�y�b�������������ՙ��V�}�^���s�x�u��������G�r������^�Y�r���L�|�ƚu����ښp������r�c�����8�2������L���Ǚ���s�s�I�>�o���Йșy�f�������@�֘��ؘ�3�G����V�y���z�^�~�o�����V�×ŗ�a�����4� �����o�{�����ɗ��ۗǗ��B��Ɩ�(�7�\�.��.�V�B���ݗ
+�������5�V���җޗ�З�1�� �ŗ����̗��v�g������c�M������ �����ߗ����X��I�����ɗ����d�p�|�%�I���q����ۗ��ԗ�n�������<� �
�
��͗�����ӗ~�b�g�/�ɗ,����|�c�(� ��֖ÖٖՖ�&�g���>�&�N���������A���������
�ϖ��ǖt������"�&�/��g�9�{�\��N�C�P��������Ŗ �@��ܖ������p�h�������������Ȗ�� �Y�a�$�
��
�=�a���}�����H�"�����×�ߗ����`�*���̖�5�\�n�������������<�?���1�/�:��x�������ٗ4�1�!�6�ԗ��ɗ{�6� ������&������Ζ��1�&�w��D�֖�������T�a�@�g�
����ݖȖ��� [...]
+����̕����E������ٕѕ��Õ��o���!�%��������^�V�� �0�`�q����Δ��]���`�����s�:�8�-�A��ߓ#�Г˓ܓ��#�s���ДԔ��k�\�����ϔ������U�����?�S�Z�b�����a�1�y�l�_���e�[���������3�|�+��J�R�h�:��ĕ����y���ߕ���>���Օ
��$���������$���ɖ����d�A�:�J���ɖݖ�����������0�,����$�4�5�Z�V�L�k�W�!�3��ؕ���1�%����~�X��������$�~�g�Q�#�8��V���N��͕ڕ���(�.���o���ĕ��}�=�0�L�=�`�z�V����#�P�^���|���ߕ.��ɕ���v�����P�1�הД�J�-�
�����`���Εɕ��c�8�M��"���Δ���G���_�;�`�`�$��הǔr���ܔ%� �ڔ�ߔ�۔ĔĔ������˔ڔ��ٔ�����۔|���~�T�O�P�v�`�c�C�t�������/�������M�q�Ĕ���.���ٔ
���l��U�����������Δ��K�?�3���&���e�p�*�Д�Д��� ���<�S�g�A��F���x�!��9�j�A�D�>�(�
+��ڔ��Ӕ��Δ}��������\�4�\�����ϓ����$�
�ۓ����L�����h�b���{�V�x�����g�o���j�D�Q��W�P���:�M�o���j���������������]����[�H��)��6����ǒ����r���
+�ɒ� �"�
+�'�|�E��"�"�u���c�9�.����Ē��3�C��<�M�m�R���t�v���͓p�.�J�����~�S�����œ��d�H�����{�l�l�e���Ǔ�������ߓ�������������/�^���ؓՓ!�������n�>�5��������:�%�
�˓�i�K��7�Z�k�z����c�:�S���ɔ��l�A�!��ғ��
�)��,�>��2�_�]�J���Ք��������������ߔ'�@�e�C�H��������������ŕ���
��y�y�ٕ��?�
���ە�������-��ؕ����ĕ���ٕە������������ [...]
+_ �^ �^ �^ u^ �^ �^ 9^ ^ ^
^ �]
^ &^ �] �]
^ �] ^ 5^ 3^ �] �] E^ �^ �^ P_ f_ B_ �^ �^ *_ �_ �_ �_ y_ �_ |_ ~_ k_ 7_
_ _ �^ �^ g^ Q^ :^ 8^ P^ ^ (^ �^ �^ �^ �^ L_ ]_ �^ �^ �^ g^ �^ �^ �^ T^ d^ o^ 5^ `^ p^ B^ Z^ [^ ^ #^ �^ �^ �^ _ �^ �^ �^ �^ �^ )_ �^ O^ h^ V_ ._ �^ �^ �^ %_ y_ �_ �_ _ h^ 7^ �] !^ �^ �^ !_ A_ �^ \_ ` 4` �_ �_ 8` -` �_ �_ �_ �_ �_ R` �` G` ` f` e` 0` �_ �_ 3` P` ,` ` ` 7` �` �` ` y_ i_ �_ �_ �_ �_ �_ �_ �_ �_ �_ >_ �_ k_ �_ ` �_ �_ �_ �_ �_ G_ 5_ �_ �` �` ( [...]
+^ �] �] Z] �\ %] �\ �\
] }] �] �] �] :] �\ \
\ P\ H\ �\ �\ �\ �\ �\ �\ z\ �\ ] ] �\ �\ �\ \ \ �[ Z[ �[ �[ �[ \ �[ �[ �[
[ �Z 2Z Z Z �Z �Z �Z �Z �Z Z �Y �Y �Y AZ rZ �Z �Z �Z �Z wZ �Z �Z �Z �Z �Z ZZ Z �Y Z �Y aZ �Z ~Z [ �[ r[ [ Z[ a[ [
[ �Z
[ =[ p[ �[
\ �[ �[ '\ �[ �[ Y[ [ ([ �[ &\ i\ �\ ]\ �\
] ] &] �] �] �] ?] �\ �\ X\ 9\ c\ w\ �\ �\ 7] K] t] i] H] z] �] O] -] �] ^ >^ �^ o^ �^ �^ �^ �^ �^ �^ �^ �^ �^ 5^ �] S^ L^ �] �] ^ �] z] 7] n] ^ 3^ (^ ^ �] �^ �^ �^
_ �_ = [...]
+[ ][ i[ �Z �Z �Z IZ 0Z kZ IZ lZ hZ lZ 2Z �Z [ �Z �Z �Z �Z �Z 9[ q[ =[ �Z �Z [ �Z �Z �Z �Z �Z BZ AZ
Z eY dY �Y �Y =Z
Z �Y pZ `Z �Z RZ ZZ Z Y �X 0Y �Y �Y �Y �X �X nY hY "Y Y RY <Y mY zY IY (Y 2Y 4Y QY �Y �Y �Y �Y MZ mZ �Z cZ �Y ,Z SZ QZ cZ �Z �Z �Z �Z �Z �Z �Z [ }[ -[ +[ 4[ _[ [ vZ Z PZ WZ �Z $[ �Z =[ �[ �[ �[ �[ �[ �[ �[ �Z �Z nZ ~Z �Z �Z [ �Z :[ .[ g[ �[ P\ �\ �\ e\ *\ �[ 6[ �Z Z �Y �Y �Y �Y �Y �Z �Z YZ
Z Z WZ Z �Z vZ �Y �Y �Y Z NZ HZ �Z �Y Z aZ *Z �Y TZ ~Z yZ �Z �Z �Z � [...]
+Y �X Y $Y Y @Y Y �X �X 'Y �X Y �Y 2Y RY �Y �Y Z �Y Z .Z 2Z Z �Y �Y �X �Y �Y `Y OY xY �Y �Y �Y Z /Z �Y �Y �Y YY
Y SY pY WY gY OY
Y 9Y Y �X �X �X tX eX �X :Y �X �X �X �X �X oX X BX �W /X /X OX �W X &X �W dW {W �W �W �W �W �W ~W HW �W qW �W fX jX GX GX .X ?X �X +Y �X �X �X ?X �X �X X GX ~X X VX
X aX �X �X %X 5X LX X �W LX
+Y �X yX �X �X �X
Y �Y Z �Y �Y �Y �Y �Y �Y �Y �Y =Y ^Y VY Y QY �Y �Y mY �Y ZY �Y Z �Y �Y �Y �Y �Y ZY �Y Z �Y bY �Y }Y ZY OY 6Y �Y fY >Y �Y rY �Y (Z NZ �Y Y Y �X �X LY Y �X
Y ^Y Y �X �X nX �X qY �X �X �X �X �X �X �X �X �X �X �X 3X gX hX Y �Y �Y �Y Y �X �X �X AY Y �X �X �X OX �X DX �W X 1X X
X !X +X �W �W �W �W �W �W �W 1W ZW ZW RW �W �W �W �W -X X pX �X pX ZX 9X 8X X �W �W �W YW +W �W X 1X �W �W �W qW �W X ]X 'X �W �W �W �W �W _W <W �W kW 1W sW �W �W �W �W �W `W XW MW dW �V �V �V }V �V W $W
W UW �W kW ,W RW PW �W rW �W �W aW EW HW LW W !W �V �V GW `W W (W CW
W lW �W �W �W �W IX X �W �W ,W �V �V
W .W
+W �W �W yW �W �W �W �W �W �W W �V qW �W OW ~W �W �W �W �W !X �W %X eX nX 0X MX rX �X �X �X �X
X -X �X qX �X ]X cX �X �X zY �Y �X �X ;Y oY Y 0Y \Y gY NY Y Y �X �X �X �X uX �W �W �W �W �W X X X X XX iX �W �W �W iW DW �V �V ZW *W W W ZW �V �V AV �V W �V �V �V pV wV lV �V �V �V �V ^V V RV =V �V �V SV \V �V �V �V �V kV
V
V V ,V WV �V =V �U jU U �U �U �U �U �U �U iU U U U U JU
U UU �U �U �U =U �T "U �U �U �U �U [U BU MU �U zU 7U MU BU ,U �U �U 'V 2V IV ~V dV �V �V �V �V � [...]
+W $W LW �W NW xW <W W $W <W �V �V �V PW +W �V UV V PV �V V �U (V dV /V �V IV
+V DV V �U �U �U V �U �U OV !V �U �U
V �U V @V �U �U CV �V xV sV �V MV �V �V rV eV �V �V �V %W �W �W �W .W MW CW �V �V �V �V wV �V <V �U `V �V �U �U pV �V �V �V sV �V �V �V /V �U �U �V �V �V wV W �V �V oV AV LV �V �V �V �V �V (V V V V �U V �U &V QV �U �U {V �V �V XV �V �V �V zV EV �V ;V oV oV KV 2V �V gV UV �V �V sV �V �V �V :W W =W _W !A:cH��gao��5�6��KmR�>]H�\L����]��I�\4��}]��� [...]
+��,-=�z�����51
+K t]C
��yb7���������f������K�����n�����,D`q������� %�����K6n�`"�G�%����ik��K��G���{Q��92�"�!���Sv�r>z����( ����S'VU���������g���R�����
+��nP
:�:vDT�/�}
1�GPP]����w2S�I
+:
vh����p� B��9�eR^�U���w�AKkW}� 3q�'l� G;0���]N�q�'2l}[����8�N�� ��"9`�a��:W�� � � ("�|LJ]\{�/O$�����2E��|���8w����oQCS�25\o�� ��
dJT��
5�
[x�� [...]
+ ��������x�I�f���I � t� ���� � )� � ��� � C������R � � � � + / ��R g C � ��@�� 4 ��U � u��yOD�DfX+��xlD��M=s����
��|������@svo����7
��^:99��i���-��`�����t8��$���$�����f������]/� k \ c = ^ � � � � D ��l���-�]���
� �Q�{�w��������S��������������������G���w�<�M�K�F�-�;��� b P N ������
] � � � � � � ` ����n � ^|z��ci-� 7*-Hx�p�N��$5��OT���{{���\��y�]9��.SA���Gf�d3
�mA���;�<_��s�tg1��A�;����iZT�a4�Mq�9�����a[#�X�������^!�l����zb_7)'���������!� � � f c � � ������n���������'���
+�t�����% 6 ^ ���� � � � �
� v i � � � � n�
���qo ����w � c ` i i � ' ��e \ R �
�}
W�����J
� � � � � � � � � � ?Y-� � � L ������������ ��I�l�|�=�t�T���M�b�`�&��\������ �
�!�����������p�s���%�o�������������������(�i���������������_�V�]�+�X���������i������������������)�:�
�
�"�.�g�f�G�c�t���x�C�(���6�X���������F���������
�;���F�������l�u�T�W���V � s A���A���������{���%���J�
+���*�.��,�����X��\���������~���������v�C�p�9�
�O�.��R�������B��������������u��� ��m�o�u�n�
�Q��!�;���3����Z�^�q�k�x��������P�;�k��� � 3 ���w�x���`�_�a���: ) - ] � � � � � � p ; � � � x � � � � �
����>�4�?�����9��o���.��������������A�������������!��������.�S�c�9�7���$�����#������������������"�j�_�o�� [...]
����������j��������������������H�~��E���n�����G�q�Z�`�������\�����|�]���������s�+��
���n�����������&�z���& N t A ����������[�L�����A���
��z���e�z���;��T������R�x���������>�����(������� �����&�����y�������������(����������������D��������F�E���������������������"�k���u����
�����X�����������^�V�"��*��������������(� [...]
+��A�S���� � f ��a�G�����_��k�|�j�N�H���7�L���
��"�>�+���������������������������w���������C���$��������������Q��t�U�e�����������������g�����j���&�����U�T�����d�z������
���`��������o�������~�*�V�"���H��/���s�X�������C�S�R�"� ���]�Z�p������������������v���������*�v�a��� U � &ad#"� u ���� g ����@ T f [...]
����N � � � � � � � )S����^/� � � /%9��\��T� � � � ~ � � ^ � @P�rB� � 9Z��)b� e� T� O� D� � �� �� j� �� �� U� e� Q�
+� � r� q� �� �� �� y� � n� �� �� � k� *� � '� �� �� �� q� d� �� �� [� �� �� � b� -� �� A� ��
� �� �� 0� �� <� V� �� �� #� �� A� �� �� �� � 1� S� �� R� {� �� ��
� F� Z� #� ~� �� �� J� �� �� M� �� �� �
� �� �� � �� P� � �� � h� |� "� �� �� g� �� � o� �� �� �� x� D� �� �� �� �� ,� �� �� �� X� u� �� �� �� �� �� �� "� )� 1� � 4� 1� �� �� �� �� � u� �� �� �� �� T� d� �� �� �� g� l� /� w� j� L� m� s� �� � �� � � L� *� e� 8� E� s� �� �� �� �� � �� V� �� �� � ?� �� �� B� � [...]
� � �� �� n� j� �� �� �� �� {� �� ��
� O� �� �� 1�
� �� s� ]� �
� �� �� �� x� � ~� :� g� �� ,� w� �� ��
� �� �� � f� 2� �� s� �� �� r� p� �� �� �� �� ?� *� M� �
� � �� �� �� �� �� �� � �� #� u� y� q� h� � �� �� �� 3� �� q� }�
� �� ~� �� � r� %�
� �� #� �� [� 0� �� !� �� �� �� �� C� z� �� �� � 9� �� h� �� � � �� G� �� R�
� k� f� �� � �� R� 0� � �� �� a� \� �� (� -� d� � �� �� X� {� �� �� <� �� T� �� q� q� �� +� �� �� G� �� h� (� � �� �� �� k� 2� �� �� #� �� �� �� �� �� �� �� ,� �� � N� �� �� 6� �� P� �� �� �� � 7� +� 2� �� �� �� �� �� �� �� �� �� �� �� �� �� g� .� p�
� �� '� ��
� #� 1� �� �� A� �� j� � �� �� �� �� �� �� 9� �� �� �� k� �� �� *� ��
� I� �� y� s� �� �� �� �� o� �� �� �� s� �� �� � n� _� �� �� �� �� �� [...]
� A� � � �� �� �� �� �� �� � \� �� e� c� m� �� �� �� �� � �� �� �� �� F� B� Y� �� �� m� 1� �� N� � �� 8� �� �� �� o� �� Z� �� �� � � �� �� �� �� %� v�
� <� S� � �� �� �� '� �� � �� � ��
� #� � j� l� h� �� � �� �� (� �
� �� �� �� �� �� I� &� � �� �� � �� r� )� 7� '� q� K� �� J� g� �� Q� �� y� �� u� W� �� � (� � u� �� ��
� �� �� �� o� �� �� � ~� �� C� �� Y� _� �� �� � !� A� �� �� �� �� �� � �� �� �� �� �� ��
+� � A� �� � (� b� n� (� � u� �
� T� �� �� 8� �� �� � �� � 6� ,� �� �� t� 3� �� ]� � R� �� �� �� � � �� ��
� ^� R� z� <� h� �� �� e� E� � �� � �� *� �� E� E� �� �� �� q� �� �� .� �� �� �� *� � 9� 4� �� �� � �� �� � �� U� �� �� �� S� �� �� �� 5� R� �� g� &� .� �� �� H� [� �� �� 8� 1� �� �� �� u� �� �� 0�
� f� �� �� �� &� y� 9�
+� �� V� �� [� ��
� � �� �� \� �� �� �� #� �� ,� c� �� �� � � � 4� g� �� �� �� �� s�
� �� �� c� �� �� � X� 8� =� �� R� P� /� �� �� �� �� �� H� p� J� �� �� � �� �� �� � �� �� �� � �� �� �� �� �� R� A� S� �� �� �� �� �� � �� �� �� F� �� J�
� 4� a� �� �� �� X� �� C� ,� N� $� ~� � �� �� � �� V� �� r� S� =� �� ]� �� �� @� J� �� �� �� q�
� �� �� 5� +� @� �� �� �� R� � � 4� �� �� �� D� O� @� )� ^� �� �� 0� �� � �� y� �� 1� �� �� g� n� �� �� �� �� �� �� �� �� �� c� �� �� �� �� �� �� �� �� � g� �� w� �� �� ��
� k� �� � }� �� � �� �� �� �� �� �� �� �� Q� #� � �� K� �� �� � D� � �� q� `� /� �� � �� � �� H� �� �� .� �� �� �� �� �� �� �� �� m� +� �� $� �� � M� �� �� �� n� �� C� _� p� �� "� �� c� -� �� �� �� Z� J� 5� 8� [...]
+�
+� Y� J� ~� �� �� �� k� A� u� �� �� �� �� � � k� �� �� &� � b� � g� �� �� �� � >� � �� �� =� <� ?� � /� ~� y� � �� y� � .� �� `� �� ^� �� �� �� �� �� � �� �� z� #� �� N� �� [� �� W� � |� t� ��
� �� �� �� ,� ^� Z� Y� s� .� � B� f� )� �� � �� �� {� |� g� � �� �� �� �� �� �� � ��
� �� �� �� �� �� �� �� 0� #� x� �� �� �� �� � �� 0� Y� � �� !� �� �� � +� N� �� � �� �� ,� � � �� �� m� �� b� �� ?� �� ��
� I� ��
� 5� �� :� 1� C� �� �� � Q� �� �� V� �� }� �� �� g� �� �� � [...]
+� �� �� �� �� Z� v� m� 8� �� � q� �� �� �� �� s� �� �� � �� l� �� �� x� �� ��
� d� _� �� � �� �� -� �� �� �� �� �� \� �� �� W� � �� k� �� J� c� �� �� �� s� i� u� O� 1� �� �� �� �� � �� �� �� a� C� � �� �� f� V� �� 2� �� M� �� U� .� �� �� �� �� T� � �� �� �� � � �� �� ]� U� n� \� � � �� K� �� 9� � �� �� Q� �� �� �� �� � � \� A� �� �� |� � f� �� ]� q� t� �� �� � � 9� :� 8� Y� �� �� �� �� �� ~� h� �� �� ?� � -� m� �� �� w� �� �� .� D� �� �� $� <� .� �� �� �� b� �� �� Q� � [...]
� � �� �� �� � ��
� � �� �� x� V� A� �� �� Z� � � a� �� �� � � F� e� �� � � @� � �� � � :� B� ,� � �� �� �� s� t� � �� � �� !� �� o� �� �� {� � �� �� �� �� �� �� �� V� �� v�
� �� &� v� �� �� �� ��
� � � �� �� � p� E� � �� �� p� '� .�
� �� .� � ;� E� �� �� R� �� �� �� �� � � 9� �� �� x� �� �� � 3� X� �� .� �� �� �� � (� v� ��
� 5� �� �� ��
� �� b� :� |� �� � 8� �� �� �� �� %� �� �� �� �� �� � C� �� �� �� �� �� }� d� W� V� �� �� �� �� �� �� �� �� Y� `� � �� �� g� Y� W� � A� � �� �� � �� �� �� s� �� � � �� �� �� � a� � � n� f� Y� y� �� �� �� �� �� �� �� �� �� �� C� �� 2� �� �� � .� � X� �� � X� �� S�
� m� �� �� Y� �� �� �� �� � �� �� �� �� �� � ��
� � � �� I� �� �� ؛ � ˛ �� T� �� g� }� �� i� .�
� �� � L� �� �� �� ƛ �� $� z� T� f� �� <� � ��
� z� �� �� �� כ � ۛ ś ś � �� /� ̛ ٛ l� "� 6� [...]
+�
+� �� /� I� s� �� �� Ԛ L� �� b� >� %� њ k� �� Y� Й �� � � B� � �� �� ř ڙ :� Q� E� R� � \� �� �� J� b� p� ݚ ]� ۙ ՙ ͙ � '� L� �� � �� /� L� � O� ?� &� �� �� � �� R� ;� ?� _� Y� � 7� � Y� � Ӛ �� �
�
� Ě �� �� {� n� t� '� �� �� �� ]� � z� � � Қ |� 0� Z� �� ƚ Ԛ �� 8� � � �� %� i� � ʚ �� �
� �� � z� !� �� � � }� s� �� �� љ a� &� � *� �� w� � ٚ � �� @� p� � � � ݚ �� ]� ۙ .� � �� �� � �� I�
� ͙ ԙ
� � ߙ � � � � O� t� �� �� �� �� �� Ԛ �� � �� d� ,� h� �� �� �� ښ К �� �� Y� {� W� R� � � z� Ś �� �� �� J� g� }� �� � <� �� w� E� �� � � �� t� &� �� � �� �� � ˙ � W� l� �� }� p� �� �� U� � � 6� � � Y� � �� �� � �� /� '� � � �� �� � Y� 8� _� �� 7� � � �� 1� �� (� �� ՙ {� i� � � � �� B� �� ۚ E� Ι �� Y� k� �� �� �� m� 2� � �� ؚ J� w� �� �� �� � �� �� �� -� � �� �� [...]
� ȗ �� C� �� H� � N� �� ɗ � x� u� �� -� � �� g� � +� � i� ,� � <� {� � ֘ �� �� �� � � �� Ș �� �� �� � �
� D� �� 5� �� � %� )� �� � ۘ �� �� �� i� �� �� �� [� J� � Ø � � � � �� *� �� ߙ ~� I� � .� B� �
� ^� }� ߙ �� v� [� -� o� +� � � �� �� �� 8� m� �� �� �� � Й o� Y� � d� w� �� �� �� �� %� 5� $� E� љ �� \� 1� s� =� 9� � � �� '� t� �� 1� X� `� Ș �� \� <� ј B� �� � �� ҙ j� � p� �� ]� �� ܙ V� 0� b� �� G� P� e� L� �� �� �� E� �� o� �� �� ̘ � �� �� �� 2� |� �
� �� ٗ � S� � [...]
+� /� ۙ P� � � �� �� �� e� v� ͙ �� 0� Ě ,� � �� �� �� 2� ؘ T� �� � ?� � e� n�
� �� F� D� � p� +� � ͙ a�
� b� � ̙ ʙ �� � &� �� Ù
� ך t� �� �� b�
� �� � � �� 4� �� � � � �� \� g� 1� ?� �� �� �� � ˚ X� �� R� �� ̚ Y� _� >� L� .� � �� [� @� <� 0� ę � ҙ ę }� I� B� � Ø �� �� �� �� � M� u� � � L� b� � u� k� �� H� �� �� ȗ �� ʗ �� 8� x� �� �� d� � � 2� a� A� � I� �� b� �� � ܗ
+�
� ?� � �� -� �� \� �� �� �� �� {� �� � 5� _� E� �� � � �� |� � �� �� � t� c� � �� p� ޘ Ř �� s� Q� � �� җ Ɨ �� k� V� G� d� q� � � q� �� �� �� G� 7� �� � �� �� C� J� T� �� ��
� L� ܕ �� ĕ � �� �� ȕ V� � � � � �� �� �� Q� � %� ӓ h� ~� ӓ �� �� �� �� � � >�
+� � �� � �� �� �� ͓ ɓ 6� �� v� �� j� �� �� �� ړ �� S� V� }� Z� &� �� � �� �� 0� ?� �� �� �� Ô �� �� ͔ 9� /� �� �� �� ϕ ܕ ؕ I�
� ݕ ؕ U� � �� N� �� �� � ^� � O� �� G� � ?� �� Q� �� �� Ɩ �� �� � � '� Ö ܖ � � )� �� �� � ^�
� �� ��
� '� �� ��
�
� K� ߗ �� 4� � � 8� � �� I� Ö �� ۖ ϖ � і N� �� �� x� X� S� �� �� �� �� r� c� �� {�
� W� V� �� *� �� �� J� E� Ԕ �� � n� �� U� l� ~� �� ǖ �� p� D� 6� � ѕ m� �� � � �� I� �� �� �� r� N� �� `� � Օ u� [� P� �� �
� � ͕ �� o� r� [� �� �� r� �� � [...]
+�
� �� �� �� � 1� +� �� � s� S� � 2� X� E� o� �� �� ;� � ߔ {� M� � _� j� �� �� �� �� ͕ � �� s� �� �� x� ~� {� P� P� }� &� � � ��
� _� 9� (� 8� I� � ˔ � '� Z� � Ք �� >� Z� X� Q� � O� �� g� � �� � � ʓ ۓ � �� � &� � �� ˔ �� �� �� �� �� � %� � _� �� x� ˔ ߔ V� �� ̔ � � [� {� �� � �� �� �� n� �� ȕ !� �� �� � K�
� � S� �� e� _� H� ]� {� @� e� |� �� �� S� :� �� і ؖ U� \� A� 6� �� 7� '� �� �� � ˕ /� j� � �� S� 2� � � � U� )� "� [� ]� }� ǖ ɖ �� � 0� ߕ .� �� �� w� �� � �� e� ؖ V� 9� �� � � � ʕ � :�
�
+�
� E� _� �� ޕ
� H� H� .� ]� _� � � D� }� �� � � ӕ m� q� �� �� �� A� e� �� �� v� a� ?� 1� J� Y� �� � �� �� �� Ք � >� -� h� ϕ �� ͕ � �� �� o� �� g� �� �� � �� .� � Ô �� � ɓ ѓ
� M� � ڔ X� C� G� j� f� f� X� �� @� � 8� %� ;� =� 4� Y� �� Z� K� O� �� �� � ֓ ��
� 3� M� h� �� �� � <� a� � � �� � ٔ �� Ô �� �� �� h� �� � �� �� �� {� �� �� �� �� ؔ Ҕ �� }� � �� � 9� �� Ӕ �� @� � Δ (� � �� �� i� ޔ V� &� �� �� �� �� }� �� �� s� m� 4� x� �� � �� S� F� �� }� �� �� ?� ǔ � ֔ �� Q� �� � �� [...]
+� ݒ >� �� �� �� Ē ђ � � � �� ˒ I� � *� (� �� � � � ,� � �� ˒ �� �� Ò � ג �� ג
� �� �� �� �� `�
� &� D� H� r�
� � �� Ƒ N� *� �� ڑ �� &� 6� � � -� � �� �� F� Z� ]� �� m� � J� �� �� �� +� �� B� x�
� �� �� �� �� v� K� � �� ǒ �� �� � 1� c� 4� ؒ x� �� �� �� P� �� Y� � �� �� �� �� ޒ ے �� .� �� �� ǒ � � Ւ �� "�
� � }� '� �� � � � x� d� �� n� g� �� P� g� Γ �� �� /� �� �� R� A� <� � � �� ]� �� �� �� �� �� a� c� ד #� � ߓ ޓ � ˓ `� ?� H� � <� �� � � P� ג ?� e� �� �� � N� 3� D� X� L� Q� � �� }� &� n� ˔ �� �� w� ֔ � z� m� ͔ q� I� �� �� �� �� ٔ ̔ ֔ �� � I� C� !� %� V� o� 7� L� �� � � M� �� B [...]
+� -� 3�
� �� �� 9� �� S� .� �� }� ;� S� q� �� � e� !� � h� @� *� A� /� H�
� b� }� i� ,� � �� ͓ y� H� b� �� ɓ |� a� �� i� �� �� �� �� ɓ �� z� ӓ �� i� ~� t� �� ʓ � ē �� 8� �� &� �� �� �� [� �� `� .� ^� L� >�
� �� �� �� �� � '� H� D� �� 6� r� b� f� �� �� �� �� U� �� q� ~� �� �� �� �� �� �� �� � M� �� ]� �� �� �� �� �� {� i� �� y� �� A� 2� �� i� X� i� � =� ��
� �� ?� �� "� I� -� V� [� !� F� � �� �� �� �� |� �� �� �� |� �� j� 4� �� �� �� � 3� *� &� �� � �� �� �� �� �� �� �� �� �� �� �� s� 2� �� �� �� �� �� M� P� � �� �� �� � ]� w� �� �� �� �� �� T� � �� �� @� �� J� p� �� �� m� �� � �� �� �� O� }� m� �� �� J� �� ,� �� �� �� �� �� Y� �� � � G� �� ��
� E� ?� �� � "� E� %� %� � �� �� q� � R� r� V� �� �� �� Q� d� �� �� ~� {� �� �� �� E� �� �� O� g� B�
� �� � �� ��
� �� � �� e� �� �� �� �� ^� �� �� �� �� �� �� �� f� W� �� �� l� �� y� i� E� �� �� �� -� �� �� 2� �� �� �� �� z� �� �� �� �� �� �� �� �� h� �� �� r� "� -� {� �� a� �� �� �� &� �
� �� H� �� ?� � �� ;� 5� F� 7� � O� |� m� �� �� �� �� �� �� �� � � �� �� �� �� �� �� �� z� 0� c� >� 5� y� �� �� s� �� �� �� c� l� �� �� 1� � � �� $� �� @� �� !� 3� �� �� �� �� �� �� �� �� C� 7� X� �� O� 3� W� �� � j� �� �� �� >� �� �� �� �� � W� s� [� �� �� �� D� �� �� �� �� �� \� �� =� �� �� �� �� �� y� n� 5� � `� �� �� e� � �� �� @� �� 0� �� � �� �� �� �� �� #� �� �� �� �� �� �� �� �� �� �� q� @� �� /� � @� �� �� V� R� <� 3� N� 7� I� �� �� �� "� �� �� �� �� �� �� � 2� �� �� [...]
+� h� �� +� &� �� '� I� <� �� �� �� �� �� �
� �� �� �� �� �� �� �� �� �� a� l� M� 1� m� �� 5� � �� #� A� �� �� *� w� �� n� �� � � h� �� �� i� P� 2� �� u� :� N� �� �� �� k� �
� !� V� W� 5� 9� �� �� I� d� �� Q� 7� � � :� U� q� }� d� d� n� �� $� �� �
� !� \� s� n� v� � �� �� �� V� G� Y� �� �� �� a� %� 9� �� �� d� �� "� �� �� �� �� �� T� N� _� � �� �� �� �� �� �� �� �� S� )� �� �� �� e� 4� �� A� �� � m� {� �� �� �� �� �� �� �� �� �� �� �� �� W� (� k� u� R� p� �� �� �� �� �� �� O� �� �� �� 0� k� `� � �� �� A� �� � 1� e� 4� j� o� �� l� I� m� ;� +� R� �� �� V� .� M� @� _� e� R� ��
+� � �� ��
� �� �� �� ��
� 3� �� � m� k� +� �� �� �� j� �� 2� c� �� �� �� �� �� �� �� I� 8� � �� �� �� m� �� S� 7� C� �� #� �� !� � � 0� ?� �� �� � E� D� �� _� �� �� �� �� �� �� T� X� �� �� k� |� X� �� �� �� �� p� S� c� �� #� -� � �� �� !�
� L� �� �� �� �� X� � �� *� ^� ;� ;� �� C� <� c� &� �� �� �� �� A� 5� �� �� �� &� \� �� �� �� m� }� �� m� B� �� � ��
�
+� �� �� �� �� `� �� �� �� l� �� �� �� 9� n� E� P� �� �� F� 1� |� �� o� d� f� �� �� �� �� �� �� �� e� F�
� &� .� K� �� �� �� �� m� *� � �� �� � �� �� � �� �� � �� �� �� �� �� �� ��
� O� �� �� ��
� ?� Q� �� m� W� {� U� T� +� y� �� �� �� u� �� �� �� � �� E� �� �� �� �� �� �� 5� �� 4� E� Q� �� T� d� �� �� � �� �� �� �� �� Z� �� *�
� D� �� R� A� �� �� �� W� 8� ��
� � �� �� �� �� �� E� g� m� I� c� � � '� a� x� �� D� �� �� v� �� �� k� q� �� 6� �� 3� n� ,� �
� !� �� U� D� � �� �� �� �� �� �� �� ,� ��
� �� �� �� �� �� ?� +� �� '� I� *� �� �� �� �� =� �� �� � �� x� �� �� � � D� .� �� � � � �� �� �� �� 3� B� �� �� �� �� �� �� �� �� �� � i� ]� :� =� m� =� q� s� Y� �� �� �� �� �� ~� /� �� /� 2� ��
� �� �� � � �� �� � �� � �� �� �� �� �� �� "� ��
� � I� U� W� �� �� }� @� � *� �� t� �� �� �� �� �� r� t� �� �� � 8� � ~� e� �� �� ��
� � � U� +� � � �� �� � �� � � �� � {� Q� 2� �� }� W� �� R� �� �� �� k� ,� � ]� �� +� b� o� � 6� � �� �� �� �� d� ?� k� �� c� � >� �� �� u� z� �� �� m� �� �� f� >� ^� �� ��
+� � �� �� c� R� �� � � ��
� 9� �� �� � �� � Z� �� �� �� �� �� ]� ^� >� /� ^� :� � N� A� �� �� �� �� �� �� �� y� 9� ^� f� m� �� e� �� � @� �� �� �� � �� �� ,� ��
+�
� 1� ��
� !� 2� J� L� a� {� #� �� � � �� �� �� ��
� �� �� 9� r� �� /� u� �� �� �� m� �� �� �� �� ^� �� �� � ?� t� }� �� �� �� �� �� �� X� �� "� <� G� � � � �� W� r� $� �� M� g� � �� ;� � �
� �� �� �� �� �� �� }� �� � �� b� a� �� �� �� �� r� \� � � � � �� �� � � �� �� �� �� �� �� �� �� �� �� �� � p� g� Z� � �� �� �� �� � <�
� �� �� � �� �� � 3� j� b� _� � �� �� g� Y� +� ]� �� �� �� �� �� �� �� �� � I� �� �� 8� R�
� ��
�
+� �� � �
� %� 8� H� �� �� �� �� &�
� �� �� �� �� �� �� � �� e� �� �� f� �� n� �� 1�
� h� b� ]� �� �� �� �� �� �� �� &� C� j� �� �� �� �� �� c� T� �� I� � � ��
� )� ?� q� l� j� P� �� �� �� -� m� �� �� d� Q� 6� �� �� �� x� `� �� ^� 9� #� � � �� 3� d� f� ]� A� �� �� ��
� �� B� �� �� �� � +� � ��
+� q� �� �� y� N� @� (� P� 5� �
� � �� �� �� �� �� e� T� k� H� e� �� �� 8� �� �� �� �� �� �� ~� �� �� p� �� �� �� �� �� �� {� �� �� �� �� n� �� G� g� �� �� �� � +�
� � � � K� T� %� !� ��
+� �� �� �� � � �� �� �� �� � "� �� �� �� �� �� �� 7� �� �� �� �� =� \� o� �� �� (� 1� � M� -� *�
� �� �� h� m� � A� Y� +�
� � � K� X� 9� �� �� �� �� m� l� �� �� �� �� �� �� �� �� �� �� �� � H� {� Q� �� � K� � �� l� �� �� �� ~� �� �� z� �� �� �� �� �� �� �� �� �� c� a� H� w� �� M� <�
� �� �� �� �� �� �� �� �� �� v� z� <� j� �� �� �� �� �� �� �� �� �� �� �� v� 9� }� �� �� �� g� �� �� � �� �� �� �� �� �� �� �
� �� z� [� l� �� � �� � '� B� �� �� �� �� �� �� l� �� �� �� �� �� �� � I� 8� �� �� �� � D� �� H� 6� -� �� �� �� �� �� �� � 2� Q� �� �� �� �� b� �� �� �� B� t� �� v� [...]
+� Q� � �� W� y� t� Q� V� �� �� �� �� �� �� �� Y� O� �� �� �� �� j� Z� ;� Q� �� � �� �� �� �� n� 1� � �� �� V� ;� �� �� �� �� �� �� �� "� � �� �� �� �� � �� �� � �� �� � 0� #� �� �� �� �� �� �� � �� Z� 8� !�
+� 8� � �� �� v� �� �� ^� i� �� ~� E� �� B� �� p� � }� d� Y� s� �� �� � �� �� "� 8� � �� [� � 5� :� �� +� N� m� �� 4� b� r� G� ?� '� d� �� f� S� ;� )� +� � .�
� �� �� �� �� �� .� � � �� �� �� C� @� r� �� �� �� B�
� "� -� &� �� �� ��
+� �� �� �� �� �� �� �� �� �� �� c� 5� 9� �� �� �� [� 7� =� E� *� )� _�
� �� �� �� R� 5� 5� � I� �� �� � l� �� v� $� 0� R� � �� O� Q� � �� �� �� _� ^� � $� 3� �� � U� 4� [� �� �� �� �� �� �� �� �� �� �� �� �� \� G� � >� Z� �
� M� \� �� �� >� u� �� �� S� � �� f� �� �� �� �� �� t� t� *� ?� � `� S� �� �� -� �� �� �� � �� �� 4� 9� �� �� � B� +� [� �� i� ^� I� W� m� H� ]� V� 6�
� H� 9� � R� �� �� �� �� �� �� �� � U� �Y �Y �Y �Y
Z �Y nY |Y \Y wY �Y �Y 2Y �X �X �X 5Y cY �Y �Y � [...]
+Y �X ~X
X �X �X UX ,X X �X vY �Y �Y ,Z �Y yY BY 5Y �X �X Y �Y �Y �Y �Y aY �X �X �X ZY iY ZY ZY 7Y �X �X �X �X �X Y �X Y �X Y Y +Y KY JY �Y �Y �Y �Y �Y �Y �Y WY GY :Y |Y vY �Y �Y �Y xY *Y CY DY nY iY =Y Y 5Y tY �Y xY �Y �Y �Y �Y {Y �Y �Y -Z =Z �Y \Y �Y Z
+Z �Y �Y FY �X Y Y �X )Y SY gY 5Y
Y qY $Y �X
Y Y =Y �X �X �X �X �X $Y Y �X �X �X qX �X �X |X YX "X X oX �X �X �X
Y �X {X JX X &X [X �W �W �W @X 6X �W X &X QX �X �X �X UX X �W �W �W �W �W
+X
X �W #X wX �X �X �X �X �X �X �X �X �X �X Y �X �X �X Y Y �X AX �X �X Y �X �X �X �X �X Y �X �X �X �X �X �X �X �X gX bX *X �W �W �W �W �W X X X �W X WX @X
X X �X 1Y �X X �W ]W �W �W �W �W X �W �W �W �W JX "X �W =W �W �W pW nW RW �W #X �W �W �W X �W TX �X
X �W W bW �W CW WW (W UW �W %X �W X �X JX �W W *W xW �W �W �W [W bW rW �W �W �W FW W �V �V zW �W X �W vW >W �W �W X X X JX �W �W �W �W X �X �X X �W X
X UX �X �X X �W aX /X �W X dX �X �X �X qX �X �X RX X �W � [...]
X �W �W ;W 5W �V W 8W <W mW �W �W �W �W �W 3W W �V %W :W @W pW ?W �V �V �V 'W W �V �V �V �V
W
W �V 9W OW yW �W LW W �V -W �V �V �V :W �V
W OW 2W AW nW �V �V �V �V �V �W eW 8W DW �V bV �V �V 0V [V KV V �U �U �U HV iV �V &W TW ;W �V kV �V
+W �V <W 5W �V �V �V 1W OW SW _W �W CW GW nW =W iW �W _W �W �W �W �W �W �W �W �W ZW
W
W TW �W �W �W X <X �W NW qW �W �W �W ?X IX �X &X AX �X �X sX �X �X �X �X �X �X
Y >Y 3Y �X .Y �Y Z �Y �Y �Y 3Y
Y �X 3Y nY yY �Y �Y �Y �Y �Y ;Y Y �X �X �X NY bY �Y �Y �Y �Y �Y aY eY �Y �Y 8Y �X Y Y �X �X �X bX }X Y EY 'Y QY yY �Y ^Y JY �X �X �X
Y 8Y lY Y `Y ]Y 4Y
Y BY Y �X
+Y hY AY �X �X Y �X XX �X X �W bW �W �W 3X �W �W �W �W �W �W ,X iX X �W �W �W �W QW W �V W �W �W �W |W �W fW &W �V �V ?W �W rW W W �V UV �V W W
W W RW �W bW W �W fX ?X UX AX X X �W �W �W HW W W �W MX �X �X fX �X �X �X �X �X �X �X PY [Y �X �X �X (Y �Y pY �Y �Y pY Y
Y Y Y
Y Y
+Y �Y Z �Y �Y bY FY #Y �X Y �X �X Y Y �X �X �X �X �X �X �X �X .X X �W �W �X {X �X >X hX gX �X �X "Y GY Y Y
Y Y �X 7Y #Y �X �X #Y �X `X �X �X Y Y �X �X �X �X �X �X �X �X �X pX YX �X �X �X �X �X �X nX sX ,X �W �W �W RW |W �W eX iX �W �W pX �X �X 6X =X 'X �W �W �W �W zW UW @W W (W XW LW W W IW tW "W �V �V �V MV 'V UV V �U �U �U JU �U �U �U mU U �U �U �U ~U 4U �T \T oT jT `T 6T #T �S �S �S 6S �R �R �R �R �R �R �R �R �R �R �R �R sR R �Q �Q -R �R tR R >R �R �R dR eR KR \R �R � [...]
+S �R 3S �R �R �R �R �R �R �R �R HS �S OS wS �S T T
T �S T mT 9T �T &U �T �T �T (U ~U yU �U 2V $V �U
V V �U $V /V FV TV �V �V �V �V �V W �V �V ,W fW cW �W �W �W gW �W pW mW JW 7W RW fW UW zW zW �W +W W |W �W �W qW kW sW
W !W
W W �V W !W �V �V `V �V �V vV \V ZV ,V V SV =V �V �V �V �V �V qV VV _V �V �V �V �V 3V �V �V yV �V �V �V �V �V �V �V W �V �V W �V �V �V UW ;W :W vW dW W 4W kW �W .W ZW �W �W �W �W X X �W �W �W �W �W �W X �W �W �W �W X �W �W �W �W �W �W X xX �W �W X �W �W X �W $X �W �W �W X VX IX 5X (X �W �W �W �W �W [...]
+U �T �T �T �T U 8U �T �T U U VU 7U RU YU
U �T �T ;U �T �T <U 9U %U 9U HU mU �U
V 7V �U �U �U �V pV @V [V xV lV 7V YV 4V )V V 2V hV NV mV XV {V ~V �V uV nV 8V 2V kV ,V V WV :V �U �U V ]V @V ]V TV VV �V .V �U �U �U BV �U �U PV �V �V VV <V >V -V V ,V V V UV |V cV -V V V .V NV V V $V HV yV �V hV `V �V �V �V �V =V bV �V tV �U �U 8V ZV V �U �U �U �U �U �U �U �U �U V V �U �U {U �U JU #U FU ;U jU $U /U U �T \T �T U U �T U yT ~T `T �T @U U �T �T �T �T �T �T �T �T �T �T uT { [...]
V FV V V mV JV �U �U �U V MV 6V V jV 6V V V V �U �U �U �U *V KV �U mU -V ZV 'V <V bV LV nV WV KV ;V �U BV {V 5V V �U �U �U #V 9V 'V 9V IV nV �V �V �V �V �W��W��W��W��W��W��W��W��W��W��W��W�~W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W��W�zW�yW��W��W��W��W��W��W��W��W��W��W��W��W��W��W�X��W��W��W��W�}W�UW��W�X��W��W��W�W��W��W��W��W��W�gW�{W��W��W��W��W��W��W��W��W��W�yW��W��W��W [...]
�l�ÙR������z��Ι��ș����ҙ��&�j����֙
��������7�-���t�����g�����+���
������֗?��<���4�n�$����|���O���:������0�
+��!�Ǚ�� �$�4�������9��(��q�l����ę.��7�K���T�����7���{�����j���יw�������ɛn���}��L�_�'������!��������d�����7�i���ߙי#�ٚ�V�!�y������J����q������ŘĘ
�+�ʘ��b�����d�$�[�ԗH������e�o�����Z���R�E�.�p�m�:�5������×��h�
�� �|����t�q�ܗ���9��]�w��������t���t�
��'���ܕĕו��ܕ��h�ŗs���ݘ����w�
�
���� �
+�����z�-�Z���әə������P�����ϙ����1�����
���͘���
�E������k�3������T�"�Ә"����Ǘȗ
��Ϙݘ��ݙ�����l�p�0���4���n���3�<���*�c�Й7����
+�
����ܗA��������M�ژ��s����O�����E�l�
�;����������w������Е'�
�������b�ʕB��
������"�:�����ϓ��~�G�w�ʑ���%�)�����D��������p�Ė����Ӕ�����=�Ɣ~�{�����E�.������5���|�����ؒ��F�����\���
�����+�z�+�����\�
���s������'�������������?���b�
���U�=��5�����Д��Q�z�4�7�E�ٕؕ���4��� ������o�Ιҙ���-���j�)�?��0�ș֙ڙǙA���$ [...]
������˖�������`�b������!��R�ǘ��������������@�a����,��m�������!�Z�
���Q�2����ޔ��#�
�1���i�!�;����n�����@��r��%���/�����|�ݖm�ݗ
+��ٗ��=�[����Ҕ������
�����[�,��ĕѕɕ��ٕ��W�ۗ��$�C�]���J�]�s���
��������o�2���
�Țj�Л̛������;���j����D������י��^���
�z�4�(���
��ҝ�����U���o�����̞�����D�/��h�śR������������'���D�}�����
+�
�����������`��g�� ��қ]���ۚ˚ �>�������Z�+�ƚ���J�p�������1�'�,����C�l���^�Z����:�Q�
������)��˖@�^���.�s�;�ۓe�<����Ւ��a���K�M���d�ݔ_�o�������ْ͒/�p����&� ���&�
�������a�[��w�R�?�V�1���.�W�
������1�����a��͕���t���D�J���%�}�����7�������(�!�&�Җ~���6�0�"��a���������ΗW�2�<��������D�����)�5�5�����P�
�^�j [...]
��Ɠ���ْV���Ɠ��ϓ#�`�#�ؓ��a�P�U�+���-�"�{������0���e����������� �e�Y�p���ɏ�� �+�ُS�G�<������.�P�
�����D�H�����p�I�ǎ����������ď��[���Ր��������i�w�h�D�u���5�M�c����ʐ����B���K�����ԐH����������E���̓��o�N�9���;�����Ք̔�7�5�����Օ��6�8�<���/����̓���������N�Y�ޓ9�͔����^�A���������S�
����
�a��K�C� �E������h�U�j���N�w����-���������ה ���B���Q������œ������F�
��� �������J�
�����������q�Q�ג&�M�C�s���ɑޑ"�����=�����������j�&�ɐW������n������E�Əs���������K���������� � �`�j����(���
��������2��6���R�x�����7�-�8�����ё
�"�E���x������Ԓ֒��ђ�Ғ|���
+������~������Ӕ��!�&���+������������q����U�����0�������;�
�<�_�)�$�֓
+���ג;�{�m�����i�y�x�|�n�ؓ,���ғ��%��ӓP�ߒO�����ʒ��Œm�(���R����W���������K��2�U� �k���������َ�H�"���L�}������������0���y���Ԏ!�9�
�
�g���6���������+���.�j�p������w��m���v���U��<����]�U����4������
�Y���q�Q�R�I�b�'�M���C��-��ތ����ɌA������'�k�z�����h�~�N�ȍ���q�\�G�����������Q�f���F�ڎߎ^� �]��������`�����T�C���e� [...]
����P�f���t�3���7�]�_�
+�Ԑʐ������T�{�?�h�:�F�4� ������~�?����q���.�\����(���(�G���ώɎ��Ɏˎm���������p�C��n�P����ڍ��}�O�m�_�q�;�)� �B�����������5�܋!�}�Č���ԋ �2�܋��c�����7�^������t�q���������������Njދ�������D�^�������+�4�(�t���w�]�
�%�Nj��
�ً��R�Ԍ�����ō����g����?�}�)�
�Ό��ƌ�����
�2�4�����T�S�����������Ѝ>�z�Վ
�K�q�=�*��q�$�U�t�;��������=�ȏ�ڏ�ۏ�+�)�H�?�c�1�2�Y���ۏʏ����&��z�}���ɑ���O����3���͑��
���^�!����v�
���#����
�אߐC�W�f�1���������A�����4����������Ï��ϏN�/���c�.�.�����ŏȏl�����ێ؎��b���������p�������R�{�B���k�����y�k�����L�����������^���x��j���1��O���������؍A�b�ݍ��l�|�����X�8��.���D����$��
�-�6�-��ҍ$�ю��������Y���4�:�U���Վ�Q�Q������ŏď��y�}�������������=���J���
�����m�e��������z�_���(�6�����͐ې�� ������u�v�����K�\�R���&���������x��������������j�1�����:�����c�]�����������������o��`����S�����<���������E���o�/�L�����|�[�^����� � ����������^���������w�����������t�D�
��������;� �������������B�#�0� [...]
+���A�������
+�]�z�'�P�c�������:����?�D�k���
�g�$���P������#�f�X�?�������������������������;�������F�<�����u��8�W����t���:�q��c������2�������?�����������8�����+���H�9������K�c�b�����4������o�A���B�����{�P�/�"�>���@�5���������I�K�����������{���1�F�e������j�
��� �
�����a���9���/��C�@���'���-�p���3���9�.���w���!�����V�����.������i�����M� �O���"�}���i�!�<���=� [...]
���g�X�]����������������3�����O�3�]��������������8���������
�h�M���A�_�U��������������A�~��3�
�����<�a�e�v�O��i�7���|�����������_�����_�������W���6�)��������� �|�|�����?�E�h����E�
���
���"�V���^�������
+��������n��������z�?��f����l���S���������^����9�!��������s�+�L���|�������� �|�T�b���,�=�P�w���k������H�@���,�z����i���J�g�#�2�y���y��������1�}�s�)�@�q��o�&�Y�������9�����i���/�&�6�����*���0���������?����P�����J�9��L����������@����������[�������s���y���Y�*���/�����s���������
���������
�Y�V�����n�O�
�R��������'�`���
���:�E�9�W����������4���������(���d�Z�J���+�������O���=�����
�F�������K�M�����,�J����-�h���E�������������@������������q�~�Z�~����������v���+�/�m���=���5�����L�����g�n���������"���/�����b�0����N�����Q���@���K�������m������E�����[�/����Q�e�����g���8���X�3��������������� [...]
��
�H��������������+�j����� �H�x�'���I�����4�
�����'�R�
�H�?�����
�9���&�����������������9�����J�m�V�����"�
+�������c�4�;�����������������������)�!�R���w�O�R�o�H�j�l�����^�������������[���M�������������������>�v�+���b�~�o����������� �'���%���i�������P�U���������.������������@���]���)�������������h�������t�������2�����D���|���M�
+����������������i���9����������������������;�v�G�|�h���F����m�������
� ���
�I����=������������[���������9�`���l���F������c�u�����q���9�����F�y���!��������~����!���������������:���x�������������{�}���r����������H���
�������������������Q������P�����������r�M�������������
���������.�f�i�R���i�����;���%�k�L��������j�
���������������@�����Y�+�O��;�R�������3����������4�:�������2����������Q� ���a�>�s�x���\�#�����F�����N�����#�]�V�����������2�U�w�(�%�����
+�������/�<��"��/��B�U����A�Y�\�{�f�~���������@�"�����l�����W�����\��������{�&��������,�W���[�����[����������4�"�����g�'�k����������X�v���=�������������#�Z�1�o�������������k�?�|�������)�h�!�-�����������;�{���$��#�������r���m�����9�t�����\���#���'����������������Q�%�#������� �����j���E�1�*�8���*�[�����t�M�E�
������ [...]
+��3��+�~���B�����g�����i���
�H�����8�T���O�d�c�,�f�3������6�Ȉ��5�����O�g���"�.�4�
���2�3�̇؇ �چֆ��^�p�߆؆�W�E��9� �����2�)�Յ1�
�,�����#���]�ʄ�U����o�R��������D������y�����������ԃV�����ڃU�����~�����(�G�r��{�����J�Ԃ�O���Q�0��˃������H�.�����'�܄W��K������Dž�I�\������P�!�������)�Å
�������~���������j��\���s�Ȅ���y�Å�����7��������ȆR [...]
�)�y� �V����o�����̃E�����g���ąT���`���q���'�ф�����T� ���C�����3��5��ҁF������Q���Z�����.�����Y�6��wQ����������~
~�}�}�}�}�~���~w~�}�}~\~F~T~|}�|#|�|\}\~
@�~s~�}�}�}�~�~J~�}�}�}�~9�~A}
|�{
|K}/~�~5~�}-~W~ ~�}M}�|G|K{2{�{Q};~�~[~k}�|�|�}������f���~�~F�x�~�}l}�}�~L��*�X��
+�~�~n�%���~I~T~�~�"��ڀ��z������~M~�}�}c~U����E���%�%{~�}~�~KB���
+�Sj�
������T����-�b���J�[������O�+���
�_���|������?T�V�/��������������]�
+��
+�~�~H~�~�K���~�}V}f}Z}R}i}�}�}�||M|W|�|�|�|�|v{�z�z�z z�yWz_zKzkzOz�y�xAxdx_x,xBx�xAx�w�v�t,uv�vwwweww�vxu�t�u�v�w�w"w�vwIw�wwMv�uvu�u�u/v
+v�tFt�t�t<u�u�vfwNw2wrv�u�u�usu�u�vGw\x�x�xex�w0ww�w^x�w�vqv�v�v�v
+v[uQu�u v�u!v�vFw`x�xx�w�w?ww�v�v[w�w�w�v�uTu�u�v�wy�y�yz�y_xIxx�w�wIx�w�w�w>w�wxxx*y�y�yy�xlx�w�w�v�uv
v�vx�xy>yymx�w�v�w�x�x�xsxkx�w�w�w�wuw�v�v<vPulu�u^vlw�wwav7v�u4u-t.s�rar~r�rTs�s9szs�sNs�rs�r�r�r�r�q�qEq�p�pp�o�o�op�oZo o�n�n
o�o
+ppo�m�l�k�k�kNlYl�l�l*l=l�k9kk�k|lllDk�jj-j�jk�k
l9l!l ldk�jj!j�j_jjj�ij
j�i�i�i�i�i�j/k"k�j�j�j>k}kgk�kpk�k�k�k,lylJl�l�l�lzlPl�kPkk�k�k�k�l�m�mhm�m
n�mlmAm|m�m�np�o8o�n�n,oFoo�no�o�o�p�qir�q�q q�p�pyp
+p�o�o�oWp�p�p+q�p�p�pp�p�p�p�p6q r�r�r�rRr�rRr�qq�p�ppq:q�pIqgr�rr.r�r�rer
s�r@r�q�q�qBrs$szr#rrzrs
s�r=r�r�rAr�qr�qSqkqr�rsvrrbrs4s�r�rr�qq�p�ptq�pRp?p�o�opDo�noJo�op]p`p�p�qrr�q�q}rr�qjqq qFq�p�ooUn�mn n�m�m�mEn_nln�n�nZnn[n�n�n{nKn�mEmOm4m�m�n�n*nRn�n�o�oSp�pRp�o
o`n�mHnn�m�mn?n�n`nhm�mwm�m9nn�m� [...]
n�n�op�o�o�n�nzo%p�pzp�o�opKpdp�p8p
+p�p�p p�o$p�p�q
r^rr3rr�qr�r:s�stotptKt)tTt�t@u�u�u�u�tqt�t�t�u'v�v&w�wowzw�w�w�wwKw9x�wiwAw�vAw�w�x
y,y�xTxfx�w|wowww�v�v�v�v�v)w�w�w�w8w�v�v�v�v�v
w�w�w�w�wwwMwfwx]x x�w�w�w�w xxExx�wpx�x�x�x�xx�wx9x�wkw�w�w�w]x�x�x�x�x�y�y�y�y�ycyy�xRx)x<x
xxx�w�wSwSw�w�w�w�wx�w�wx�w�w�wxwxZx�w�vAv�u$vTv�v�v4ww�v�uu�t�tculu�u�u�u�u
v^v�v&w w�v w�vw
w�wxx�w�v)w#x�x;y�y7yKx7x�xNx�x<yjypy�y�ysy�y�yz�zdzQz�zvzlz�z�z,{{{�z�yz�z@{a{�{�{<|]|]|Q|3|a|�|�|�|�{2{Q{|g|�|�|�|�|<| |j|�|k|L|<|�|�|�|}�|�|�|Z|4|�{3|~|�|w|;|�{E|@|U|�|�|�|1} }�|}(}�|�|u|�|�{�{G|P|�{<{uz�y�y�y�y�y�z [...]
+x4wDw�w
x�w�w�w�w�w�ww�v�vyv�v�v
+wDwxFxBx xx�w
w�v
w�wFx�xQxex�w�w�v�v�v1w�wKww�v�v�v�vsvnv�v�v�vpv�v�vwxww�v}vbv�v�v�v�vjv�v-w}w�wx/x+xx�wLw�wx�w;w/w=w�w�w�wx�w%xxQx�w�w�w]x�x{x6xxUx�x�xy>y�y�y�y�y�yy�x�x�x5y�y0z�y�y�y�y�y�y�yzz�yDyYy�yJyVyqy1yryLyWy�y�y�y8z�zU{�{{_z9zfzcz�y�yKzSz�y
z7z�z�z�z*{�{�{�{�{�{r{�{
|
||�{�{�{�{�{^{�{R{�{�{�{�{9{{�z�z�z�{2|B|M|�{�z|z!zLz#z�y�y�y�y�y�y
z�y<y�ynyCyy�xbxNxRxgxuxux�x�x�xkxDxbx[xxYw�v�v�v�v:w:w�v.v.v�u�t�t�t�t�t�t�t�t�t�t�t*uGuuu`u�u�u�uu�tuMuru�u�u�uMu�t�t�t'u|ufuOuru�u|uEu8uxu~u�ucu�u�u�u9u�u�u�u�usu�u�u�uruwuuuluRu
u�t�t�ttRt�t�t�t�tPu�u�u�u�u<v�uuu�t�tu [...]
xKwfw0w�w*x�x�x`yby�x�wcwgw�wxdx
x�wZw4wFwAwbw�w�wuwww^wFw8wowQw0w wgv<vCvMvv
v�vwAww�vowxwNwQw�v�v�vw�w�w�w�w�v�v�v�vZv�v�v�v�v�v"w�w�w:ww
w&wIw�w6w�v�v�v;w�wfx�x�x�x�x�x>x�ww(w�v*w�w2wv�u�u�u�v�w
x�x�x�x y
+y�x�xy�y�yz�y<y�xKxHx�x�x�x�x�x;y�yPzNz�z{
{�zz$z�y|y�y�yoy�ySy�xyoy[y�y�y;zpzGzgz�zrS�yS�pS��S��S�_S�S�mS��S�cS�oS�US�CS��S�oS�S�US�@S�dS�uS�;S�]S�~S�RS��S�zS�MS�ES��S�US�XS�@S�rS��S�`S��S�mS�HS��S��S�gS�YS��S�eS�|S�\S�pS��S�BS�[S�wS�kS�qS�aS�XS��S�SS��S�cS��S�jS�S�uS��S�iS�SS�iS�LS�pS��S�pS��S�_S�uS��S�KS�fS�;S��S��S�XS�&S�]S��S�8S�$S��S��S�\S�~S��S�iS��S��S��S��S�IS�bS��S��S�CS�FS��S�`S��S�cS�mS�[S��S��S�WS�S�OS�^S�qS�tS�jS�US�{S�u [...]
tEt7t
t�s&s�r�s�s�tru(uWt�sZs�r�rJs�s�sus�s�s�sYt�tu�u�u�tqs(s}s�st t
t�s�ss�r�r�sos�r�r�st�s�s1t�s�rZr�q�q�qIr�rNrrlr9s�s�s�sQs:s�rGrnr>sws�rZr�q[quqrqbq�qr�q�q�qFr�rws-s�rs�rcrGr�r�r�r�rDrArrOr�r�r:s�s(s�q�qQr�r�r�rmr�q�q_rZr�rr�r�r�q/qsq�qr�r�r s_s�s�s�stIt't�sCsKs<s�r�r�s�s�sgs�r�r<s�sCt�s�sfs�s�s�s
ser�r/s�s<s�r�r�r�r*sbs"s�rs:sxs]ss2s�s�t\u�ubu�tLt�s(s�r�r�r;s
t5t�s9s�q�q.rZr�r�s [...]
+sXr�q�qr�r�rbrtrzr�rEs�s�s�sjsr
r,rRr�r�r�r)r�rs�r�r!s3s�s�stsUsZs�s�s�s�s�s�s?s"rr�r�r�r�r sgs�sEtAt~s�r�r�r�r�r�r(s shr�q�pp�pqCpmp
q]qqq�q[q�p�p
q�q`r�q�o�n�n�oLp�o
p_p�pop/p�p�p
p�o�o�o
p5oynn�n�o�o�o&pKp�o�o�oWo6o#o,o)o�n�n�n[o�oYp�p�o�oo�n�mm/m9n
o�nqn'nn�nmo�o\o�n|n�nto�o�o�n�n
o�o+pkpJp"pep
p�o�o�pjq�q�q�p4p�o�o}p�pjp�oxo�opop?q�q�q�q
+rr�r�rfrr�q�q�q]r�rwr?r-r�q�q�pop�p�p�p)p�o�o�o�pjr�r�r�r\s6sFs�s&t�s`s�r~rgr(s�t]u�tmt?t?tit�t�t�tkt�s�s�s
+t
u�t�s
s�s+t�t u�t+t~t&uv+v\u$u.u3uu�t6uvu7uu u!uSu�uNu�ttxt�t{t�tu�u�u�u�uYu�t�s�s�s�s�s
+s�r~r�r�rAs�s�sJt�tWuu�ssUs�s]sds:s�r�r�r#s�sjsBs�r]rrrrOr�qAqlq�qtq�p�p�p�p�oSo�o�o�o�o�o�oIo/n m
m�m6nfn�n�n�n�n�nen�n�o?ppap:pp?p�p�p�p�ppp�pfp'p�op�o�o�p�pMp�opYp�p
q�pXpop1p�o�p�qr�r�rar=r�q2qq�q�q�q�q�q�q�q�q�q�q~q�qor�r�st
+tt�s!s�s<t/t*t1t�sSt�t�t�t�t{tmt�t*uOuuuJu�t�s�s~ss"s�st�t�t�t�tu�u�u]vw�v
wCw#w�v:v�u�u�u�vGw5w
w:w�vev�u�u�vww�vHv�u�u�upu�uv�u�u#vv
u�tmu�u�u�uku�t�tOt"t�s[s_s�sIt;t
t�s-s�rdr�r�r|rr&rsrXr"r5rCrr�q�q�q�q�q�qSq�p�p�p�p�p�p�pq�pqp�o�oqo[o6oLo[o9ooo�n�n�nBo)o�n�n�n�m�m n_n�n�n�nnn�nRnZn/nnxn<nnOn`nnnn�m m�l�l&m�mln�nSn�m�mEnjnWn�nbn�n5n�no�no2oo�n�njoVo�n0oo�n�n�o�p�p�p3p�p]q�q�q q�ppq<qq�pop�p*qq�p�p�p�p0q.rNr�q�q�q�q�qFq:q�p�p~p�pq}q�qr<r�r�rQr�rar�q=r�rhr;r�rr
r�q�qeq�p�p [...]
p7p�o�o
pYp
+pqo@oo�o�o�oco�n�nynBnn�no�no�n�n�nPn+n�mnn�m)n^n=nnn7n�m�m�m�m�m$m�l�l�l�l]l6ll>l�l�l�l�l�lm�l"l�k�kxkKktk,k
+k�j�j*jjIj/j�j=kkej�i�ijPj�j`k�j<j6j�i�i�j�j|j�j�j�j�j�j�ijtj+k�klk*k�j�j\jj#j�jzk�k�k4l,l�k�k�kl�kNk�j!k�k
+lSl#ll|l�l�l?ll]l�l
m@m&m2mmfm�m"n�n�n!o�o�oPoOoRo\o�o
p^pZp%pxpupKp�p�p�pXqeq�p�pCqq�pkp`p�plpsp�pFpWp�p�p�pip�o�o�opCp�p�pp�o o�n�n�no�n�n�n�n�nfn�m�mmnEoro%o�n�n�n�nJo�o�o�o�oxo�oFp;pop\pvpNq�q�q�q<q�p�pqq�p�p�p�p�pq�qcqMq2q�p�p�p�p�pq6q
q�p�pcpPp7pp�oEoCo�o�o�o�o�o�oooo9o�n�n�n�n9nFn{n&n�m�m0nIntn�n�n�nzn:n�m�m�mnRnzn#n�m�m�m�mn�mxm�m�m
+n�no&o9ooo�nuop�o
ppto�n2o�o�o�op1pKp�p�p�p�p~p�p�pqq�qKqqqq�q�q�q�q�qmq�q7r�r�r�rlr�rs�rss�r�r�rs�r.r-r�r ss�r
s�rGrrtr�r�r s�r�rgrNr�r�r�r�r�rrr`r�r�r�r�r�r�r�r�r�r�r�r�r�r�rNr+r�qHq:q&q:q�p�pq%qUq)q�p�p5p�o@o�o�o�o2oCo
p
p�okpCp�o_o�n�nknnnen�njnVnn�m>n8n�mzm�m�m�m�l�l�l�l1m�mn�m�m�mnbmLm3m�lGm�m'm�l�l�lm&m
m m�l.l�lym�m�m�m�m5m&m�l�l�l�l0m�l�lElhl�lm�lcl�l�l_l�k_k�ktl2mm�l�l�l�lWm�m�mxm�m�m9nwn�n�n�n�n{nonvn�nGnnnn<n n�mkn�no�n�npnnVn�n�n�n�n�n�n*oFo�oLo�o�o?ooDo
o�n�n
oXo'p5p p�p�p�p�p�pp;p{p�p�p�p�p�p�p�pmp�p"q�qr�q�q�qjq�qDr [...]
+lvk�k�k�k�kpk�kFl�k�kdk�k<llRll3l+l�kl4l�k�lm�m njnEn@n�n�nen,n�mpmtmen�n�nn�mn�no?o$oXo:o�n�njn�n�n�n;ouoao}o�o*ppp4p
+p�o�o5o�n;o#pAp�o�o6pQp�p�q�q|qoqQq�q�q�qq�p�p�pzp�pq�p�pq�q
r�r�rYsOsNsnsJs{sasurr�r�r�rs�r�r�r�rkr@r!r2r
r�qrEr�r�r�r�rAr�q�q�q�q"q\p}p�p�p�p�p�p�pTp
p,p�o�oAp>p�opsp�pqpzp�p�p�p�pMp p�o�o]pp�o�o�odoLo�no�n�n�n
oo�n�n�n�nCn
nnn�nWn:n3n�n�nXn�n�n�n�n�no�n o�nJnTn�n�n�n!o�oo�o
p8p�pIp�omo|oioSoCo"o�n�noOoGo�o�o�o(oo_o�o�o�o�o�o�oCp�o�obo<oooo�noQo�op4pp�o�o�o�odp�pXpCp%pfp�p
q6q�p�pqcqBqq
qEqDq�p�p�p�p�p)qIqWq
q�pnp�p�pqzq�q�q�q�q�qr} �| (} �} �} �} } �| �| �| A| �{ d{ *{ �z { v{ �{ a| -} �} /} p| �| �| } a} �| l| �| �| R} �} �} �} 8} �|
| | g| �| �|
| �{ �{ 5{ �| �} ~ "} �| �{ �z �y �y }z �z z{ L| �{ �{ �{ | f| �| B| ${ /z �y �y �z S{ �{ �{ 1{ wz �y hy !z { +{ �z R{ �{ | @| �| �| �{ { _z ?z Iz �y z �z �y �y Mz �z f{ �{ | | X{ �z �z Zz Oz 3z
+z �y �y �y �y �y gz �z wz %z Sz fz �z { �{ �{ R{ �{ �{ �z Qz �z {
{ }z
z _z Bz �y �y (z s{ | 7{ %z Fz c{
+| 8| J| �{ �{ 8{ 2z �y ez �z �z �y \y My ky z �z �{ �{ ~{ y{ �{ | Z{ E{ �{
| 8| �{ �{ �{ k{ �z �z Xz ez �z �z �z jz
{ d{ { M{ b{ �{ �{ U{ �z \z �z 0{ <{ T{ �{ �{ | 8| �{ �{ { yz �y Iy 9y �x �x y �y �{ | �|
} �| | w{ m{
+{ �z { | �{ <{ { �z &z �y �z �{ l{ �{ f{ �z <z �z �z �z 5z �y �y �y
z cz �z
{ �{ �{ �{ g{ Q{ �z jz #z /z �y �x Hx �x y �x y wy y �x �x |x Yx )x wx Ex x Kx �x y _y \y �x Hx %x �x �y �z �z �y hy Hy �y �y ry y �x ]x #y Dy �y �z �z { { �z �z �y $z �z 3{ { rz �y qy :y �y �z �z Cz Rz �z �z K{ �{ |{ jz �y �y �z �z �z 1z �z >z $z �y �x ,x �w �v =w ?x 9y �x �w <x nx �x
y �y �y gy [y y 7x
x �x �x 5x �w rw �x Py Ey �x �x �x >y �y �y �y �y �y #z $z �y �y �z
z )y �x y zy z uz z � [...]
v %v �u �u �v �w �w tw �w 6x �w )w w tw �w nw gv �u �u v :v <v 5v ;v �u &u u ru v �v v �u ~v �v �u Ku u ;u u �t ct Jt ~t 7u �u �u *u ^t Jt �t `t Ws
s �r 5s t �t -u �t �t �t `t Zs s \s {s �s ;s rr �q �q �r �s �s fr ;q �p �q ^s �t u �t �t pu �u nu u u *u �t �s :s us et �u �v �u Ft ss 2t �t �u )v ^v ku �t xu �u �u �u �v �v �v �v ov �v vv �u ?u �t �t �u 6v �u �u �u ;v Lv $v v �u �u v �u �u �t u �u qv w �w x �x By �x ,x x Gx Gx .x (x ow �v [w �x yy -y �x )y |y @y =y ?y ky fy [...]
y �y �y �y �y Ay �x +y �x x 6x #x �w �w x Ux �x �x �x ]y 4z �z
z �x Cx !x 4x �x �x Cx �w Sx Rx Dx x �w �w �w 6w �v v Wv �v �v �v �v ?w w
+v �u �u au At Os s 1s �s �t �u �u �t �r Nq >q 2r �r @s �s |s �s s �r �r �s -t �t �t t �s Dt �t \u �u cu u _u �u v �u ]v v Zu �u v �u �u �u v [v �v �v v �u �u �u �t 0u �u �v Tw w �v (w w rv v cv �v jv �u �u
v Fv v �u Du
u v �v �v
w xw �w x �w �w �w x ?x �x Ry My �y Wz �z bz Bz �y Fy `y �y �y �y �z �z "z z �z �z 'z �y Wy �y z Kz !z �y z z yz �z j{ �z rz [z �y �y �x �x �y �y Sz �z { �z 2z Ty �x Qx Hy �z j{
{ 3z �y xy �x x �x �x �x Cx �x �x x
+x py �z "{ ={
{ kz �y Ky �x zx 'x �w pw
x �x �x x lw �w 2w w _w !w �v w x �w �v 0v �u �u jv cv �v \v vu �t `t �s �s 0s �s ^t 8u pu -u �t it �s �s �s �s Ps �r s s zr �r �r ar xr s .s �r �q _q �p �p �p 0q �q �r �r Qr Gr �q �q wq �q &r �q /q cq
r
r �q #q �p xp vp �p "q �q �q �q �q �q
r ir �r s �r ,s s �s �s _s ns �s $s �r �r
s �r Tr #s s dr r kr
t et As Rr �r ws �s �s t 2t Jt �t �u �u �u #u �t u �t
u $u 4u u �u �v Nv xu gu �u u �t
u �t �t �t �t �t ou �u �u �u Qv w �v [w 9w �v v
v pv kv �u
u Ru �u �u 8v �u �t �t �t �t �t �t 9u 6v ov �v v �u *u �t �t �u �u �u 'u �t �t �u �u Yu ku �u |u Iu et �s t Jt 1t t t �s �s �s �s Gt �t [t �s �s /t �s �s %t �s �s �s Zs &s �r 's 6s �r [r $r �r �r �r r �q �q zr s �r �r �r �r �r �r vr r ;r �q �q �q cq �q �q �q �p q fq �q
r Nr r �q vq $q �p �p �p p �o �o Bp �o �o p �o no �n �n �n o ^p jp �o zo zo o �n �n o �n �m Km �l �l rm n "n �m �m �m �m n %n �n No �o p �o so uo |o %o o �n !o �o <p \p Ep �o �o �o Uo jo Yo �n �n o �o �p [...]
+r |r �r Ws �s Ls �r @r Dr �r �r s us t t �s �s >t �t hu �u ku zu Cu �t u ^u �t �t rt Dt �t Yt bt �t �t �t Ru "v �u �t �t �t �t u pu Xu �t wt Ot �s �s �s �t �t u �t t �s s �r yr Ks �s -t �t 4t t �t �t �t �t �t t t t �s Et 1t ft �t �u �u =v �v �v w �v �u �u �u �u �u Fv �u �u �u �u v Av Mv |v gv v �u �u �u $v 9v �u u �t u |u �u �u ku �t �t ju �u �u �u �u uu Au "u u �t �t u �t u �t �t �t �t `t ?t Xt Lt ot �t �t �t �s �s �s �s �s �s ?t �s �s js cs �s �s �s �s s Gs �s �s � [...]
x ;x �x �x lx �x �x �x �x �x �x px �x y y 4y �x �x y �x �x px �x /y �x Wx Bx 5x ]x yx �x y �x �x =x �w �w �w �w aw Aw lw Qw Ww �w �w x Bx Fx �w �w
w _v ]v w Zv �v �v �v w �v �v �v ~v
v �u u
u �t �t �t vt �t �t
u �t Tt �t �t 2t �s
s �r �r _r �q �q �q `r cr [r {r }r ~r Ar r
r yr vr Fq �p �p 5q �q �q �q mq �q r
r �q lq
q ep �p fp �o �o rp �p p �o �o �o �o �o �o �p �p .q �q �q �p �p zp �p �p �p �p nq %q �p �p \p Xp up q Kq �p fp
p Cp Ep �p
q �p ]p �p �p �p �q Xr 7r �q �q -r &s :s �r Or �q �q �q �q fq �q ;r Vr �r �r �r �r �r �s �s �s �s #s �r �r �r Es �s is s -s s ps zs t t �s �s 5s �r �r ir �r �r s �s Nt �t �t !u 7u u �t u �t �t `u �u u �t �t Yu �u @v �u 3u zu �u
+v %v �u v �v Tw x �w �v Qv 9v �u ku pu �u Mv &v �u Pv >v kv �v �v
w �w �w nw w �v �v �v �v 3v �u Jv
v [v `v �u ou u ]u !v �u �u �u �u �u xu
u �u �v
v �u 7v �u Ju �t �t �t �t �t
t Ns �r �r �r �r �r �r
+s �r �r Er r !r &r Gr Kr �r �r `r r �q �q \r �r �r tr �q >q cq �q �q rq �p Ip �o p �o �o
p Bp �o �o �o vo o �n !n Zn �n �n �n n _n �n �n �n �n 0o �o to �o �o oo io >o Bo Eo �o �o o �n �n �n
o �n o mo so yo �o �o �p �o Jo 1o Ko �o zo po wo �o �o
p 2p �p Rq �p p �o Jp �p �p �p <q
q �p �p 'q q Zq �q �q �q Gr _r r �q q �p �q Fr ar Lr Kr
r &r yr �r �r s �s �s (s �r s �s �s t >t �s �s 9s >s �s �s �s �s �s t ls s s �s t �s �s �s �t
u ~u �u yu u �t 4u Eu wu \u �t mt �t �t bu @u Mu �u �u �u �u �v :w �w �w �w �w Vw aw w "v �u �u �u ^u Du �u �u v Kv 3v �u �u �u �u �t Pt yt �t �t Xt Nt +t t �s �s �s �s �s �s �s �s �s �s �r �r Zs �s !s s �s
t �s zs Ts �s 9s �r �r �r s es Gs �r �r ur /r r �q �q �q �q �q �q �q �q �q �q Jr 4r �q Ur r r �q Mq �p q �q r Jr r �q 7q Dq mq Jq q
+q Kq 8q Hq r r �p _p lp ep �p uq iq $q �p �p 1q
+r gr r �q :r nr }r Dr �r �r Lr �q �q 6q �p oq �q �q �q .r gr |r �r �r �r ss \s �r �r �r 7s
s �r 5r �r �r [r @r ?r \r �r Zr wr 5s �s �s �s 5t �s Ks Us �s Et {t �s �s u �t t �s ft qt �t pt �s �s t �t �t �t dt {t >t jt u 7u u u u du vu Qu �t �t 2V��U��U�8V�%V��U��U�V�
V��U��U��U��U�!V�V��U��U�V� V�V��U�V�2V�V� V��U�V��U�*V��U��U��U�V�V��U�>V��U��U�
V�#V��U��U�IV�V��U��U�
V�V��U�V�V�V�%V��U�V��U��U�V�V�1V��U��U��U�V��U��U�V��U�$V�/V��U��U�V�V��U��U�(V�V�=V�sV��U��U� V�V��U��U�.V�
+V��U��U��U��U�V�V�4V�V��U��U�V��U��U��U�LV��U�V�
+V�#V��U�CV�:V��U��U��U��U�V�V��U��U��U�V��U�V�
V�V�:V�V��U��U� V�V��U��U�V��U��U��U�IV��U�V�6V��U��U�
V�?V�V�EV�>V��U� V��U�V��U��U�?V�V�)V��U�V�3V��U��U�
V�V��U�V��U�
V��U�V�V�&V��U�V� V��U��U��U��U��U�V�;V��U�V��U��U��U�V�+V�V�
V��U��U��U�
+V�$V��U��U�0V�
V��U�V��U��U�V�V��U�0V�<V��U��U�=V��U�
V��U��U��U�V��U�V�V�V�V�V��U��U�gV�.V��U�V��U�V�&V��U��U��U�V�V�rV�;V��U�V�$V�V��U��U�.V�V��U�.V�&V��U��U�V��U��U�!V�
V��U��U�V�V�V��U��U��U��U�V�V��U��U�'V��U��U�4V�$V�
+V�=V�V��U�V�V�GV��U�V��U��U��U��U�V�V�V� V�V�V�!V�RV�*V�V�(V�
V��U��U��U��U�V��U�HV�V��U�+V�V�6V��U�
V�V��U�.V�/V�V�8V��U��U�V��U��U�V�V��U�
V�"V�V�6V�V��U�
V�
V��U��U��U��U��U��U�.V��U��U��U�V�"V� V�V�V��U� V�V�V��U��U�
V��U�
V�V�
V��U�V�2V��U�V��U��U�V�V�V�'V��U�0V��U��U�-V�>V��U� V��U�%V�>V��U��U�V�&V�V�
V�>V�
V�V��U��U�-V��U��U�V�IV� V��U��U��U��U�OV��U��U�V�V�V��U�V��U��U�
V�VV��U�V�1V�(V�
V��U�0V�.V�V��U��U��U�
V�V�
V�
V��U��U��U��U��U��U�
V�(V��U��U��U�V��U��U��U��U��U��U� V�PV�V�@V� V��U��U�FV�;V�V�KV�V��U��U�V�,V�
V� V�
V� V��U��U��U��U��U��U�%V�V��U�V�3V�1V��U��U�V�(V�V�"V��U�)V�NV��U�
+V�V�V�V�HV�0V�
V��U��U�2V�V�V�!V��U��U�V�/V��U�%V�&V�&V��U��U��U�V� V��U�
V�V�V�V��U��U��U��U��U��U�V�
V�
+V� V��U�V�V�V�V��U�V� V��U��U�V��U��U� V��U��U��U�
V�
V�EV�V��U�'V��U�*V�V��U�V�
V��U�V�+V��U��U��U�V�V��U��U��U��U��U��U��U�V�
V�=V��U�V��U��U��U��U��U�@V�V�V��V�V��U�V�.V��U��U�+V�V��U��U��U��U��U�-V��V�GV��U��U�V��U��U�:V�*V��U��U�
V�nV�V�+V�QV�V�V��U��U�V��U�V��U��U�V� V��U��U�V�V��U�V�V��U��U��U�)V�V��U��U� V�
+V�V�V�BV��U��U�V�GV�BV�.V��U��U��U��U��U�V�"V�
+V��U��U��U�-V�JV��U�V�V��U�
V�
V��U�V��U�HV�V��U�V��U�V�
V��U��U�V�5V�V��U��U��U��U�V�V��U�%V�,V��U��U��U��U��U��U�V��U� V�OV�V�#V��U��U��U�1V��U�7V�GV�
V��U�V�
V�V��U�
V�V�JV��U�V�V�V��U��U��U��U��U��U��U��U��U�V�(V��U� V� V� V�<V�
V��U��U��U�.V� V��U��U�
+V�V��U��U�V�
V�
V�=V��U��U��U� V�V�;V�V�
V�V�V�2V�V��U�&V�?V�V��U�V� V��U�!V�V�
+V�V��U��U�"V�V��U��U�V��U��U�
+V��U�qV�V��U��U�%V�7V�
V��U�4V�
V��U�V��U��U�.V�V��U�#V��U��U� V�V�V�5V��U��U��U��U�V�V� V�DV��U��U�
V��U��U��U�7V�V��U�'V�/V�
V��U�V�iV�
V��U�V��U��U�
+V��U�V��U�
V�(V�V�V�
V��U��U��U�
+V�V�V��U��U�V��U�
V�V��U��U��U��V�V�V��U�V�
+V�$V�)V�V��U�2V�V�V�
V�V�V��U��U�-V�V��U�V��U��U�V�AV��U��U�JV��U�TV�<V��U��U�V��U��U��U��U� V��U�%V��U��U��U�V��U��U�
+V�V��U�V�>V�V�V��U�V�V�%V��U��U�<V�V�V�
V�LV�4V�V��U��U�4V�V��U� V�V�V�V� V��U��U�
V��U�V�V�V��U�V��U��U�V�V��U��U��U��U�V�V��U��U�"V�V��U��U��U�)V�V��U��U�
V��U��U�%V��U��U�V��U�
+V�
V�V��U�4V�/V��U��U�V��U��U��U��U�
V��U��U��U��U��U�@V�V��U�V�9V��U��U��U��U��U�#V�V��U�
+V�V��U��U��U�
V��U� V��U�V�!V��U��U�
V�NV�V��U�2V�V��U�V��U��U�
V��U��U�V�
V�V� V��U�9V�V�.V��U��U�
V�V��U��U��U�V��U�.V�[V��U�MV�V��U��U�
V�&V�1V�OV�V��U��U��U�
V��U��U�"V��U��U�1V�0V�V�5V�%V�V�
V��U�V�V�
V�V�(V�8V�2V�V��U��U��U��U��U��U�dV��U��U��U��U��U��U�8V�V�V��U��U�
V��U��U�V�V�V��U� V�WV�V��U��U�V�#V��U��U�
V��U�"V�8V�V�
V��U��U��U��U��U�8V�+V��U�V�
V�V�.V�!V�UV�V��U�"V�OV�V��U��U��U�V��U��U��U��U��U��U�V��U��U�V�
V�V�V��U�V��U��U�[V�%V��U�,V�
V�V�V�V��U��U�
V�(V�
V��U��U�"V��U��U�@V��U��U�
V�V�V�QV�DV��U��U��U��U��U�
V� V��U�V� V��U��U�%V��U�V�V��U�
V�aV��U��U��U�
V��U�
V� V��U�V�V��U�$V��U��U�V�3V�V��U��U�
V�$V� V�OV�>V��U��U��U� V��U��U�BV�'V��U�
V�V�V�,V�KV��U��U��U�V�#V�V�
V�+V��U�
V��U�CV�)V�!V��U�JV�1V�.V��U��U��U�%V�#V�-V��U�(V�V��U�-V��U�V��U�V��U� V�
V��U��U��U�9V�!V�V��U�
+V�V��U� V��U��U��U�V�V��U��U�V��U�V�V��U��U��U�%V�
+V��U�8V�1V�V��U�V� V��U��U�*V�V�V�KV��U��U��U�FV��U�V�V� V��U�V��U��U� V��U��U�AV��U��U�7V��U��U�V��U��U��U�:V�;V��U��U��U�V��U�1V�3V�"V��U��U�
V��U�)V�
V�4V�$V�V�
V�V��U��U��U�
V�V��U�V� V��U��U�V�FV��U��U��U��U�(V�#V��U��U��U��U��U��U�V��U�-V�
V��U��U�V�V��U��U��U��U�$V��U�0V� V��U��U��U�(V��U��U��U�"V�EV�
V�
V��U��U�V�V� V�V��U�$V��U�V��U��U��U� V�*V�V��U��U�V��U��U�V�V�V�8V�V��U�V�
V�7V�V�V��U�V�V�
V��U��U�V��U�1V�6V��U��U��U�V�V�'V��U��U��U�)V�?V� [...]
+V�V��U��U�
+V�*V�+V�?V��U�V�V�V��U�V��U�V�0V��U�
V��U�V�V�:V�!V� V��U�4V�V��U��U�$V��U��U��U� V��U��U�V�
+V�V�
+V��U�AV�
V�V��U��U��U��U�,V��U��U�<V�sV��U�V��U� V��U��U��U�V��U��U��U�6V��U�2V�V��U��U�V�3V��U��U�V��U�
+V� V�
V��U�V�V�?V�
V�V��U��U��U��U�V�V��U��U��U�
V��U��U�%V�V�V��U��U�AV�V�(V� V��U�V�V�V�%V��U�
V�.V�CV�)V�^V�BV��U��U�V�
+V��U��U�MV�
V��U�V��U��U�
V��U��U��U��U��U�ZV�V��U��U�
V��U�,V�*V��U�V�BV��U�*V�JV��U�*V�V� V�<V�1V�V�V��U��U�'V��U��U�@V�
V��U�"V�"V�DV��U��U��U��U�,V�4V��U�%V�%V��U�V�V��U��U��U��U��U� V� V�V��U��U� V��U� V��U�V��U��U�
V��U��U��U�
V��U�V��U��U� V�MV��U�
V��U��U�
V��U�V�6V�V� V�V��U�-V�+V��U��U��U��U�(V��U�V�hV�CV�<V�V��U�V�V�V�V��U��U��U�V��U��U��U��U��U�
+V�V��U�/V�-V�
V�V��U��U�3V��U��U��U��U�V�`V�1V�V� V��U��U�)V�
V��U��U�V�
V�;V�V��U�
+V�V�
+V��U��U��U�V�<V�V��U�'V�V��U��U�:V�(V��U��U��U�V�.V�V�*V��U�V�&V�
V��U�V�*V�V�V��U��U��U��U��U�V��U��U��U�
V�V��U�V��U��U�
V�V�2V�V�V��U��U��U� V�V�V�V�2V�V��U��U��U�gV�
+V��U�,V�V�V�V��U�V�!V��U��U�V�"V�V�V�V�1V�zV��U��U�V�
+V��U�V�V��U��U��U��U�V�2V��U��U��U�V�V�
+V�
V�V��U��U��U�
+V��U�V�V��U�V�V�
+V�
V��U��U�'V� V�
V��V��U��U�)V�V��U��U��U�V��U�
+V�2V�V��U��U��U�
V��U��U�V�)V��U��U��U�
V�CV��U��U��U��V�?V��U��U��U��U��U��U��U�V�V�%V�V�V�V�RV�
V�V�-V��U��U��U��U�V��U�V� V��U�V�'V�
V��U��U�3V�NV�V��U��U�
V�V��U��U�KV�"V��U�+V��U�V�/V��U�V��U�)V��U��U�%V��U��U��U�$V��U�V�V��U�V��U��U�V��U��U��U�AV�
+V��U��U��U��U�DV��U��U�
V�0V��U��U�V�V�V��U�
V�$V�V��U��U�&V�V�
+V�V��U��U��U�EV�7V��U�V�V��U�V�V�V�4V�V��U�,V�%V��U�/V�V��U��U��U� V�QV� � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � [...]
\ No newline at end of file
diff --git a/mne/fiff/edf/tests/data/test.edf b/mne/fiff/edf/tests/data/test.edf
new file mode 100644
index 0000000..198feec
--- /dev/null
+++ b/mne/fiff/edf/tests/data/test.edf
@@ -0,0 +1,9591 @@
+0 X X 13-May-1951 Anonymous Startdate 27-Oct-2013 27.10.1319.41.4935840 6 1 139 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 [...]
��
�� ������
+ ���� ������������������ ��������
+
�� ���� �������������� ��������
+ ����
����������������������������������������������������������
+ ������������ �� ������
+ �� ������
�� �� ���� ������ �� �� ������
+
+
��
+
���� ���������������� �������� ��
+
�� �������� ���� ���������� �� �� ��
+ ����
+
������ ���� ��������������������������������������������������������������������������������������������������w�n�Z�P�B�J�Q�a�I�G�C�8�7�4�2�5�4�C�N�`�T�T�P�K�>�N�Z�g�f�������p�|�t�������������������������������������������������������������������������������������������������������������������������������������
�������������������������������� ����������������������
+ ����������
+
+ ��
+ ���� ���� ��
�� ��������
+ ���� ���������������������������� �� �������������������� ������������
+
+
���������������������������������������������������������� �������������� ������������ �������������� ������ ��
���� ������������������������
+
+
��������������
��������
$
��
��������
+
$ %
"
# # ' * ( %
����������������������������
���� ������ ����������������������������������������������z�e�\�N�S�X�e�O�N�K�@�?�>�;�=�=�I�V�f�_�_�Y�V�I�X�e�q�q������������������������������������������������������������������������������������������������������� ������������������������������������ �������������������������� �� ������������
���� ��
+ ����
+ ������
����
���� ��������
��
����
����������������������������
�� ���������� ������ ���� "
�������������� ������������������������������������������ �������������� ���� ������
+ ��
+ ��������
���� �� ����
+ �������� ������
��
��
��
�� ���� ������ �������� ��
+
+
��
������
�������� �� �� ��
+ ����
�� ����
���������� �������������������� ��������������������������������������������������������������y�q�X�P�=�E�Q�f�D�:�7�.�0�2�*�.�,�9�I�[�P�V�G�<�2�E�R�[�\�z�~���f�t�k�}����������������������������������������������������������������������������������������������������������������������������������� ���������������������������� ��
+ �������� �� �� ����
+
����
+ ����
+ ���� ��
+ ��������
��
���� ����������������������������
�� �� ���� �� ���������� ������ �� ���������������������������������������������������������� �������������� �� ������ �� ��������
+ �� �� ������ �� ����
+
+
+ �� ����������
������
#
�� �������� �� !
+ % !
+
+ ���������� ������ ���������� ���������������������������������������������������������������u�_�T�C�J�T�d�J�E�C�9�7�9�2�1�4�A�M�^�X�Z�M�E�;�J�X�f�f�������w���{������������������������������������������������������������������������������������������������������������������������������������� ������������������������������ ������������������ ��������
������ ���� �� ������ ���������� ����
��
��������
���������������������������� �� �������������������� ����������
"
�������������������������������������������������������� �������������� �� ����
������������
�� ��
������������������������
+
���������� ���������� ��
+
+
#
+
�������� �� ����������
" & ' $ # ������ �������������������� ����������������������������������������������������������������x�c�Y�H�K�Q�\�H�F�C�7�6�6�2�/�4�@�I�Z�S�P�H�E�9�I�V�d�e������{���~�������������������������������������������������������������������������������������������������������������������������������������
������������������������������ �������� ��
��������
����
������ �������� ���� �� �������� ��
���� ����������������������������
+
+ ��
���������� �������� ���� $ ����������������������������������������������������������
������������
������ �� �� ����
���� �� ����
+
+
+
+
������ ��
+
" ��
�������� ��
�� "
+
������ ������ ������������ ��������������������������������������������������������������t�l�W�M�9�B�P�a�C�5�8�-�)�.�(�'�+�7�C�T�P�O�B�>�,�=�K�Z�\�x�w�{�l�x�q������������������������������������������������������������������������������������������������������������������������������������� �������������� �������� ��
���� ��
+
+ �������� ������ �� �� ������ ���������� ����
��
+ ��������
�� ��������������������������
+ �� �� �� ��������
�� �� " �������������������������������������������������������� �������������� �� ����
�� ��������
+
������ ��������������
������
+
" (
+
+ ������
% $ ' ! "
���� �� �����������������������������������������������������������������������������u�`�W�G�K�R�`�J�C�B�6�2�4�1�0�0�?�H�X�R�P�G�E�7�E�T�b�b���|��w���{������������������������������������������������������������������������������������������������������������������������������������� �������������������������� �� ��������������
������
������������������������ ������������������ �� �������� �������� ���������������������������� �� �� �� ��
+ ������
���� ��
���� �� �������� �������������������������������� �������������� �� ����
������������ ��
������������������������
�� ��������
! # (
$
���� �� ����������
+
! " % "
�� �� �����������������������������������������������������������������������������u�a�U�E�J�N�V�E�F�B�7�6�6�1�.�3�?�I�X�N�K�G�E�7�D�S�c�b�}�{�}�x���|�������������������������������������������������������������������������������������������������������������������������������������
������������������������������ ��������������
����
+ ������ �� ������ ���������� ����
�� �������� �������� ��������������������������
+ ��
�������������� ������
+ ������
+ ���������������������������������������������������������� �������������� �� ������ �������������� ��
+ ������ ���� �� ����
+
��
+ ��
����
+ ��������
��
+ ��
�������� ��
+ ��������
+
+
���� ����������������������������������������������������������������������������������������������x�`�T�B�9�,�.�6�@�0�,�-�!�
�
����&�.�<�4�4�.�.�
�+�9�G�H�b�]�a�U�d�]�j�r�y������������������������������������������������������������������������������������������������������������������������������� �������������������������� �� ���������������� ��������
������������ �� ������ ���������� ����
��
+ ��������
+ �������� �������������������������� ��
��������������
+
������ ��
���������� ��������������������������������������������
������������ �� ������ �� ������������ �� ��
������ ����������������
����
+
������
������������ ������������
��
+
��
�� ������
�� ����������
+
+ ��
������������������������������������������������������������������������������������������������o�c�S�I�;�?�E�P�?�?�<�/�-�/�,�)�.�9�B�O�F�B�>�;�-�;�I�X�Z�s�p�s�h�w�o�{�����������������������������������������������������������������������������������������������������������������������������������
+ �������������������������������������������������� ����������
+
���������������� ������ ������
�������� ��������
�������������������������������� ��
��
������ ������
���������� ������������������������������������������ �� �������������� ���������� �������������������� ���������� ��
+ �� �������� �������� ����
��
+
����
+
+
���������� ����������
+
! ��
������ �� ����������
+
+
+ ����
�������� ������������������������������������������������������������������������������������r�e�T�L�=�@�F�N�B�E�<�4�2�3�1�.�3�A�K�W�M�J�F�E�7�D�S�`�_�x�u�u�q�}�t�������������������������������������������������������������������������������������������������������������������������������������
+ ��������������������������������������������������
+
�������� ������ ���� ���� �������� ���� % ��
��������
�� �������� ��������������������������
+ ����������
+ ������ ������ ���������������������������������������� ������������ ������������ ���� ������ ������������
��
������ �� ����
+
��
+ ������
���������� ��������
+
+
+ ��
���� ��
���������� �� ������
+ ��
�� ���� ����������������������������������������������������������������������������������������������x�j�`�P�E�8�=�@�H�;�<�9�.�+�-�)�$�*�7�@�N�D�A�>�?�0�=�J�Y�Y�q�p�p�c�u�l�y������������������������������������������������������������������������������������������������������������������������������������ �������������������������� �� �������� ������ ��������������
������������ �� ������ ������ ��
!
�������� ���� [...]
+
+
+
��������
+ �������� �������� ������������������������������������������ ���������� ����������
�� ����
������������ ��
+
+
+ ������ �� ����
����
+ ������
���� ��������
+
��
+ ��
������
�� ����������
+
����
+ ��������������������������������������������������������������������������������������������w�g�`�O�E�8�>�@�I�=�B�?�4�3�5�2�.�4�E�N�X�N�L�I�I�=�K�U�b�_�w�w�x�l�z�p�{����������������������������������������������������������������������������������������������������������������������������������� �������������������������� ������ ������ ��������������
�������������������������� �������� ��
+
�������� ������
��������������������������������
+
������
+ ������ �� ��
���������� �� �������� �������������� ��������
���������� ���������� �� ���������������� �� ��
�� ������
+
+ ��
����
+
+
������
��
$
�� ������ ���� �������� �� ���������������������������������������������������m�b�Q�L�?�C�I�Q�F�M�G�<�=�?�<�:�A�R�Y�g�\�Y�Y�W�O�_�i�v�p�������z���x������������������������������������������������������������������������������������������� �� ����������������������������������
��������������������������
+ ���� ������
���� ���� ����
�� ��
+ &
+ ��������
�� ������������������������
+
+
��
�������� �� �������� �������� ������������������������������������������������������������ �������������������������������� �������������������� ������������ �� �������� �������� �������� ���� ������ �������� ���������������� ����
+ ��
+
�� ������������ ���������� �� ������ ��
+
+ ���� ������
���������� ����������������
+ �� ��������
+ �� �������������������� ������������������������������������������������������������������������������������{�y�y�����d�W�Q�F�=�.�5�8�A�7�;�4�-�'�(�%� �'�9�=�K�?�@�>�=�0�?�M�Z�U�m�q�p�W�k�`�m�t�y�~������������������������������������������������������������������������������������������������������������������������������� ������������������������������ ��������������������
��������������
+ ������ ���������������� ����
�������� ���� ������������������������
+
+
�������� ������������������ �������������������������� �������������� ���������� ���������� ���������� ������������
�� ��
������
+ �� ����
����
+ ����
��
����
+
������
+
+
+
��
+ ��������
+
�� ��
��
��������
�������� ���������������� ������������������������������������������������������������y�e�^�M�J�=�<�E�R�F�K�D�<�7�8�6�/�6�D�O�^�I�F�L�P�G�V�b�m�_�z�~�|�n�u�j�x�}���{�����������������������������������������������������������������������������������������������������������������������������
+
�������������������������� ���� ������ �������� ��
������ ���� �� ������
���� ����
+ �� �� �������� ���� ��������
���������������� ������
�� ����������������
+ �� ������
��
���� ����������������������������������������������
+ ������������
+ ��
+ ��������������
+ �� ��
+ ������ �� ������������
+ �� �� ������
+ ��������
���� �������� ���� ���������� ������������
+
+
+ �������������������������������� ����������������������������������������������������������������u�`�X�I�L�Q�X�D�I�G�>�=�>�6�6�9�I�R�c�\�\�Y�Z�M�^�g�m�l������}�~�t��������������������������������������������������������������������������������������������������������������������������������������� ����������������������������������������������������������
+ ��������
���� �� �� ������ �� ������
���� ��
�������� ���������������������������� �� �������������������� ������������
+
+
�������������������������������������������������������� �������������� ����������
���������������� �������� �� ������ ����������������
+
�� ���������� ��������
+
$
+
+ ���������� �� ��������
+
# #
! ���������������������������� �������� ��������������������������������������������������������n�c�T�T�Y�c�R�T�N�A�B�@�<�;�<�I�U�e�]�[�W�U�J�X�e�s�r����������������������������������������������������������������������������������������������������������� �������������������������������������� ���������������������������������������������������� ��������
+
������������ ���������� �������� ������
����
�������� ���� �������������������������������� �������� ���� ��������
��
�������� �� �������� �������������������������������� �������������� ������������
+
�������������������� ������������ ������ ����������������
+
+
��������
+
+ ������
�� ��������
" "
!
�������� ����������������������������������������������������������������z�f�Z�N�P�R�[�K�N�H�<�;�<�7�7�;�H�U�f�]�Z�Z�Y�O�]�h�v�s������������������������������������������������������������������������������������������������������� �� �������� �� ������������������ �������������������������������������������������� ������
+ ������ ���� �� ������ ���������������� ��
��������
+ �� ���������������������������� ���� �������������������� ����������
+
���� �� ���������������������������������������������� �������������� �� ����
�������������� ������ ��
+ ���� ������������������������
+
�� ������������ ����������
+
$
+
���������� �� ����������
+
# % #
"
������������������������������������������������������������������������������������������������z�e�\�K�N�Q�]�H�J�F�9�9�9�4�5�7�B�M�]�T�S�P�M�A�O�]�i�l����������������������������������������������������������������������������������������������������������� ������������������������������������
+ ������������������������������ ������������
��������
+
+ ����������������������������������������������
+ �������� ��������
���� ���������������������� ������
+ �� ���������������� ��������
+
" ���� �� ���� �������������������������������� �������������� ������������
+ ��������������������
�� �� �� �� ������������������������ ����
+
+ ��
+ �������� ����������
" ! &
�������� �� ����������
+
+
! $ ' ( $ )
!
�������� �������� ��������������������������������������������������������r�f�V�Z�Y�a�S�W�O�B�A�B�=�<�?�N�V�h�`�`�\�\�O�_�i�z�y�����������������������������������������������������������������������������������������������������
�������� �������������� ������������������������������ ������
��
������������������������ ��������������������
���� ��������
+ ������ ������������������������ ������
�������� ����
+ ����������
+ �� ��
���� �� �� ���� ���������������������������� �� ���������������� ������������ ����������������������
������������ �������������������������� ���� ����
+ ��
��
+
+ ���������� ����������
�� �������� ��
+
+
�������� �� ����������
����
+ �� ���������� ������������������������������������������������������������������|�i�^�P�S�T�[�K�O�I�<�:�:�6�5�9�F�S�b�Z�W�U�U�J�X�b�m�m���������������������������������������������������������������������������������������������������������� �������� ������������������ ��������������������������������������������������
+
����
������������������������ ������������������ ��
��������
+ �� ���������������������� ���� �������������������� ����������
���� �� �������� �������������������������������� �������������� ����������
���������������� ������ ��
+ ���� �������������������������� ����
+
���������� ������������
��
+
! &
������
�� ����������
+
! ' % %
��
+ �� ������������������������������������������������������������������������������|�g�\�O�N�S�\�J�K�F�8�7�7�4�2�4�A�J�[�S�R�K�I�<�J�X�f�f����������~����������������������������������������������������������������������������������������������� �������� ����������������
�������������������������������� �������� ��
����
+ ������������������������ ��������������������
�� �������� ������������ �������������������� ������
+
+ ��
+ ���� ��
+ ������
���� �� ������������ �������������������������������� ���������������� ������������ ���������������������� ����������������������������������������������������
��
��
����
+ ��������
�� ������������
+
������
�� ���������� ����
�� �� �������� ����������������������������������������������������������������y�f�]�L�N�R�W�L�P�K�=�;�<�7�4�:�J�V�f�\�Z�W�X�O�[�h�r�o����������{��������������������������������������������������������������������������������������������������������������������������������������� ����������������������������������������������������
��������
������������������������ ������������������ �� �������� ������ �������������������������������� �� ������������������
����������
����
+ �� �������������������������������� �������������� ����������
����������������������
������������ �� ����������������������������������
�������� ������������ �� ��������
! '
"
�� ����������
��
# # #
������������������������������������������������������������������������������z�e�[�L�N�O�X�G�J�E�6�6�6�3�2�6�A�M�]�R�N�J�I�?�L�Y�g�c��|�~�~���}������������������������������������������������������������������������������������������� �� �������� ��������������
��������������������������������������������������
��
+
������������������������ ������������������
�������� �� ������
+ �������������������������������� ������ ��
+ ����
+ ������ ���� �� ���� �������� ������ ���������� �������������� ������������ ���������������������� �������������� ���� �������������������������� ��
��
��
�� �������� ��
+ ��������
!
�� ����������
����
+
�������� ����������������������������������������������������������������|�o�_�R�E�I�N�N�A�H�<�4�4�4�0�0�8�I�T�_�S�T�P�P�G�W�b�l�j���|�{�{��z����������������������������������������������������������������������������������������������� ���������� ��������������������
���������������������������������������������������� �� ����
������������������������ ���������� ����
�������� ������ �������������������������������� ���� �� ������ ��
��
�� ��
���� �� �� ���� �������������������������������� �������������� ����������
+ �������������������� �������� ��
+ ���� �������������������������� ��
���������� ������������ �� ������ &
+
+
�� �� ����������
+
# !
�� �� ����������������������������������������������������������������������������|�o�\�S�C�E�J�O�B�C�>�2�2�1�0�,�2�A�G�V�L�J�F�D�7�F�R�_�`�y�w�y�w���y����������������������������������������������������������������������������������������������� �������� �� ����������������
�������������������������������������������������� ��
������������������������ ���������� ����
+
�������� ��������
�������������������������������� �� ��
����
���� �� �������� ���������������������������� �������������� ������������ ���������������������� �������������� �� ��������������������������������
+
+
���� �������� ��
"
+ �� ����������
������ �� ����������������������������������������������������������������������������{�o�[�P�A�D�F�K�=�A�;�/�0�0�-�,�4�C�O�\�U�P�P�P�F�T�_�m�l���}�}�{���z������������������������������������������������������������������������������������������� ��
+ �������� ��������������
��������������������������������������������������
������
������������������������ �������� ����
�������� ������ �������������������������������� ��
+
��
+ ������ �� �������� ������������ �������������� ����������
�������������� ������������ ���������������������� �������������� ���� ��������������������������
��������
+ ��
��
��������
+
+
������ ���� ���������� ��������������������������������������������������������������{�o�[�R�D�F�H�N�?�D�?�3�1�2�2�0�8�J�T�c�[�Z�U�X�O�_�k�w�s������������������������������������������������������������������������������������������������������ �� �������� ����������������
�������������������������������� ���������������� ��������
+
+ �������������������������� ��������
+
+ ������ �������� �������������������������������� �� ��
��
+ ������ ������
���������� ������������������������������������������
�������������� ����������
�� ������������ �������� ��
������ �� ����
��
����
+ ��������
+
#
+ ��
������
�� ����������
+
+
������ ������������������������������������������������������������������������������������r�g�R�J�<�B�D�J�>�A�>�2�0�2�0�/�6�E�N�Z�P�O�M�K�B�P�Z�j�f��~�~�{���{����������������������������������������������������������������������������������������������� ���������������������������������� ��������������������������������������������������
������
+
+
�������������������������� ������
+
+
�������� ��������
+ �������������������������������� ��
��
+ ������ ������
���������������������������������������� ����������
�������������� ������������
����������������������
�������������� ���� ������ �� ����
+ ��
��
������
��������
+
+
$
��
��
+ ������
+
+
+
+
+ ������ ������������������ �������� ����������������������������������������������������c�Y�G�>�0�3�6�=�0�6�4�'�&�'�'�(�/�A�K�W�Q�O�M�L�E�S�^�n�l������������������������������������������������������������������������������������������������������� �� �������� �� ������������������
+ ������������������������������ ������ ������
��������
������������ �� ������ ������
+
������ ������
��������������������������������
+
������ �������� �������� ���������������������������������������� ��������
���������� ��������
+
�� �� ������������ ������
+ ������ ��
+ ����
+
����
+
�� ������
+
+
+ ��
+ ������ �� ������
+
���� ������������������������������ �������������������������������������������������������������o�d�T�P�>�@�E�J�>�F�A�6�6�6�5�4�=�P�Z�e�\�]�Z�V�Q�]�j�w�t�������z���y�������������������������������������������������������������������������������������������������������������������������������������
+ �������������������������� ���� ������
+ ��������
+
������������ ������������ �������� ���� ������ �� ���������������������� �������������� ����������������
������������������������������������������ ����������
���������� ����
������
+
+ ��
+ �� ������ ���������������� ������ ����
������ ������ ���� ���������� ����������������������
+ ������
+
+
������
+
+
����
�� ��
+ ��������
+ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �� ���������� ������������ ����
+ ������������������
�������� ��
���� ���������� �� ��
������ ������������ ������������ ������������������ �� ����
������ ������ ��������
�������� ������
���� �������� ���������������������������� ������������ �������������� ������ ���������� ������������
+ �������������� ������������������������ �������� ���� ���������� ������ �������������������� ������������ ����������
�� �������������� ������
�� ����
+
��������
���� ��
������
+
����
�� ������
+ �������� ����������������������������������������������������������������������������������|�{���w�q�z����������������������������������������������������������������������������������������������������������������������������������������������������� ����������������
�������������������������� ���� ���������������������� ����������
+
���� ������������ ������������
�������� ���� �� ��������
+ �������� ���� ���������������� ����������������
�������������������������� �������������������������������� ������������ ����
+
����
�� ������ ������������������������ ���� ����������
+ ���� ���� �� ������ ������������ ����������
+ ����
+
������
+ ������
+
+ ������
+ ��
������
����
�� ��
�������� ��������������������������������������������������������������������y�~�����������n�j�c�b�b�o�x�~���{�y�|�~�v�x����������������������������������������������������������������������������������������������������������������������������������� ������������������ �������������������������������������������������������� ����������
+
+
���������� ���� ������ ������ ���� ������
�������� ������ ������������������������������������ ���������������������������������������������������������� �������������� ������������
�� ������������ ��
+ ���� ������ ������������������������ �� �������� ���������� ������ ������������������������������������������������
+ �� ������������
+
������
��������
��
������
+
�� �������� ���������� ���� ���������� ������������������������������������������������������������������x�l�e�Y�[�_�g�^�g�^�K�D�I�B�@�H�S�Z�d�W�W�Y�X�M�S�^�k�k���}�r�x�}�z��������������������������������������������������������������������������������������������������������������������������������������� ������������������������������ �� �������������������� ���������������� �� ���� ���������� ����
+ ������ ����������
������������ ������������
�������������������� ����
������ �� ������������ �� ���� ��
�������� �� �������� �������������������������������� �������������� ������������
�������������������� ����������
+ ���� ������ ���������������� ������
������ ���������� ������ �� ������������ ������������ ����������
�� ����������
���� �� ����
�������� �� ����
+ ��
+
+ �� ��
��������
��������������������������������������������������������������������u�{�}���y�����w�n�l�c�d�f�u�����~�{�w�{�u�~����������������������������������������������������������������������������������������������������������������������������������� ��������������������
+
+ ������������������������������ ����������������������
����������
+
+
���� ����
����
+ �� ���� ������������ ������������
�� ���� �� ������
+ ������
+ �� ������ �������������� �������������� ���������� �������������������� ������������������������������������ �������������� ���������������� ������ �� �� ������
�� �� ������ ��
+ ���� ��
+ �� �� �� ������ ���� �� ���������� ����������
��
+ ��
+
������ ������
+
+ ������
����
��
�������� ������������������������������������������������������������������{�q�u�{���s�t�p�[�^�k�^�U�K�a�s���u�n�q�v�j�q������������������������������������������������������������������������������������������������������������� �������������� �� �� ���������� �������������� ����������
+
������������������������ �������� ��
+
+ �������� ������
+ ���������� ������������ ������������ �������������������� ������
+ �� �� ������ ������������ ���������� �� �������� �������� �������������������������������� �������������� ������������
�� ������������ �� �� �� �� �������� �� �� �������� ���� ����
�� ������ ���� �� ���� ���� ���������� �������� �� ����
������
+ �������� ����
+
+ ��
+
+
+ ��
�������� ������������������������������������������������������������������r�a�a�d�|�]�`�`�T�U�W�K�I�M�X�e��n�b�[�a�Y�f���������������������������������������������������������������������������������������������������������������������������������� ��������������������
+ �������������������������������������������������������� ��������
+ �� ������
+ ��
+
���������� !
+ ��
������ �������� �� ����������������
������
+ ������������ ���� ����
+ ��������
�� �� # ���� ������������ �� ������ ���������������� �������� ����
������ �� ��
�� ����
+
+ ���� ���� �������� ���� ���� ����������
����
����
�� ������
��
����
���� ��$ !
+
+ ����
�� ����
����
�� ��
"
�� �� �� ����
+ ������
���� ����������������������������������������������������o��}�h�O�o�q�|�p�v�r�[�X�b�J�&�7�Y�l�y�d�c�Z�q�d�f�o�k�r������������������������������������������������������������������������������������������������������������� ��������
��������������������
������������
������������ ���� �������������� ���������� ����
+
���� ������������������
�� �� ���� ����������
���������� ������������ �������������������� ����
�� �� ����
�������������� ������ �������� ���������� �������������������������������� ���������������� ������������
+ �������������������� ���������� �� ������ �� ������������ ���� ����
������ ���� �� ������ ���� ���������� ����������
�� ���� ��
��
+ ������
���������� �� ������
+
+
+
�� �� �������� ����������������������������������������������������������������z�n�d�e�g�q�c�l�f�Z�W�X�P�O�S�^�h�y�p�l�d�m�d�o�w������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������� �������� ��
���� ������
+ ���� �� �� ������ ������ ������ ������������
����
��
���������� ������������ ���� �� ���������� �� ������������������������������������ �� �������������������������������� ����������������������
���������� ������ ������ ������������������������ ���� ��
�� ������ ����
+
+ ���� ���� ������ ���������� ����������
�� ���� ��
! ����
�� ���� ����
+ ������������ �� ������
+ ������
���� ���� ������ �� �������� ������������������������������������������������������������������m�e�]�b�a�n�b�e�\�R�O�V�I�L�Q�M�X�u�p�\�Z�g�Z�b�o�z�x�����������{�������������������������������������������������������������������������������������������������������������������������������������
��������������������������������
��������������������������������
+
��
+ ���� �� ������ �� �� ���� ���������� �������� ������ ������ ����������
������
�� �������� �������������� ������ ���������� ������������������������������������������ ������������������������������ ���������������������� ���������� ���� ������ �� ������������ ����
��
+
������
+ �� ������ ���� ���������� ��������
��
����
+
+ ����
+ ���������� �� ��
+
�� �� ��������
����������������������������������������������������������������r�h�\�]�a�j�^�e�[�Q�O�Q�H�J�J�Q�]�s�l�b�]�d�Y�d�o�}�y��������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������� �������� ����
+ ����������
+
+
������
+
������
��������
+ ������ ���� ����������
+
+
����������������
��������������
+ ������ ���� "
������
��������
���� �������������� �� ����������
+
������
+
���� ��������
����
������ ������
+ ������
+
������
������ ������������
+ ��)
������
+ ��������
& !
��
+
, #
����
��
% ����
$ " $ " " #
����
�� ��
��������������
�� ������������ ��������������������������������������h�d�m�r�e�k�k�k�Y�e�d�O�O�d�F��#�;�^�q�L�U�f�i�\�_�g�n�m���v�h�d�k�y������������������������������������������������������������������������������������������������������������� ������������������������ �������������� �������� ������������������������ �� ��������������
������������ ����
�� �� ����
��������
+ �� ������ �������������� ������
+ ���������������� �������������� �������� �� �������� ������������������������������������������ �� ������������������������������ �������������������� �������� �� ������ ������ ���������������� ����
��
+
+
+ ������
+ �� ������ ������������������ ����������
��
+ ����
���� ����
���������� �� ������
+ ��
���������������������������� ����������������������������������������������������������������|�k�c�T�X�\�g�W�\�V�J�I�I�B�@�>�K�Z�m�b�[�[�_�U�_�k�w�s�������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������� �������� ���� ���� �� ������ ��
�� ��������
�� �� ������������������ �� ������ ���������������� ������������ ������ ���������������������������������������������������������� ������������������������������ �������������������� ������������ �� ������ ����������������
+
��
+ ��
���������� ��������
+
����
���������� ��
+
������������������������������ ����������������������������������������������������������������{�h�^�P�T�W�`�O�U�L�A�A�A�<�;�=�K�W�e�\�Z�X�Z�N�[�h�u�t�����������~��������������������������������������������������������������������������������������������������������������������������������������� ������������������������������ ���������������� ������������
������ �� ����
��
�� ��������
+
�� ����������������������������
+ ��������������
+ ��������������
+ ������ ��
+ ���������������������������������������������������� ��
+ �������������� ������������
������ �������� ������ ��
���� ������������������������
+ ����
����
+ ���� �� ���������� ��������
�� ��������
���������� �� ���� ��
+
��
+ �������������������������������� ����������������������������������������������������������������t�d�\�M�O�U�`�O�R�N�@�>�9�:�:�7�G�T�f�X�W�U�W�I�X�a�n�m�����������u��������������������������������������������������������������������������������������������������������������������������������������� ���������������������������������������������������������� ��������������
+
����
��
���� �� ������ ����
+
��������
+ �� ���� ������ ������ �� ������
��
�������������� ���������� ���� ����������������������������������������������������������
+ �������������� ���� ������
���������� ��
������ �� ����������
+
+ ������ ��
��
+ ����
�� ������������ ��������
������
+
���� ���� ��
���������� �� ���� ��
����
�� ������������
+ ������������������������������������������������������������������������������������������������r�c�[�T�F�I�N�Z�C�H�A�2�.�"�-�1�5�A�H�T�M�L�M�B�4�E�O�W�[�u�l�q�s�r�j�{���z���������������������������������������������������������������������������������������������������������������������������������
+ �������������������������� �� �������������������� ������������
������������ ���������� �������� ��
+
+
+
������ ��������������������������������
+
���������� �� ���������� ������
�������������������������������������� ��
���������� ��������
+ �� �� ������������ �������� ������ �� ��
+
��
+ ��
+
+
��
! " + !
+
+ ��
+
+ #
#
+
����
+ ���� ������
������ ������������������������������������������~�s�a�[�L�Q�R�W�M�R�L�>�>�>�>�?�H�Y�b�o�e�f�c�`�Z�f�t�~�{�������������������������������������������������������������������������������������������������������������������������������������������������
+ ������������������������������ �������������������� ������������
���������� �� ������ ��������
+
+ �������� �� ��������������������������������
+
+
���������� �� ������������������
��������������������������������������������
���������� ����
�� �� ������������
���� ���� ������ �� ����
������ �������� ����
+
+
+
����
+ ��
������
+ ��
+
+
��������
������ ���� ����������
+
+ ��������������������������������������������������������������r�j�Z�U�C�K�O�P�H�O�H�>�<�<�9�:�=�N�W�h�`�]�W�P�K�X�g�p�l���~��v�~�s�z�����������������������������������������������������������������������������������������������������������������������������������
�������������������������� ���� ��������
+
+ ����������������
���������������� ������������������ �� ��
+ �� �������� ���� �������� �� ������������ ����������
�� ������
+ ������
��
���� �� �������� �������� ���� ��
+ ��������
+
+ ������
+
+
+
+
+
+
+
+
+
����
+
+
" &
+ " $ &
! (
+
* - (
% ( . 3 . & 0
" $
������ ���������������������������������������������~�u�p�]�`�c�l�a�f�^�Y�O�Q�O�G�L�[�b�n�\�c�i�c�X�f�p��w����������������������������������������������������������������������������� ���������������������� �� ������������������ ����������
!
����������
+
)
������
������ ��
���������� ��
������ �� ������������������������ ������
��
�������������� �������� ������ ����������������������������������������
+ ���������� �� �� ������������ �� �� ��
+ �� ���������� �� ���� ������ ������ ����
+
+ ����
+
+ ����
��
+
+
�� "
�� " ������
+
����
�������� ���������������� ���������������������������������������������������������������q�Y�Y�L�R�P�V�M�S�I�3�<�<�9�>�G�S�_�j�g�`�U�R�W�`�k�x�t������y�~�w�~�����������������������������������������������������������������������������������������������������������������������������������
�������������������������� ������ ��������
����������
������ ���� �������� ����
+
������ �� ���� �� �������������������� ������
�� ������ ��
���������������� ������������������ ���������������� �������� �������� ��
������������ �������� �������������������� �������� �� �� �� ������ �� ������
+ ��
+ ��
�������� �� ����
��
+ ����
"
# ��
+
+
����
���� ������
+
�� ��������������������������������������������������������|�g�Z�R�Y�[�\�R�W�Q�A�4�?�=�?�J�X�d�m�e�_�_�c�V�h�p�{�}�����������|������������������������������������������������������������������������������������������������������������� ���������������������� �������������������������� ���� ������
+ ����������
+
+ ���� ������ ���� ������������ ��
��������
+ ������
������������ ���� ������
+
+
����
���������������� ��
�������� �������������� ������������ �������� ��������
������ ����
�� �� �� ������������ ��
���� �� ���� ��
+ ��
+ �� $
������ ����
+
!
���� ��
+ ��
' ! "
+
, ) &
+ ) ����
+
$
. ��
+
$ �� ��
����
���� ����
���� ������������ ��������������������������������������������z�v�S�L�Z�P�V�P�X�L�O�G�?�0�6�E�]�h�q�h�H�=�e�N�]�i�s�v�������|���y����������������������������������������������������������������������������������������������������������������������� ���� ������ ������������ �������� ��
+ ! ����
��������
������������ ������ ���� �� ��
�������� ��������
���������������������� ������
�� �� �� ���������������� ���������� ����
���������� �� �������� ������ ��
������������ ��������
+ ���� ������������ �������� �� ������ �� �������� �� ��
������
+ �� ����
+
+
+
������
+ ��
�� # ��
��
+
���� ������
+ ���� ��������������������������������������������������������~�l�a�W�[�\�`�V�[�S�I�D�C�D�B�L�]�h�u�i�d�e�j�^�k�t�������������������������������������������������������������������������������������������������������������������������������� ������������������
�������������������������� ����������������
������ ��
+
+ ������ �� ����������
+
+
������
��
+ �������� ����
���� ������ ��
���� ����
������ ������ ����
+ �������� ����
���������������������� ������������
+
����
������������
����
+ ��
+ ��������
+ ����
����
��������
+ �������������� ���� ����
+
��
���� ������
������
�� ��
��
+ ������
+
% ������ ����
+ �� ���� ��
���� ������ �������� ������
+ ����������������������������������������������������������������o�P�W�O�T�O�U�Q�S�G�"�)�+�(�1�G�Y�d�`�S�V�J�E�T�e�j�u�o���~�z�x�x�a�b���������}������������������������������������������������������������������������������������������������������������������������� �������������������������� ����������������
���������� ������������ ���� ����
�� �� # �������� ��������
�������� ���� ������ ������
+
+ ������ ��
������������ �� ������������������ �������� ������������ ����������
+
��
+ ������ �� �� ������������ ��
+ ������ ������ �� �� ������ �� ������
+
��
+ ��
������
% ��
+
����
!
��
+
�� +
+
+ ����
+ ������ ���� ������ ����������������������������������������������������������m�f�[�a�c�f�]�b�X�\�X�6�F�I�S�c�l��p�_�f�k�_�n�v���{������������������������������������������������������������������������������������������������������� �������������������� ������������������ �������������������������� �������� ���� ���������� ������ ����
����
�� ������ �� �������� ���������� ���� ������ ���� ������
������
+ ��
��������������
������ ��������
������������
���������� ����������
+
+
�������� �� ��
�� ������������ ����������������
+ ���������� ���� ���� �������� ������
���������� ������������ ��
�� �� ������ ���� ������
+
��������
����
������ ���� �� ��������
�������� ��������������
������������������������������������������������������������������z�i�a�T�^�Y�]�W�Y�O�I�J�=�1�4�>�Q�_�j�f�L�1�H�R�]�e�r�o���x�u�t�y�t������������������������������������������������������������������������������������������������������������������������������������ �������������������������� ���� ��������������
+ ��������������
������ ���� �� ������ ��
+ ������
+
+ �� ���������� ����������
������������������������ ���� ������ ��
�������������� ���������� ������
�������� ������������ ������
+
+ ������������ �� �� �������� �� ��
����
��
+ ����
�� ������
+
���� ��
��������
+
����
+
! "
��
+ ����
+ ����
+
+
�� ��������������������������������������������������������{�w�h�n�n�u�j�o�f�X�Z�Z�Y�Z�^�n�v���w�s�p�t�k�v������������������������������������������������������������������������������������������������������������������������������� ����������������
+
����������������������
������������
��������
+
+ ������ �� �������� ������
+
�������� ��������
���� �������� �� ����
����
+ ������ ������ ��
+ �������� ������ �������������������������������� ��
+
��
����������
��
+ ���� ��������
��
+
+ �� ������
+ �� ��
���� ����
+ ����
��
������
+
+ ��
+
����
+ �� �� �� *
+
������
��
+ ��������
���� ��������������������������������������������������������q�n�b�h�j�m�e�h�_�I�5�8�L�P�[�p�x�x�m�m�h�k�e�q�x�t�i����������������������������������������������������������������������������������������������������������������������������������������������� ���������������������� ����
+
+ �� �� ��������
�� ����
+ ���� �� ������
�������� ������
���������� ���� ���� �������� ���������� ������
�������� �� �������������� ���������� ����
���������� ����������
����������
�������������� ����
���������� ��
+ �� �� ������
+
����
�� ������
+
+ ����
+ ������ ����
��
��
+
���� ��
��
��
��
+
+
+ �� ������������������������������������������������������������}�o�t�{���w�z�o�a�i�k�f�d�i�x�����y�{�x�z�s�{��������������������������������������������������������������������������������������������������������������������������������� ���� ���� ����������������������
+ ��������������
�������� ���� ���� ���������� ������ ����
+ �� ���������� �������������� �� ������ ������
�������� ����
���������� ����������������
�������� ���������� ������������
+ ������������ ����
+ ���������� ��
+
+ �� �� ������ �� ������
+
+
+
+
+
+ ��
+
��
�� ��
������
+ �� �������� ������������������������������������������������������������������q�k�^�d�g�j�c�f�Z�P�O�M�H�J�W�d�p�r�k�g�a�a�^�g�p�z�y�������������������������������������������������������������������������������������������������������������������������������������������������
�������������������������� ������������������ ������������ ���� �� ������
+ ��
+ �� ����
+
���������� �� �� �� �������� ���� ������
�������� ����
���������� ������������������ �������������������������� ������������
��
����������
+ �� �� ������������
+
��
�� �������� �� ���� ������
+
+
+ �� ����
+
+
+
+
��
+
+ ��
������ ����������������������������������������������������������������u�h�b�S�X�\�\�V�V�N�D�C�B�=�:�B�O�X�^�W�Z�V�Q�L�U�\�k�l���x�u�r�}�|���������������������������������������������������������������������������������������������������������������������������������
����������������������
������
+ �� ������ ������ �� ������
+ ��
+
���������� ���� ���� ������ ���� �� ������
+
�������� ����
+ ���������� ������������������ ����������������������������������������
+
+ ���������� �� �� ���������������� �� ��
+ �� �� ���� �� ���� �� ���� ������ ���� ����
+ ��
+ ����
+ ���� ��
+
��
+
�� ����
������
+
+ �������� ������������������������������������������������������������������y�w�h�n�o�r�n�l�d�Z�W�U�P�O�X�h�p�v�l�o�h�g�c�j�p�z�}�������������������������������������������������������������������������������������������������������������������������������������������������
���������������������� �� ������������������ ������������ ������������������������ �������������������� ��������
���������� ���� ������ �������� ���������� �� � [...]
+ ��
������ �� �� ������ �� ���������� ������������������������������ ����������������������������
+
��������������������
������������ ������ �� ������������ ����
����
������ �� �� ����
+ ������
�������� �� ������������ ��
+ �������� ������
+ ��������
+
+ ���� ����
��
��������
+
���� ������������������������������������������������������������}������������t�r�p�l�k�p�|�������������|������������������������������������������������������������������������������������������������������������� �� �������� ����������������
�������������������������� ����������������
+ ����������������
���� ������ ���������� ������ �������� ���� �� ������������ ������������
�������������������� ����
+ ���� ��
���� �� �� �������� ���������� �������������������������������� ������������������������������
����������������������
������������
�� ������ ���������������� ����
�� �� �� ������ ���� ������������ ���� ���������� ����������
�� ������������
������
���� ��
����������
+ �� ����
+ ����
+
+
+ �� ��
�������� ������ ����������������������������������������������������������������������������y�v�m�l�o�~����������������������������������������������������������������������������������������������������������������������������� �� �������������� ������������������
�������������������������� ���������������� �� ������������
������������������������ �������������������� ��������
�������� ���������� �������������������� �� ��
������
������ ������ �� ������������ ������ ���������������������� ���������������������������� ����������������������
������������ ����
+ �� ����������
+
+
��
������
+
�� ��
+ ��������
+ �� ����������
+ ��
���� ������
+
��������
���� ����
����
�����������������������������������������������������������r�u�x��u�|�u�f�g�e�_�^�c�p�{����~�{�{�s�}����������������������������������������������������������������������������������������������������������� �� �������� ������������������
��������������������������
����������������
������������ ������������������������ ���������� �������� ��������
���������� ������������
�������������������� ����
+
����
������ �������� ������������ �������������������������������� ����������������������������
���������������������� ������������
���� �� ������������
��
������ �� �� ���� ��
+ ���������� �������� �� ����������
��
�� ��
����������
+ �� ����
����
+
+
+
����
+ ���� ������������������������������������������������������������s�u�y���w��y�m�j�g�a�_�d�q�}���}�|�y�|�u��������������������������������������������������������������������������������������������������������������� �� ���������� ����������������
�������������������������� ����������������
��������������
������������������������ �������� �������� ������
���������� ������������
�������������������� ����
����
������ ���������� ������������ �������������������������������� ����������������������������
+
+ �������������������� ���� �� ��
+ ���� ����������
+
��
+
������
+
+ ������
+ �������� �� ������������
+
��
���� ����
��������
+
+ ����
����
+
+
+
����
�� ����������������������������������������������������������y�k�m�p�w�l�s�l�a�_�^�W�W�[�h�t���w�v�t�v�n�z������������������������������������������������������������������������������������������������������������� �� �������� ����������������
�������������������������� ���������������� �������� ��
���� ������������������ ���� ������ ��������
���������� ������������
�������������������� ����
+ �� ��
+ ��������
������ ��
�������� ���������� �������������������������������� ������������������������������
�������������������� ����������
+ �� ������ �� ������������ ��
��
�� ������ ���� �� ������ ���� ���������� ��������
�� ���� ����
+
����
�� ����
���������� �� ������
+ ��
��
��������
������ ����������������������������������������������������������x�m�p�q�y�n�y�p�e�b�`�Z�X�\�k�t���v�t�q�u�n�y����������������������������������������������������������������������������������������������������������������� ���������������� ������������������
�������������������������� �� ����������������
������������ ������������������������ �������������������� ����
���������� ������������
+ ������������������������ ������
+
��
������
������ ���������� ������������ �������������� �������������� ���������������� ������������ �������������������� �������� �� ����
+ ������������
+
+ ��
��
+
+ ��������
�� ��
������
����
+
+
+
��
��������������������������������������������������������|�s�e�h�h�p�c�j�c�V�V�V�Q�N�T�c�n�{�s�r�o�s�j�u������������������������������������������������������������������������������������������������������������� �� �������� ����������������
�������������������������� ����������������
������������
������������������������ ������ �������� ������
�������� ������������
�������������������� ����
+ �� ��
��������
+ ������ �������� ������������ �������������������������������� ������������������������������ �������������������� ������������ �� ������ �� ������������
+ ����
+ ������
+ ���� ���� ���������� �������� �� ���� ������
+
��
+ ������
���������� �� ������
����
��
��������
+
+
+ ������ ��������������������������������������������������������y�n�c�c�f�n�d�j�e�Y�W�U�P�N�S�a�l�|�q�n�m�n�i�t�~��������������������������������������������������������������������������������������������������������������� ���������������� �������������������� ������������������������������ ������������������
���������� ������������������������ ���������� �������� ��
���������� ���������� �������������������� �� ����
��
������
�������� ������ �� ���������� �������������� ���������� �� ���������������� ����������
��������������������
�������������� ������ �� ������������
+
����
+
+
+
+
��������
�� ��
��
������
+ ����
����
+
��
������
���� ��������������������������������������������������������r�h�[�\�_�d�X�]�Y�K�K�I�E�D�I�Z�e�s�k�j�g�g�`�i�s�~�y���������������������������������������������������������������������������������������������������������������������������������������������������
+ �������������������������� ����������������
���������� ������������������������ ������ �������� ������
�������� ����������
�������������������� �� ��
+
��������
+ ������
+ �������� ������������ �������������������������������� �������������� ������������ ����������������������
������������ ������ �� ������������
��
����
+
+ �� ������
��������
��
+
+ ������
+ ����
+
+
+ ������
+
�� ��������������������������������������������������������w�k�]�a�d�i�]�d�_�S�Q�Q�K�J�P�[�g�v�n�l�k�l�e�p�{����������������������������������������������������������������������������������������������������������� �� �������� ������������������ �������������������������� �� �������������� ��������
������������������������ ���� ������ ���� ��
�������� ������������
�������������������� ������
�� ��
�������� ������ �������� ������������ �������������������������������� ������������������������������ �������������������� ������������ �� ������ ����������������
+ ��
+ ������ �� �� ���� ���������� ���������� �� �� ����
��
�� ������
���������� �� ������
+
+
+
+
�� �� �������� ����������������������������������������������������������������s�h�]�_�`�h�[�d�^�S�P�Q�I�G�M�Y�f�t�l�h�d�h�`�l�u���~����������������������������������������������������������������������������������������������������������������������������� �������������������� ����������������������������������������������������
+ ������������ ! �������������������������� �������������������� �������� ����������
+ ������������
������������������������ ������ ������ �� ���������� ������ ���������� ������������
��������������������������������
���������������� ������������
�������������������� �������������� �� ���� ������ ���������������� ��
+ ��
����
+
+ ����
�������� " ��
+
+
&
��
) $
������
�� ������
% #
+
# " ) ) "
&
" " �� �������� ������ ��������������������������������������������������������n�f�Z�[�]�`�U�[�T�I�J�F�A�>�F�V�^�o�g�f�d�d�]�i�t�~�|������������������������������������������������������������������������������������������������������� ��
+ ����������
��������������������
������������������������������ ����������������
������������
+ ������������������������ �������� �������� ���� ��
�������� ������ �������������������� �� ������
+
+ �� ��
��������
+
+ �� ��
+ �������� ������������ �������������������������������� ���������������� ������������ ����������������������
������������ �� ������ �� ������������
+ ��
+
��
+ ���������� ��������
+
+
+ ��
+
��
���������� �� ������
+
��
+ �������� ����������������������������������������������������������������o�d�W�X�Y�b�U�\�V�K�I�I�B�B�H�T�^�p�g�e�b�d�[�h�t���|����������������������������������������������������������������������������������������������������������� �������������� �������������������� ���������������������������������������������������� �������� ��
������������������������
+ �������� �������� ���� ��
+ �������� ���� ������
�������������������� ������
�� ����
��������
+
+
���� �������� ���������������������������� �� �������������� ������������
�������������������� ���������� �� ������ �� ������������
+ ��
+
+
+ ��
+ �� ���������� ��������
+
����
+
+
���������� �� ������
+
+
+
�� ���������� �������� ����������������������������������������������������������������w�e�Z�N�Q�U�]�N�V�P�C�A�B�<�<�>�L�W�i�^�]�X�Z�P�_�k�v�u�����������y��������������������������������������������������������������������������������������������������������������������������������������� ���������������������������������������������������������� ������������
+ ������������������������ �������������������� ���� ��
�������� ������ ������������������������ ������ �������� ��
����������
���� �� �������� �������������������������������� �������������� ������������ ����������������������
������������ ���� ������ ����������������
+
+ ������
+ ��������
��
������
�� ������
+
+
�������� ����������������������������������������������������������������~�j�_�R�T�V�^�O�S�O�C�@�A�=�:�@�M�Y�j�`�`�\�]�S�`�l�w�u������������������������������������������������������������������������������������������������������� �� �������� �������������������� ��������������������������������������������������
+ ������
+
������������������������ ����������������
+ ����
�������� ������ �������������������� ������
��������������
+
+ ����������
�� ��
+ �������� ������������ �������������������������������� ���������������� ������������ ����������������������
������������ �� ������ ����������������
+
+ �� ���������� ��������
��
+
+
+ ��
+
+ ���������� �� ������
+
+
������ ���� �������� ����������������������������������������������������������������~�h�`�S�U�W�^�P�V�P�D�D�B�@�;�?�M�Z�j�b�_�]�]�U�`�m�x�w����������������������������������������������������������������������������������������������������������� �������������������������������������� �������������������������������������������������� ����������
������������ ���������� �������� ���� �������� �� ������ ��������������������������������
�� �� ��
�������� �������� ���� ������ �� �� �������� �������������� ���������� ���������������� ������������ ���������������������� �������������� �������������������������������� ��
��
��
+
+
��������
+ ���� ��
+
+
��
��
��������
��
+
������ �������� ����������������������������������������������������������������v�d�Z�M�O�P�T�G�M�H�;�;�:�9�7�=�M�X�f�_�^�]�\�T�d�n�y�v���������������������������������������������������������������������������������������������������������� �������� ������������������
������������������������������ �������������������� ����������
+
������������������������ ������ ��
�������� ������
��������������������������������
+
+
�������� ���������� ������
+ ���������� ������������ �������� �� ������
+ �������������� ������������ ����������������������
�������������� ���� �������� �� ��������
����
+
��
+
��������
��
��
����
+
+ ������ ���� �������� ��������������������������������������������������������������}�r�^�V�H�L�N�R�E�K�E�9�7�8�8�7�?�P�[�h�`�_�]�^�W�d�p�{�y������������������������������������������������������������������������������������������������������������������������ ����������������������
�������������������������������� ���������������� ����������
+
������������������������ ���������� ������
+ �������� ������ ������������������������ ������
+
+ ��
�������� ���������� ���������� �� �� ������������ ���������� ���������������� ������������ ����������������������
+ �������������� ���� ������ ���������������� ��
+ ��
+
����
��������
+
+ ��
+
+
�� ������
��
������ ��������������������������������������������������������������}�k�c�V�W�X�]�P�X�R�E�D�E�B�?�D�U�_�p�f�d�c�f�^�j�u���{����������������������������������������������������������������������������������������������������������� ���������� �� �������������������� ������������������������������ ��������������������
����������
������������������������ �������� ������
���������� ������������
+ ������������������������ ������
+ �� ��
���������� �� ���������� �� �� ������ �� ������������ ������ �� ����
�������������� ������������
+
+ ����������������������
������������ �� ������ �� ���������� ��
������
+
+ !
����
������
+ ������
+
+ ���� ������������������������������������������������������x�e�]�P�R�T�X�L�R�L�@�@�>�=�<�C�T�_�n�g�e�b�d�]�i�s��{����������������������������������������������������������������������������������������������������������������������� ������������������
�������������������������� ���������������� ������������
+
�������� �� ������ ��
+
�� ������������������ ���� �������� ���� �������� ������
������ �� ������������ �� �������� ���������� �������� �������� �� ��
�������������� ���������� ���������� ������������ ����
��
��
+ " ��
�� ��
��������
$ �� ��
���� ��
+ ����
������ ���� ����������
+ ������ �������� �������������������������������������������y�`�]�P�V�P�W�P�S�I�@�A�B�C�D�F�[�f�s�j�c�f�g�_�k�v����������������������������������������������������������������������������������������������������������������������������������������������������
���������������������������� �������� �������� ����������
������������������������ �������� ������
+
+
�������� �� ������ ������������������������ ������
+
�� ���������� �������� ������ �� �������� �������� �� ����������
���������������� ������������
��������������������
�������������� �� ������ �� ����������
+ ��
+
+
��
+
+
��������
+ ���� �� ��
! ��
+ ������
+
����
������
�� ��������������������������������������������������������o�e�Y�\�]�b�U�[�U�I�H�H�D�C�I�Z�e�r�k�k�i�h�c�o�y��������������������������������������������������������������������������������������������������������������������������� �� ������������������ �������������������������� ���������������� ������������
�������������� ���������� ������ ��
�������� ��������
��������������������������������
��
���������� �� ���������� ��
���������� �� �������� ������
+
������������ ��������
+ ����������������������
�������� �� ������ �� ���������� ��
����
����
+
+
+
������
+
��
��
�� ��
+
������ ������
+
+ �� ��������������������������������������������������������z�f�^�S�V�W�\�R�T�P�D�A�A�A�?�G�X�c�q�j�g�d�g�a�m�v���~������������������������������������������������������������������������������������������������������������������������� ����������������������
�������������������������� ���������������� ����������
+
������������������������ �������� ��������
�������� �� ������ ������������������������ ������
+ �� ������ ������ ���������� ������������ ������ �� ���������� ���������������� ����������
�������������������� �������� �� ������ �� ����������
+ ����
��
+
+
+
+ ������
+
��
��
����
+
������
��������������������������������������������������������z�o�c�c�f�j�a�e�^�Q�Q�Q�M�L�Q�`�j�y�r�p�o�p�i�s�|��������������������������������������������������������������������������������������������������������������������������� ������������������
��������������������������
���������������� ����������
+
������������������������ ���� ������
+
+ �������� ���������� ������������������������ ������
+ �� ��
���������� �� ���������� ������ �� �������� ������ ���������������� ��������
��������������������
�������� ������ �� ���������� ����
����
+ ��������
�� ������
+ ��
��
��
+ ���� ����
������ ������
+
���� ��������������������������������������������������������s�i�]�_�a�g�Y�_�[�N�M�L�J�H�O�]�j�x�p�m�l�l�f�q�|����������������������������������������������������������������������������������������������������������������������������� ������������������
�������������������������� ���������������� ���������� ������������������������ �������������������� ����
�������� ������������
������������������������ ������
+
�� ��
������
�������� ���������� ������������ �������������� �������������� ����������������������������
+
��������������������
�������� �� ���� ��������
��
����
+
+
+ ��������
�� ��
��
������
+
������ ��������������������������������������������������x�m�m�p�u�j�n�k�\�\�]�X�V�Z�i�t���y�w�w�v�n�x������������������������������������������������������������������������������������������������������������� �� �������� ������������������ ��������������������������
�������������� ����������
���������������� ������ ������ �������� ��
+ �������� ����������
+ ������������������������ ����
+ �������� �� �������� ������ �� ���� ���� ���������� ���������� ����������������������������
��������������������
+ ������������ ����
+ �� �� ����
����
������
+
+
��
+
+
+
�������� ���������� ��
��
+
��
+ �� ��
������
+ ����
+ �� ��������������������������������������������������������}�v�g�i�i�q�d�l�d�[�Z�Y�W�S�Z�l�t���y�r�r�v�k�w����������������������������������������������������������������������������������������������������������������������������� ��������������������
��������������������������
��������������
���������� ������������ �� ������ ���� ������ �� �������� ����������
+ ������������������������ ������
+
+
+ �� �� ��
�������������� ����������
������ �� �� �������� ������ ��
+
+ �������������� ������
���� ������������ ���� �� ���� �� �� ��
+ ����
+ ������
+
��
+ ��������
+
+
���� ��
+
��
�� ��
+
+
+ ����
+
����
������
+
���� ��������������������������������������������������������v�n�b�f�g�k�b�f�^�R�T�Q�Q�P�V�e�p�|�s�q�n�p�j�t������������������������������������������������������������������������������������������������������������������������������ ����������������
��������������������������
+ ����������������
+ ������������
������������������������ ���������� �������� ����
�������� ����������
+ �������� �������������� ������ �� ��
+ ��������
+
+ �������� ���������� ���������� ������ �� �������������� ���������������������������� ��������������������
�������� �� ����
+ ��������
+
+
����
+
������
+
��
+
+ ��������
+ ���� ������
��
+
��
������
+ ����
+ ����
+ ��
������
������������������������������������������������������������s�t�x�}�s�x�q�d�f�d�`�^�e�s�}�����~�|�|�s�~����������������������������������������������������������������������������������������������������������� ���� ���������� ���������������� ��������������������������
��������������
����������
���������������� ������ ������ ������ ����
���������� ����������
+ ������������������������ ������ �� �� ��
�������������� �������� �� ������ �� �������� ������ ������
��������������������������
�������������������� ���� ��
+ ����
+ �� ��
+ ����
+
+ ������
����
+ �� �������� �������� �� ����
+
��
�� ��
+
����
+
+
������
+ ������
���� ����������������������������������������������������������{�p�s�s�z�o�s�l�_�`�_�]�\�a�p�z���~�{�y�y�q�y����������������������������������������������������������������������������������������������������������������������������� ���������������� ��������������������������
���������������� ����������
+ �������������������������� �������� ������ ������
���������� ��������
�������� ���������������������� �� ��
����������
������ ������ �������� ������ ����������
+ ����������������������������
��������������������
��������
����
+ �� ��
+
����
�� ������
+
����
�������� ������������
+ ��
+
�������� ��
�������� ���� ������
+
+
������
+
������
���� ������������������������������������������������������������{�}����|��w�l�l�k�h�f�o�z�������������z��������������������������������������������������������������������������������������������������������������������� �������� ���������������� ������������������������
����������������
����������
������ ���� ������ �� ���� ���������� ����������
+ �������� ���������������������� ���������� ��
��������������
+ �������� ������
+ �������� ��������
+ ���������� ������������������������
������ ������������ �� ��
����
����
�� ������
������ ��
+ ��
��������
+
����
��
��
��
! ��
+
+
+
����
+
+
+ ������ ������������������������������������������������������������v�y�}���{�~�v�c�j�l�k�h�n�z�������������z��������������������������������������������������������������������������������������������������������������������������������� ����������
��������������������������
+ ���������������� ��������
�� �� ����
�� �� ������ ���������� ��������������
�������� ���� ����
+ �������� ������ ���� ������������
+ ����������������
�������� ������ ���� �������������� �������������� ������������ ������������
������ �������������� ���������������� �������������������������������������������������������������������� ������ ������������������������������������������������������������ �� �������������� �� ������ �� ������������������
+
���������� ����������
������ �� �� ���������� ���������� �� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ���������������������� �� ��������
+ ������ ������������ ����
+ �������������������� ����������
+ �� ���������������� �� ������
�� ���� ���������� ������������ ��������������������
+ ������
+ ������ ������
�������� �������������� �������� ��������
+ ������������������������������ ����������������������������
����������������������
+ �������������� ���������������� ���������������� ������������
+ ���� ������������ ���������� �������������� ���� ������������ ����������
�� �������������� �� ��
�� ���� ����
+ ���������� ��
+ ���� ��
������
+ �� ���� ������
+
+
+
������ ������ ����������������������������������������������������������������������������������~����������������������������������������������������������������������������������������������������������������������������������������������������� ������������������ �������������������������� ������������������������ ���������������� ��
+ �� ���� ����������
����
���� ����������
���������� ���������� �� ������
+ �� �������� ��
������ �������� ���� �� �������������� ���� ������ ������������ ������������
���������� �� ������ ������ ������
������
�������� ������ ������ ����������
�� ������ ���� ����������
+ �� �� ������������������������
�� ��������������
+ �� �� �� ������������ ���������� ���� ����
+ ��
+
+ ��������
+ ����
+ ������ ������������ ������ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ���������� ���� ���������� ������������ ��������
+ �������������������� ���������������� ������������������������ ���������� �������� ����������
+ ���������� ������������ �������������������� ������
�� �� ��
������ �� ���� �� �� ����
������������������������������ ������������������������������
+
����������������������
�������������� ������ ������ ���������������� ���� ��
������ �� ������ ���� ������������ �� ���������� ��������
�� ����������
+
+
��
�������� ������
��������
+
+ ���� ������
��
�� ��
+ ��������
���� ��������������������������������������������������������������������������������|�z�~����������������������������������������������������������������������������������������������������������������������������� �� �������� �� ����������������
�������������������������� ����������������
+ �������������� ��
���� ������������������ ���������� ������ �������� ���������� ������������
+
�������������������� ������
���������� ����
+ �������� ��
+ �������� ������
������ ������������������ �� ��������������������������
�� ������������������
�������������� �������������� ���������������� ����������
���� ������������ �������� ���� ������ �� ���������� ���������� �� ����������
������
������ ������ ���������� ����
+ ��������
��
��
��������
������ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ���������������������� ���� �������� �� ����������������
+
+ �������������� �������� ����������������������
+ ��������������
������������������������ �������������������� �������� �������� �� ������ ������ ���������� �� ������ �� �� ��
������
�� �� ���� �� ����������
+ ������������������������������ ����������������������������
����������������������
�������������� ������ �� ������������ ��
���� ������ ���� ���� ����
�������� �� �������� ��
��
�� ���� ������
+
��������
+ ���� ������
+
+
��
��������
+
���� ��������������������������������������������������������������������������~�~�}�y�y�~����������������������������������������������������������������������������������������������������������������������������� �� ���������� �� ���������������� ��������������������������
+
+ ���������������� ��
+ �������������� �������������������������� ���������� ������
+ ��������
+ ���������� ���� ���������� ������
+ �� �� ������
���� ���������� ������������
������������������������������ ������������������������������
���������������������� �������������� ������ ������ ���������������� ������������ ���������� ������������ ���������������������������� ����
+ ���������� ����������
�� ������������ ������ �������� ����������
���������� �� ����������
+ ������������������
+ �������� ������
��������
+ �������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������
+ �������������������������� ���������������������� ��������������
�������������������������� �������������������� ��������
�������� �� ������
�������� �������������� ������
+ ��
������
�� ���� �� ���������� ������ ���� �������������� ������������������������������ ����������������������
������������ ���� �� ������������
+ ����
+ ������
+ �� ��
�������� �������� ��
+ ��
���� ������
��������
+ ���� ������
+
+
+ ������
+
������
���� ������������������������������������������������������������y�z�|���{���w�j�k�i�e�b�i�u���������}�}�u�}������������������������������������������������������������������������������������������������������������� �� ���������������� ������������������ ��������������������������
+ �������������������� ��������������
�������������������������� ������������������ ��������
+ ���������� �� ������
�������� ����������������������
�� �� �� ��
��������
�� ���� �� ����������
������ �� �������������� ����������������������������
��������������������
���������� �� �� ���� �� ������������ ��
+ ���� ���� ������
+ ���� ������ ����
�� �������� �� ������������ ������
+
�������� ������
��������
����
������������
+ ��
������
+ ��������
������ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ �� �������� ���������������� ����������������������
+
����������������
+ ������������
�������������������������� ���������� ������ ��������
+ ���������� �� ������ �������������������������������� �� �� ��
����������
�� �� ������ �� ����
������ �� ���������� �� ��������������������������
+ ��������������������
�������� �� ���� �� ������������
+ ���� ���� ������
+ �� ���� ����
��
�������� �� ������������ ����
�������� ����
+
��������
���� ������
+
+
+
������
+ ������
+
���� ��������������������������������������������������������������������������x�z�x�u�u�z����������������������������������������������������������������������������������������������������������������������������� �� �������� ���� ���������������� ������������������������
+
����������������
������������
�������� ���� �� ������ ���������� ������ �������� ���������� ������ �������� ���������������������� �� �� ��
+ ������������ ������
������ ��������
���� ��������
�������������������������� �������������������� ��������
���� �� ��������
���� ���� ������
+ �� ������ ��
��
�������� ��
������������ ������
������
+ �� ��������
���� �� ������
+
+
��
������
���� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ �� �������� ���� �������� �� �������������� ������
+ ���������� �� ���������� ��
+ �������� ������ ������ �������� ����
+ ������
���������� ��������
�������� ���������������������� �� ���� �� ���������� ��
+ ������ ����
������ ���� ��
+ ������ ����������
������������������������
��������������������
���� ��
���� ��
+
+ ��
+
+ �� ������
+ ��
+ ������ ��
�������� ��
+ ������������
+ ����
�������� ��
+
+
+ ��������
+ ����
+ ����
������
+ ���� ��������������������������������������������������������������������������z�|�{�{�z������������������������������������������������������������������������������������������������������������������������������������� �������� �������� ������������ ��������
+ �������� ������
��������������
���� �� �� ���� �������� ���� ��
+
���������� �� ���� ��������
����������������������
���� �� �� ������������
�������� ��������
����
���� ���������������������� �� ������ �������� ��
����������
+ ������
+ ��
+ ������
���� ������
���� �� ����
+ �� ��
+ �� �� �� ������
������ ������
+
����
������ ��
��
$ �� �� ��
��
��
����
+ �������������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ���� ��������
�� ���� �� ������
�������������� ��
���������� ����������
������
������
+ ����
+
+ ������ �� ���������� �������� �������� ������ ������������ �� ���� �� ��
+ ��������������
+ ������ ����
������������ �������� ��������������
������������������������ ������ ������������ ����
������
+ �� ��
+
������������
+
+ �������� ��
������
+
������
+ ����
����
������ ��
����
+
+ " $ ����
��
+ ��
������ ����������������������������������������������������������������������������v�~���{�}����������������������������������������������������������������������������������������������������������������������������������� ���������� �� �������� ��
�������������� ��
��������������
��������������������
���� ���� ��
+
���������������� �������� ���� ������������ �� ������������������������
������ �������������� ���������� �� �� ��������
+ �������������� ������
�������������� $ ����
+ ���� ��
���� ����
�� �� �� ���� �� �� ������ ����
+
+
����
+ ����
����
����
��
������
" ����
+
��
������
+
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������ ������
�� ���������������� ����������
����
+ ������ ������ ������ ���� �� ������
+ ��������
���������� ���������� �������� �������� ������
+ �������� ����
���������� �� �������� ������
���������� ������������������������
+
�������������� ����
����������������
+ ��
+
+ ����
����
���� ��
+ ������ ���� ���� ���� �� ����
��
����
+
����
+
+
+
������
+ ����
���� ��������������������������������������������������������������������������x�u�q�n�n�t���������������}������������������������������������������������������������������������������������������������������������������� ����������������������������������
+ ����������������������
�������������� �� ��
�� ����
+
�� ������ ������������ ������������
�������������������� ������
+ �� �� ���� ������ �������������� ����������������
�������� ������������ �������� ���� ������������ ���������� �������� �� ��
+ �� ������ ���������������� ������ ���� ���� �� ������ ������ ���������������������� ������������������������
+
������������
��
+ ��������
��
+
+
+
+ ��
+
�� ��
+ �������� ���������������������������������������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����������������
+
�������������������������� �� ���������������������� ���������� ����
������ ������ �� ��
�� ���� ������������ ���� ���������������������� ��
+ �� ������������
���������� ���� �������� ���� ������������ �� �� ��������
��������������
��������
���� ���� ���������� ������ ��
���� �������� ���������������� ���� �� ���������� �� ������ ���� ���������� �������� �������������������������� �� ������������ ������
+ ������������������������ ������
���������� ������
+
+ �� �������� ������
+
�������� �������������������� ������
��
���������� ��
������������ ������ ������ �������������� ������ �������� ���������������������������� ������������������������������������ ���������������� ������������������
+ ���������������������������� �������������������� ����������������
������ ���� �������� ���� �������� ���� �� ������������
������������������ ��
+ ��
+ �������� ����������
��
+ ������ ����������
������ ��
���� �������� �� ���� ������
�� ������������ �� ������
�������� ��
����
+
+ ������
�������� ���� �� ���� ��������
+ ����
+ ������ �������� ����
+ ��������������
�� ��
+
+ ������ �������� ����
���� ����
��������
+
+
+
������
+
���� ������
������ ����
������
+ ���� ���� '
���� ������
+
+ ���� ��
+
+ ������������ ����
������
��
+ �������� ����
+ �� �� ��������
+ ������
+ ��������
�������� ��
+
������ ���� ���� ��
�� ������ ���� ����������������������������
���������������� �������� ������ ��������
������ ���� ����������������
+ �� ������ �� ������ �� ������
��������
+
�� ���� �� ������
������
+ �� ��������
������ ������
+ �� �� ���� ��
+ �������� ��������
������ �� ����
������ ������
����
+
+ ����
��
������
+
+
) & 6 = = G J H ^ K M Q ^ n z { q t s t t x � � � � � � � � � � � � � � � � � � { u v | s � w k f c Y S O U X ] ` Z N B < B D H C 1 + + * $ "
! & % $ $
%
# !
+
��
+
+ ����
+
+ �� ���� �� ���� ������
������������ ! �������� ���������� �� ������������ ����
+ �������� �������� ����
��
������ �������������� ������! ���������������� �� ������ ���� �������� ���� ���� ���� ���� ��
+ ������������
�� ����
������������
+ ����
�������������������� �������� ���� ���������� ���� ������
����������
���� �� ���������� ����
+ ������ �������� ������ ���������� �� ����������������
+
������������ ������������
����
������������ �� �������� ������������
�������� ����������
�������������������������������������������������������������������������������������������������������������������������������������������������� ���������������������������� ������ ������������������������ ��
+ �������������� �������� ����
�������������� ����������
�������������������� ������ ����
+
������
��������
+
+ �� ���� ����
���� ����
�������������� ���� �������� �� ���� ������ ���� ������ ������ ����
���������������������� �� �� ����
���� ���� ����
��
��
+ ������
+
+ ������
��
+
������ ������
��������
������ �� ���� �� ���� ����
������
����
������ $
+
���� ��
�� �� ��
����
��
+
$ & - + ) & / 3 : 1 ; J V R L I M P J J V Z ` v o g _ c \ K U n w u h h [ X T Q L K T b Q G E H D E I K H K F F ; ' . > 6 3 8 + % ( ' &
% #
% 2 & "
��
+
+
+
+ �� �� ������ ������������������������ �������������������� ���������� ���������� �������� �� ������ �������� ������ ����������
�������� ������ �� ������ �� �������� ������������ �� ������ ��
���������������������������� �������������������� �������� �� ���� ����
+ �� ���������� ���� ����
+ ���� �� ������
�� �� ����
+ �� �������� �� ������ ��
+ ���� ����
+ ����������
+ ����
+ �������������� �� ���� ��������
+ �������� �������� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������� ������������������������ �������������� ������ ����������������
�������� �� ���������� ���������� ���������� ��
+ �������� ���������������������� ���������� ����
���������� ������ ��
+ ������ �� ����������
+ ������ ���� ���������� �� ���������������������������� �������������������� ���������� �� ������������ �������������� ���������� ���� ���������� ������
+ ���� ������������ �� �� ������
+ ���� ������������ ������
�������� ��������
���������� �� ������
�������������� ��
����
�������� �������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ���������������������� �� �������� ���� ���������� ���� ������������ ����
�������������� ��
��������������������
������ ����������������
+ ������������ �������� �������� ��������
�������� �������������� ���� ������������ �� ������ ����
���� ��������
������������
������������ ����������
������������������
������ ��
+
���� ���� ����
��
�� �� ����
+
��
������
+
��
������
+
+
+
�� �������������������������������������������������������������������������������������������������������������������������� ����������������������������������
������������
��
��������
����
+
����������
+ �� ��
+ ���� ���� ��
���������� ���������� ������ ��
������ �������������������� �������� �������� �������� �� �������� ������ ������������ ���������� ������������ ������ ������
����������������
���������� �� ���� ����
+ �� ���������� ���� �� ����
+ ������ �������� �� ������
������ ��������
���� �� �� ��
+ ����
+ ����
��������
������ ������ ��
����
+
�� ��
& & - ( # $ ) ( + / 6 : < E < 4 1 2 2 / 2 ? F A 3 2 4 3 . , . 1 / ; 0 % $ # $ ( $ + % & " !
* %
��
+
+
�� �������� ����
+
�������� ���� ���� ���� �� ������������
��
�������� �������� ������������ ������ ���������� ������ ���� ������ �� ���� ����
+ �� ��
�������� �� ���� �� ������ �� �� �������� ��������
�������������� �� ������ ����
+ �� ���� ������ �� ����
+
�� ����������
�������� ��������
+ ����
������������
������ �� ��
+ ������ ��
�� ����
����
+ �������� ������ ���������������������������������������������������������������������������������������������������������������������������� ������������������������������������
���������������� �� ��������
��������
���������� ����
+
������������������
�� ���� ������ �������� ����
����
��������
���� ����
������ ������������
+
���������������� ����
����
+
�������� ���� ���� �������� ��������
������������
+
+ # ������ ������������
������
������ ���� ��
������
+ ����
+
+ ��
������ ���� ��
���� ����
+
+ ����
+ ����
+
����
+
�� ������
��
+ �� !
��
�� + /
�� #
������
+
( - ! " / > @ B A 4 > P M P O P [ f r i X X T O K X k s [ 7 G _ e Z T J L N [ K @ < ; > 7 5 9 / * + - . ( * 0 , & & $
# & %
����
����
$
������������ ������
#
���������� �� �� ���� ���� ��������������
�� ������������ ������������
�������� ��
+ ������ ���������� ����
������������������
+ �� �� ������������ ������������
���������� ���������� ��������������������
������������ ����
�� ��������
+
����
�� ��������
������������ ������
��������
����
+
���������� �� ��
+ ������ �� ����
+
+ �� $
+ ���� ��
+ ����������
������ ������ ���������������������������������������������������������������������������������������������������������������������������� �������������������������� �������� ����������������������
�������������������� ������
��
+ ����
+ ������ �� �� ���������� �� ���� ����
������ ���������� �� ������ ���������� ������ �������� ���������� ����
������������������ ���� ��
+ ����������������
���������� ����������
+ ��������������
�������������� ������ ������ �������� ��
+ ����
��
+ ������
�� ��
+
+
+
+
������
��
�� ��
���� ����
+ ����
+
+
+
�� ����
+ ����
+ " ' ( ! ! & % * ( 1 - "
% ) 9 : 7 ( - & "
,
+
+
����������
+ ���� ������������ ��
��������
#
����������������
���������� ��������
+ ��
���������� ����������
+ �������� ������ �������� �� �������� �� ������
���� �� ������ �������� ���� ����
���������� ������������������������
+ ���������������� ����
���������� ����
+ ���� ��
+
+ �� �������� ���� ������ ���� ��
������
+
+
�� ��
��
+ #
��
+
+
��
������ ���� �������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������������ ����������������
�������������� ��
��������������
+
������ ���� �� ������
������ ���������� �� ���� ���� ������ ������������ ������ �� ���� ����
+ ����������
+ �������������� ������������ ���������� ������������
+
���������� �� ��
�� ������������ ��
��
��
+ ����
+ ������ ����
��
+
��
+
��
+
��
+
+
+
+
��
������
�� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ����������
���������������������� �� ���������������� ����������
+
+
�������� ������ ���� ������ ���� ����
+ �� ������������������������ �������������� ������������������ ���������������������������������������� �������� ���������� �� ������ �� �� ������������ �� �� �� �� ������ �������������������������� �� ������
+ ������������������������ �������������� ������������������������������
��������
��
+
����
+
��
+
+ �� �������� ������������������������������������z�x�z�j�u�h�\�@�+�%�"�
�"������������������������w�p�p�l�h�r�{����������������������������������������
��%�*�,�,�+�4�@�[�_�W�Y�^�g�a�c�`�j�u��������������������������������������������������������������������������������������� ��������������
���� �� ����
+
�� ���������� ������ ���� �������� ���� ���� �� ���������������������� ���������� ������������������ �������������� �������������������������� �� �� �������������� ������������
+ ������������������ ����
������
�������� �� ������ �� �������� ������
���������� �� �� ������ ��������
��
+ ��
��
+
�� ��
+
#
+
+
����
������������������������������������������������p�]�V�[�O�H�&�!��� ����������������������������������������������� ���
��
� �'�6�8�E�M�T�]�\�`�f�b�f�u����������������������������������������������������������������������������������������������������������� ������������
+
+ ������ ����
+ ��
���������� ���������� ������ ��
����
�������������� �������������������� ������������������������������������������������������������ �������������� �������� ��
�� ���������� �� ��
+
������ �� ������������ ��
+
+ ������ ��
+ �� ���� �� ���������� ��������
��������
+ ���� ��������
���������� �� ����������
������ �� �� ���������������� ����������������������������������������������������������������������������������������|�������k�g�P�E�;�=�=�K�;�B�?�,�)�$�#�
�-�7�<�G�@�A�B�<�/�=�I�Q�O�i�e�b�h�h�a�l�q�p��������������������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������� ������������������
+ ���� ����
���� �� ��
�� �� �������� ��
+
+ ���������� ������������ �� �� ����������
������������������ ������������ ���������������������������� ������������ ����������
+ ������������
������������ ��
+
���� �� �� ���� �� ����
+ ����
+ ������
+
+
�� ������
��
+ ��
+ ��
������
+ ��
����
+ ��
����������
+ ������������������������������������������������������������������������������������}������r�h�_�Q�E�?�?�@�D�<�B�6�#�1�/�'�
�)�/�A�J�@�A�I�;�/�=�D�T�S�m�j�i�Z�p�`�n�r�x������������������������������������������������������������������������������������������������������������������������������ �������������������������� ���������������� ����
������Z 9 ���� $ (
4 ; # 6 : 2 4 , % " ������ �� % ) 0 �� ����
& B f U
+ ���� �������������������������������� �� * Q � z N ��d�[�\�f�������������X�e���������! J E % ����8 9 8 8 ��������
6 8 ' ���� ( # *
����. 8 6 �� " : 5 , 2 < B < ' # X K @ \ v f E < : ) , ) ,
& J Z i b f N M / ���� 9 O ^ _ : M U > % / Q ^ _ M A G F N U y z R F ` p ; G T R a B O A S S J > �� 4 A : - ��
+ 7 % " * $ $ H Q 0 �� ��
6 # ��
+ 9 ] 8
/ ; E 3 1 ; K 6 R ` \ P �� ��
> " & 1 = 1 ������
H K ' �� ( R Z P \ I , 2 C K R < ���� . " �� �� �� J 8 $
;
����
+ ������������7 3 ���� ) $ ����������? ' ��������������������������������x�)�������l�0�,�<�@�@�>�&�)�6�W�B�=�M�X�#�=�X�P�6�/�3�W�m���q���{�s�u�Q�v�r�~��������������v��������������������� ��% . ���� �� 8 8 ) ���������� , 0 6 ������������������������, ������ 0
������������ , N { } k ��������
+ ����
��������" ��������_ M ������ �� ( �� , . / 8 < 6 #
+ * 6 ) , ( 2 1 ���������� 1 ) - ���������� 9 E
�� % 2 I ] M ���� �������������������������������� < i t O ��W�\�k�x�������������N�S������� ( 9 > / ��E H = ? " ������
�� ? L 9 * 5 " ������
6 3 1 ����K F I �� ! L Y P E : K \ R ? O J F r � s H 8 I > C < 1 ) 0 7 2 X k � } { f _ B �� @ S d g d I f s Q *
: S P R H @ S [ _ l � � q R N ` E M \ V ^ J V O m n c N �� : N Z J
6 Z k O 7
) & 4 / < ��5 * 0 ; 5 ? , C 8 ) / , ( E \ [...]
��.��%�E�<�&�%�2�X�h�r�p�t�|�u�p�a�z�f�z�������������e�P�n�������������������
���� ���� ��������3 = 3 ����������2 P ; ������������������ ���� ������������0 4 3 ����������) D G c e P �������������� ��������*
V ? ������
- ) �� # , 9 B 6 ' 3 & ) # ! ��������
) & ' ������
( A O @ ����
������������������������������������ ( A l j A
��d�Y�Z�e�������������V�W������� ' < 5 $
+ ��5 ; 8 3
������������ 1 H > ) ������ , ! ) �� 4 = + ��
6 < 8 & / 2 5 ! ) I = : Q f G % . G , 1 . * !
- $ F Z m b w V D ;
7 B I V g B L [ Q * ) K _ L K B P S M G x v Z e V Y : E U _ [ @ K A d ^ O ? , : H K ? % > K 9 6 ' . , ' % ! # . $ ( / , ! = ? 2 )
% $ $ : 0 D I Y d r w l S 0 % �� " 6 < 9 - * ������
$ , H B # ; �� < S L S C " ( $ @ N I = # ���� / 0 ! ��
+
*
�� $
+ ���� ��
, 1 ������������4 ! �� ' ����' ����������������������������������m�����n�:�
+�
�6�4�'�?�J�1�6�D�)��4�P�8�/�W�C�/�3�:�O�V�u�����x��j�d�����r�����������o�i�j������������������� ������������ ������ < 7 > �������� - A 4 ���������������������� ���� ������
- % ������������ $ * > P ` ������������������ ��������
+ ��������P < �� + *
$ # 5 B D 9 & 5 % "
��������
" $ $ �������� #
+ $ > K 8 ���� ������������������������������������ ( G m k @
��d�b�f�n�����������{�X�[������� ' 4 2
3 7 1 /
������������ & = : '
������ +
% ? B 3 9 > 8 , / 6 6 $ ) G = 7 L d L , 0 B 2 ? 4 . ) $ 1 + J X n h ^ H B ! 7 @ I X r L U _ V 6
2 T d W T H T U U W ~ h n ` f O V ^ j f N U L k a U J 8 $
< O L E ( ? J ; : ) " / / & $ # "
* % ) - '
8 9 ( ! 0 ( 7 9 F P ] ^ b F
* 3 - % ' �� ��
$ > > $ 8 B X R X D % * # H N I @ + ���� 2 4 % ��
+ . # - ) *
+ ���� " $ 5 ; ������������7 + # ���� ����
����������������������������������m�����h�>��)�6�4�0�D�O�5�7�C�)��8�Y�G�7�b�U�.�5�@�V�V�i���|����h�m�����������������{�|�q�����������������
������ ���� ������# M > ? " �������� ) A 5
���������������������� ���� ������ + $ �� �������� 0 < Y [ a �������� " ��������# $
������������������~����������������������������������������������������������~��}����������������������z�s�z���{�~���������w�u�����q�t�u�~�v�v�|�����x�p�v�|�w�r�j�j�v�r�~�s�|�s�l�~�t�q�����|���s�|�����}�u�{�������y�{�v�}���p�r�r�����|�x�~�����z�z�{�|�����t�y�v�����������x����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+�����!��������$�
��
��
����
�
���#� �
���� [...]
+ ���� ���������� �������� �������� ������ ��
+ ��������
+
%
&
��
' , 2 0
# "
��
��
! $ !
% * ) 2 2 1 ) * , 2 ' ) " / %
��
�� %
+ ' !
+ '
+ "
+ )
��
"
+
+ ( ( ' , 1 & " &
$ # "
+
$ $ ��
+
%
"
%
! !
������
����
!
��
�� �� �� ���������������������� ���������� ��
�� ������ ��
������
+
+
+ ������
"
. &
#
+
"
! + 4 7 = ; ! #
# ( ) $ ( # ! *
��
����
! . . ! ( ! * 1 2 5 6 4 / . 0 9 / . & / - !
#
% ( ! ' % & +
! 1 &
1 , -
/
# 3 - '
! &
! $
!
! $ $ 5
) + % "
( . "
( '
"
$
! " $ # * & 4 0 1 5 8 0 2 # . 4 ) ( # !
$ . , + + +
+ ! #
% & 0 .
" # # 1 + $
# ' ( + - , 1 , , * " ) $
��
$ ( " ! ! *
!
�� ��
+ ��
�� ��
+ ������������
��������
��
(
�� ������ �� ��
+ �� �� ��
&
* !
! 5 *
) *
3
��
+
# ' 0 4 ? > $ $ ' " ) , . * 4 / / ' .
+
" ' $
* ) , 3 ( . % 5 8 2 : < 8 2 3 5 : 4 = 0 H 3 $ " # %
+ " $ ( $ & (
- $
0 & 4 / ! 1 . (
#
$
! <
+ " $
+ +
&
4 ) ( 4 ? / # % / ! !
( & & !
��
( '
��
# )
!
- #
( % " + ! & /
) %
������ ����
$
��
" ��
�������� ������ �� ���� ���������������������� ������������ ������������
�� ���������� ���� �������� ���������� �� ��������
"
/ '
#
+
*
��
( 0 5 > :
!
$ ' ! ( % " (
�� ����
+ ' +
"
* 1 . 3 5 3 , ( - 4 + 0 $ 4 )
��
+
" " # $
- "
* $ + (
+
, & !
!
.
+ %
+
+ * ! ! ( . # !
%
��
# ! ��
( # # " ) $ " $ $
������
�� ����
! ��
! ��
�� ������������������ ������������ ��
$
+
������ ������������ �������� & " & ( ) & $ $
" $ # # * 5 / % $
" +
( !
# + 6 @ C I E . % + - " ) $ * - 2 - 1 # , , , ( 8 * #
����
+ % ( 6 7 & + 0 , 5 @ ? A > @ : 7 : A 8 8 / 7 6 , , - $ " ��
+
' ( ! ' % ( ,
( : / "
% % 5 0 / ! +
+ . ( #
% !
! " $
" # $ 3
$ ' "
( . ! ' !
!
! " )
# 1 * - 0 0 ( -
& * #
& ( % ! $
+ (
" " " 3 + %
" ( + * / 0 2 / * ' ! % - * ��
+ % & " " ,
$ ! ) ��
+
$ ! $
�� ����������
����������
��
+
* # �� ������ ��
��
+ �� ��
����
)
$ *
% 4 - " #
% 0
# 3
- 2 7 E A " #
# & - ( - . % + . %
$ &
% & 6 5 ( - ( 5 = 9 > > B 9 7 : A 6 < 0 F 7 ! ' * &
% ! #
% ' ( & ' ' 2 %
!
/ * 2 (
0 ( $ !
#
% 1
+ & # $ .
! " ,
$ 5 & , 5 9 ) .
, 3 & $
* * * $ %
" + +
��
(
)
"
&
$
4 )
$ ( ) , + / . + , !
( 1 - %
+ ����
+
# % *
0 ,
% ,
�� �� ��
�� ������������������ ���������� ������
+
��
����������
������ ��������������
��������
! "
# 0 * # !
,
+
)
����
( 0 6 ? ;
! !
$ ( ' + ( ' ( 2 &
����
+
+
# % 5 6 " * - ( 3 = < > = @ 9 8 8 ? 8 9 - 8 3 ( ' ( #
��
+
+ ! " "
# % 1 &
* ' * $
- % ! !
! -
# (
&
. & + / 3 & ,
& , # ! # !
��
% $ ��
+
+
+ !
$ % ( ' " " + (
+ ������
+ ����
$
+ ��
#
+
�� �������������� ���������� ��
+ !
+
����������
��������
& $ " # " & 1 * " !
)
% �� ! - 5 : > ; &
& &
$ % ) . * / " ' ) * ' 8 + #
+ ����
" 1 3 # ) + ) 2 : ; : : < : : ; A : 7 / 1 5 1 . * #
+ ! ��
+
# " % ! 6 ( ! # 1 + * %
- ( " # !
#
! -
# % "
& +
!
#
* ( + + - % .
$ * $ "
# # " "
+
% "
�� ��
- !
! $ & ' % " ' ' ��������
+ �� ����
+
��
+
+
���������� �������� �� ������������������ ������������ ������������
+ ���� ����������
�������� ������������ ��������
' %
*
+ & " ����
" ' . 4 /
"
" *
+
+
����
* *
!
( 2 0 2 / 3 / 0 / 6 , , # * ( ! ! "
��������
+ �� (
�� ��
"
+
+
����
+
+
# & & #
#
+ ������
������
+
&
+
# $
$ # �������� �������� �� ���� ����
+
������ ��
+
+ �� ���� ��������
�� ������������������ ������������������������ �� ���� ����������
������
+ ������������
������������
( $ #
+ ! ����
" ( / 2 - ! #
"
/ !
+ ��
������
) (
$ 2 - . / 0 - . . 2 - + " % ( & #
+
+
+ ����������
+
�� ,
& #
��
+
+ &
+
��
+
#
+
" $ &
'
#
����
+
+ ��������
+
'
+
" #
% % ��������
+ �� ���� �� �� ��
����
+
�� ���� ��
+ ���������������� ���������� ��
+
��
����
���������� ��������
$ $
! $ . * ! # ! *
& ( ( ) . 3 7 1
" $ % ' % % ( ) 7 )
+
����
0 0 % $ " ' 2 0 1 2 4 . . / 4 - + " # ( ) % $
��
2 #
! 0 ) $ "
1 ' "
)
+
! $ #
' (
#
# $ & ) ) # ,
! '
+
+
+ !
������
+
, !
" !
% % ��������
+
�� ���� �� ���� ��
����
+
�� ���� ��������
�� ��������������
+ ������������ ���� ���� ����������
+ ��
�� ������ "
"
# + ( # !
# .
# , * . %
+
& - 2 3 +
% & ) " % % 3 % #
+
+ ����
+ # ! 1 / ! $ " " + 8 2 3 2 7 3 6 3 9 3 0 & ' . . ( '
��
$
��
3
- + $
"
+
. % # !
!
(
% $
# &
"
) ' + - , % 0
& , ( $
% " ! !
& $
$
% ! %
! " 1 & # # # $ ' * , ! !
0 . " ��
��
" ��
( �� ������ ��������
+ ����������������
+ ���������� �� ���� ������
��
�� �� ������
* & !
)
' & * ! ��
+ # ) 0 2 ,
! ! % # # ( 3 #
����
+
/ - " #
# . ) + , 0 ' + , 3 - )
' ( $ "
+
+
��
#
+
��
+
2
- ) !
+
+
/ % !
+
+
#
+
+
! #
$ %
$ " ( ' ' " - " $
������
+ ������
+
+
,
$ #
* *
��
���� ��
+ ����������
����
% ��������
�� ��
+ ����������
+ ��
����
"
% ( ! " ' !
# $ ( 2 - ) )
! - !
! * + 1 #
+
) . 3 7 2 "
$ $ ' ! # % & + 6 ) "
��
% # 6 4 ' ) % # ' 2 / . . / * + * 3 , (
' + % #
"
)
2 "
. * %
*
& 9 . % #
$ "
&
+
# ( & "
, +
' !
! " # # !
*
!
��������
+ �� ��������
+
- "
!
) +
����
+ ���� ����������
���� $ ��������������������������
�� ������������������ ������������������������������
���������������� ��������
+ ��������
+ ��������
!
#
��
#
������
+ ��
+
! %
+
*
��
��
������ �� ' ! $
" '
&
������ ���������� ��
���������� $
�� ��
�������� ��
&
+ ��
+
��������
+
"
$
+
+
+
���������� ������ ����������
+
+
$
+ #
+ �������� �������������� ������������ ������
+ ������������ �� ��
+ ������������������������ �� ���� ���� ����������
�� ��
���� ����������
��
������
+ "
������
! " # $
' # ( " ����
+
& ( , %
+
!
# 0
+
��
2 -
, * , - ) # * * 0 ( '
& + % #
��
+
+ #
+
�� .
* " "
5 '
��
& !
( &
+
$ $ % ' # ! . " % !
��������
+ �� ! " �� �� ��
! -
, & "
+
���� ������ ����
������
' ���������������������������� ������������������������ ������������������������������
������ �������������������� ���������������������������� �������������������� ����
+
�� ���� ���� �� ����
+
+ ������
% $ . *
������������ ���� ����������������
# ! "
!
�������� �� ������������ ����
�� ����
����
�� �������� ����
��
���� ���� ����������
�� ��
����
��
+ ��
+
��
+ ���� ����
+
���������� �� ��������
+ ������������������������������ ������ �� ��������
+
������ �������������������������������������������������� �������������������� ���������� �������� �� ��������
���������������������� ������������ ��������
������
+ ������������ ��������������
��������
- &
#
+
+
%
"
" ' 4 = ? D @ (
% (
$
% ( + & *
% % " # 1 "
+
����
+
# ' 7 8 ( * . ) 3 < = ? ? = 7 6 7 < 4 2 * / 1 , ) ( !
*
) *
! ' ! ' + % 7 , !
! 2 - * -
/ ( #
% !
#
.
+ $ % * % "
! * ( ) * ) $ ' '
" ! #
+
#
+ �� ��
+ ����
&
&
+
+ �������������� �� ����
+
+ " ��
�� �� �� ��
+
���������������������� �������������� ��������
+
����
+
+ ������ �������������� ������������������
+ $
+
������
( 1 2 6 4
-
+
��������
* )
!
# , - / . / ( * + 3 + & ! " % %
!
0 %
+ ( % (
+ * ! " !
! '
& !
*
!
# '
$
! ! " " "
����
�������� ���������� ��
+
!
+
+ �������������� ������������ �� ������������
������
+
�������� �� ���������������������� ������������ ��
+
�������� �������������� ��������
$ # !
" . &
#
+
������
$ 1 : > B ? * ( * & % ) + % (
# $ # ! 0 $
+
+
��������
! " 2 3 % ( - ) 1 : : ; 9 = 4 4 4 < 2 0 ' , , % " "
! ��
+
$ ' ! ( " ) ,
$ 7 * !
1 - ,
,
, $
"
&
!
-
$
$ *
! !
!
* & ' ) * # ) " ' !
" " # !
& ! ��
) ! $ ( , $ !
" �������� �� ����
+
+
&
+
+
+
+
�������������������� ������������������������
��
+
�������������������������� ������������������
+
%
���� �� �������� ��������
( - 0 3 3
, "
�� ��
�� ��������������
+
( )
" # , - . + . ' & ' . %
�� ������ ��
+
*
%
�� �� ��
% $
% % ( ' % %
$
!
+ ��
+ �������� ������
#
+
! $
�������������� ������������
! ��
+
�� �������������� �������������� ��������
������ �������������� ������������������
+ &
!
���� ! + 3 4 7 5 "
# $ " # % 3 (
+
������
+ - *
! ' . 0 1 1 2 / - / 8 1 , % % - + ) & '
' & %
% '
& 8 , #
# & 3 - )
(
. ' !
& " #
% ) "
% !
! " / $
) , !
( "
#
! !
' $ ' % " &
+ ��������
+
"
+
"
������������ �� ���� �� ���� ��
��
+
�� �������������� ���������� ��
"
+ ������ ������������ ����������������
# ' $ " $ $ ! % 1 * " !
'
������
$ 1 ; ? D B + " ( ) % % ) + * , " ' ' ( ' 5 + !
��������
! # 1 4 $ + - , 5 > @ A A B < < < C : 6 . 4 5 0 , , # ! ��
% ' " ( # ) - ' < 0 % !
$ & 5 / - (
. ' "
& "
!
# ( !
% ! -
! % !
* - ' #
"
! " %
! - ( + - , ' -
" ' #
$ $ # " #
+
' " ��
+
+
+
- $
" # ! & ( - ) $
' % ��������
����
'
+
! �� ���� ������
+
+ ��������������������
+ �������������� ��������
�� ��������
������ ������������ ������������������
+
+
% %
' - 1 / -
% 3 '
+
+ ������
+ ' " " " " # # ! % / ' #
% * $ " !
+
- #
* ' " &
- #
!
#
+
+
+
" $ )
% #
#
!
����
+ ��
+ ������������ ������������
����
��
�������������� �� ���������� �� ������������
+
+
������ �� �� ���� ��
+ ������
�� �������������� �������������� ������
+
+
+
+
������ ����������������������������������
!
! * "
!
+
������
+ 0 5 9 8 $
# ! # ' $ &
" & ) * : , !
��������
- -
" % % + 6 6 9 8 : 5 4 7 > 7 1 + + 0 0 - * "
! ��
+
# $
" &
! 7 , " # 2 - ' #
+
( "
! &
*
+
$
& *
#
$ % ( % $
'
����
+
��������
&
! $
! ���������� �� �� ���� ��
+ �� ����
+
+
+
������������������ ������������������������
�� ���� ������ �������������� ������������������
#
����
$ * + / )
!
#
, 6 &
�������� ����
( !
& ' & ( ) ( * + 3 * & ! # , , ) " %
1
- ( #
+
+
* !
%
!
) & $
"
����
+
����������
$
!
������������ �� �� ���� �� ���� ��
������ ��
+
+
������������������ ������������ ��
+
+ ������������ ������������������
#
" !
" . & !
&
����
) / 5 : 6 " !
" ' # '
" & ' ) 8 , $
+
������
0 1 & $ # + 5 5 7 7 8 4 5 5 < 5 0 * + 1 / + ' !
����
!
" 4 '
! " / , & !
* #
!
(
+
+ # !
) *
" "
# # ' & & " * $
!
+
��������
+
+ #
" % "
% % ��������
����
��
����
+
�� �������������� ������������ ����
+ ������������ ������������������
!
! ) #
#
# $
+ & . 2 6 2
" " $
" $ $ + : , %
������
- +
!
# - - 0 . 0 . . 0 9 1 - & & / 0 , )
!
0 #
- ) # $
+
+ "
"
&
+
#
) )
$ !
!
! %
����
+
��������
+
&
!
# $ ��������
����
+
�� ����
+
+
+
+
��
�� ������������
���������� ��
+
������������
����������������
* ! $
+ ! ( )
& , 1 5 1
! " # # + 9 , " ����
, +
" ' ) * ( ) ( ) - 3 0 ) # $ . 1 + ) $ &
-
) & " %
. %
! !
(
+
+ % # !
, + ' $
!
$
" # !
( "
+
��������
+
+
'
# #
% ' ������
+
+ ����
����
+
�� �� �������� ���������������������� ������������ ��
����
+ ���� ������������
������������������
!
) !
$
+
+
# $ ��
% , 0 4 /
! % 2 $
��
+
������
/ , #
" , - . , 0 , , - 3 , ' ( ' " !
+
����
.
) #
+ ! - #
#
"
' (
#
&
������
+
+ ��������
+
(
!
# $ ��������
+ �� ���� ��������
+ ������
!
+
�� ��
�� ������������ ���������� ��
+
+
+
+
������ ��������
+
$
!
# , $ " !
'
% * ,
+
+
, 2 6 : 5 $
#
$ $ & $ ' ' + < . %
+
��
! # 4 2 % ' * $ ) 0 / 1 . / - , , 5 0 * # # - / + ) # %
"
!
+ 3 '
" 0 . ( * "
# * 7 , ' $
& "
.
$ - ( $ & # 1 0 % , ) !
! $ !
) !
! # & & ' # - ! & "
" #
!
+
+
+
+ ��������
! ! 1 &
! $ ' & "
+ .
��
��
! ( �� ���� �� ���������� �������������� ���������� ��
���� ����
+
��������
%
) # !
'
# ( +
! * - 1 -
% 3 $
+ ����
1 1 ! ' %
" ( % ( & * ' & $ - ' #
% ( % !
+
�� )
' & # $
# 1 ( $
+
,
" !
' % !
! ! # ! *
"
������
+
��������
+
, "
&
* . #
+
+ ��
+
������
+
����
$
�� ���� ��������
�������������� ���� ����������
��������
��
+
����
+
+
+
+
������
��
������������ �������� ������������������ ��
+ �������� �� ��
+
��
+ '
+
$
+ ��
��
+
��
+
+
��
��
! $
+ ��������
+ ��
���������� ������
���� �������� �������������������������������� �������������������������������������������������������������� ���������������� ��������
+ ��������������������������������
������������ ������ ����������
���� ��
+ ������ ����
+ �� ����
+ ��������
+
+ ��
+
�� ����
����
��
+
�� ��
���� ��������
+
+
���������� �� ��
+
+
����
+
����
��
+ �� ���� ����
�������� ������
+
����
���� ����
��
+
���� ����
+
+
+
+ ����
+
+
����
+
�� # $ ���� ��
+ ��
�� ��
+
+
+
��
+
+ ��
+ ��������
+ ���� �� �� ��
��
+
���������������������������� �������������������������������������� ��������������
�� �������� �� �� ��
����
+ ��������
������ �� �� ��
�� ����
" ������
������������������
�������� ���� �� �� ��
+
���� �� ������������
+ ���������� ���� ����
+
�������� ��������
+
������ ���� �� ��
��
��
+ ��
��
!
!
����
"
��
&
����
+ ��
����
+
+
+
+ ������������ �������������� �������������������������� ���������� ������������
�������������� ����
����
����
+
��
+
+
��
"
+
+
+
���� ������
������
+
+
!
��
+
+
+
�� $
+
+
+
+
+
"
+
$ ' " ' ' * % ( ( #
$ % !
) %
" !
# " 2 (
+
' ,
+
+
' "
# ) ������������ ������������
������������ ���� ����������
+ ����
+
���������� ���� ��
����
+
+
+
+
$ #
��
" " % "
+
��������
+
+
����
"
+
+
����
+ �� &
+ !
# ��
+
��
"
+
��
+
+
����
# "
+
��
+
+ ��
+
��
����������
��
+
�� ���� ����������
+ ����������������
����������
+ ��
+
+ ����
������
+
! ��������
��
+ ��
�� "
+ �� ������������
������
������ ����
+ ��
����
�� ��
+
+ #
����
+
����
+
!
+
+
(
# "
��
"
" ! ����
+ !
+
" ��
+
+ # ����
��
������������
������
!
��
����
+ " ����������������������������
������������������������
+ ���������� ����������
������ �������� �� �������� ������
�������� ��
+
+
+ �� ����
��
��
+ ! # !
+
������������
+
+
����
+
%
"
+
+
+
��
+
+ �� !
+
% !
+ "
+ ��
+ ��
+
$
+
+
! "
# #
+
% '
+
+
+
"
+
������
+
" ! ��
+
������ �� �������������� ������
�� �������������� ��
��������������
����
��������������
! �� & ��
! ��
����#
�� )
�� �� ( * ' ( )
���� -
����
�������� �� * * $
& ����" 7 0
�� ������
+ ������ ����
�� $ �� �� ! /
����
+
+
) ,
+
������ 0 $
������ ��* * $
+ ����
+ ���� #
���� + 3 ' ,
+ ( . ' )
��
+ " & & " * $ ����������) "
" $
�� + %
����
% + ,
+ �� ���� &
��
������
��
# # & ����
��������������������������������
��������������������
���������� ������ �� �������� �� �������� �������� ����������
��
+
+
+ ! ���� # ' ) ' #
+
������������
����
+
%
%
+
��
+ *
' #
'
$
&
+
$
" "
#
+
+ # !
+
+
+
+ �������� ����
+
+ ! ��
+
�������� ������������ �� �������������������������� ������������ �������� ���� ������ ���� ������������ ������
������ ��
��
+
+
# ����
" * ����
* - !
+
+ ' ������������
+ ����
#
!
+
��
����
����
+ ������ &
#
'
��
!
��
+
+
+
/ ��
+
/ # # )
' + # & & ( # ' ' $ ! " $
, +
' #
# ' 2
+
+
��������
+ ��
+
)
&
! �������� ������������ �� ������������������������
+ �������������� ���� �� �� �������� ���� �������� �� ������
����������
+ ��
+
+ $ ��
$ - / * %
������
+
����
+
( $ " ' ! # & # % & - % !
! $ !
$
!
2 (
! / * & /
* $
"
#
#
/ ! #
) "
#
" + ) + + ) $ + " ) " !
!
$ - +
+
+
, &
! /
$
+
������
+
! " % ! $ . %
+
$ ������������
������������ " ��
+
��������
������������
������ !
����
+ ���� ! &
"
) �� %
! % & '
, 3 * ! ! * & ! $ 1 - # (
' ' % & % >
#
���� F : ' + $ . ) , % " * 2 " ' = I 6
! 1 + - # ( ' $ ! ' ) " ����" = 4 % !
& 6 =
$
' ) 4 , + , / , + + ( * < 7 ) ( ! �� : T N K B < ? G ; 4 + 5 > : 1 '
2 4 4 A 5 ' & 0 * " " ) * #
$ ���� 1 8 + 2 1 4 4 ! ) & $ 2 G :
. 8 3 ; B B B < 3 % - J ) ) G
% % , 6 8 F ; 7 5 $
" : 2 , [...]
���� (
! �� * < , " " ( < % 0 ���� $
+
���� ���� !
# &
" % ��
" "
����������������������������������
���������������������� ���������������������������� �� �� ���������� ������ �������� �� ������ ��������
+
!
+
" !
$ * , , *
+ ��
+
��
& # " ( ( ) , ) ' ( / & #
" &
+ "
+
+
+ , !
* & # ,
+ ' "
(
+
+
* ( ) ( & ! &
$
# ( %
( $
+
'
! %
��������
' ��
+
+
+ �� ���� ����������
+ ���������������������� �������������� ��������
��
+ ����������
������ ������ ��������
( "
$ !
( 0 3 3 .
'
+ ����
) %
) - / - 0 , * , 4 ) ' " ' ) %
$
!
4 &
# 1 , ) 0
! 1 * "
& "
$ ! "
$
! ! -
# &
) + !
) $
!
* * , * + ' + " ) % "
! " $ # $
* $ ��
'
$
��������
����
" $ ! ,
���������������������������� ������������������������������������������������������
������ �������������������� �������� ������ ��������
+
!
+
+ ��
"
��
+
& ' + )
+
�� ��������
+
����
+
! ' ) ( ' " " " +
+
+ ��
��
�� %
+ %
# ��
+
+
+ �� ��
+ % ' # & %
# % "
��
"
�� ��
+
+
+
# #
+
��������
����
! & ��
+
+
������������ ��������
+
������ �������������� ��������������
+ ��������
�������������� �� ������
+
����
��������
+
+ ) " !
+ ��
+
$ * % #
' / 2 4 0
!
! )
$
# . / / . + & $ 1 ' ' " ) $ &
+
��
+
+
+ �� )
, "
* �� % !
! ��
"
! #
+
' / $ + ' # - % - $
) $ # ����
! ( % ��
% !
- + ! " % ) & "
, 0
��
#
��
& ������������ ���������� ���������������� ���������� �� ������ ���� ����������
��
+ ��������
$
$ &
! & , 3 +
" 0 "
����
0 - ! $ # & ) % ' & ) ( & % . ' #
* - * %
$
!
2 &
- ( %
*
! ' 2 ) " !
! "
+
$
+ ���� !
' % "
%
��������
+ ��������
!
+
+
$ ( ��
����
+
+ ������
+
������
!
�� ������ ���������� �� ����������
�������� ��
������
��
������ " ! * ! ( !
& ' -
+ ! ( * 3 *
% 3
��
2 , # $
# % ) # % & ) ' "
$ ( " !
+ �� *
+
+ ( # '
1 ( % $
+
+
! ��
% !
! & "
! " $ $ # -
$ & $
������
+
������
$ - # $
! $
0 9 &
+
+
��
��������
+ ����
(
+
+ �� " #
��������
) &
" # $ ! ( # # ( ) * & "
% 7 " #
& *
) # + 3
&
+ * & # ! ,
" - + 7 /
, / / 2 ) ! " " " % * & $ ' & , 7 * (
!
" & ) ) A 9 , . % & - 5 8 < ? > 6 8 : A 9 5 0 / 8 > 9 5 * ! - " ! %
! # " $ * ; 0 &
( / $
. @ + ! ' & 7 9 , $
3 $ !
& " ) * $ # [...]
+
������ �� ��
&
! #
���������� �������������������������������������������� �������������� �� ������ �� �������� �������� ���������� $ ������
��
�� �� ����
+ ����
+
��
����
+
#
!
����
! ,
+
+
% 0 + " # 0
��
+
2 - ! $ ' $
! ! ! ( "
!
��
��
+ '
+
+ &
(
$ " %
$
# ' $ ������
# "
% $
# ) $ - ! % " �� ������
������ ��
+
!
(
% - !
��
+
����
������
! ��
(
+
������
+
+
+ ������ !
+ ������
��
+
���� �� ����
+
+ ��
+ ����
& , (
+
) 2 .
+ # " 0 $
+ ��
- )
" #
$ ! % & #
+
)
+
+ % !
'
+
+
&
�� ��
+ # #
% * "
+
# '
!
������
+ ��������
+ %
- #
+
+
���� ��
+
' ����
���� ��
��
+
) ���������� B ! ��������
����
������
. ��
& '
(
!
*
!
!
' < 0
��
& + +
'
! $ , # ) "
+
$ $
+
+
, $ %
, %
'
! " ( $
) = & % ����
/
���� $ !
" 5 :
1 > !
+ & + # &
! < +
" & & ��
, !
/ 2 ��( "
��
( *
# $ # ' .
* + *
"
" * 3 ��������
+ #
+
%
# !
' ' & % 8 6 0
! . F 3 % �� ��
+
����
�� %
+ ! & % +
+
+
+ ������
������ ��������
+
+ ��
+
+ �� ����
! #
& - -
( . *
$ / "
��
+ - )
% !
# ' !
+ )
) '
&
# + "
' ��
$ $
$ ) $
!
$
+ ������
+
��������
+
+ ( "
+
% %
+ ����
��
$ �������� ������������
����������������
# �������� ������ �� ������������������ �� ����
���� �� ��
���������� ��
+
����
���� !
����
+ ����
+ ���� % #
+ ��
)
+ ��
+ ��
+ ��
��������
�� �� * (
��
+
���������� �� ��
������������
&
+
��
���� ! ��
�� ����
!
������������ " ' �� *
& #
+ �� & - # )
+ �� �� �������� ��������
+
!
��������
��
+
���� ��
+ ����
&
+ ��
��������
+ ������ ��
�� �� ��
�� �� " %
+
+ ������
����
% ������
��
�� ��
+
��
& " !
"
+ % ' - / ��
% ' . +
(
% 0 #
$ * ��
+
+ . * !
(
. )
' "
! $
��
��
+
) !
+
+ %
' #
" 1 ) "
*
! (
% $ ! / " $ ' "
.
! ! (
-
����
+
+
+ "
������
+
$ / ��
. %
" ( �� ' /
& ��
+ !
( / ����
% �������� ������������
���� ����
���������� # ��������
+
��
+
����������
+
��
+
+
����������
+
+
������
�� �� ����������
+
+ ���� ������ ���� ���� ����
& $ ( $ #
���� �� ��
������ ������ ���� ��
��
����������
& ��������
% ������
����
�� ����
��
" �� ����
+
����
��
+
�������������� ������
�� ������
����
�� ��
�� ����
+ ������ ��
����
+ ���� �� ����������
+
����
+ ���� ����
!
+
����
+
+
$
����
+
+
+
+
#
! "
+
( , 2 &
+
& ) ' ,
+
% �� * (
"
#
��
(
, ' &
+
(
#
# * & !
������
+
+ ��������
+ ) #
"
+
&
��
����
+
����
+ �� * ��
+ ��
����
+ �� ���� (
$
"
���� ' "
% & + . !
��
! # * ,
�� % " * 4 !
��
0 +
" �� ' & & ) # !
+
������������
������
' "
$ !
��
���� % %
��
# %
# " ( * '
+ # + !
������
��
# ! ������
����
! " - % ��
& "
��
����
# &
+
������
+
% ��
+
+
+
����
+ #
" & "
+ ' )
+
" %
*
$ .
+ / (
! !
����
+ ����
+ )
+
+
+
, & *
%
����
/
& - " %
+
" "
+
������
���� $
��������
!
* "
"
��
+ ��
! �������� �� ����
+ �������� �� �� ����������
+
��
��
+
+
+
# '
)
"
* '
"
+
��������
������
&
+
+
+
��
" % " # ) " !
# ��
. $
% %
+
+ ��
��
+
$ ��������
+ ��
+
������
+
+ ��
+
+ $
+
" #
$
" , ,
!
! / "
# )
3 - ! ! # ) & # " % " # #
!
+
��
�� $
+ ( " '
+ $
+
"
"
& %
!
#
!
( - , ' % ! - ' % )
#
��
* '
+
( # # & $
" & ) 3 , ! !
+ -
!
+
+
" # + ������ ��������
�������� ��
��������
��
+ �� ����
+
��
+
+
������
+
! "
+
+
# )
+
1 ,
! & #
" " "
+
����
�� "
%
+
"
+
��
+ !
����
+
+
# ���� ��
"
) "
# $
+
+
+ "
�� �� ������
������
��
+ ����
+ ��
+ ��
+
$
% &
# ) * ( )
+
&
��
+ ��
+
+
+
+
+
'
+
+ #
+ "
+
+
+
+
+
��
+ ��
������ ��
��������
�� ��
+ �������� �� �� ����������
����
+ �� ����������
+ ����
������
+ �� ���� ������
+
+
������
��
����
+
��
����
+
+
"
+
+ $ "
% & & $ !
+
����
+ ����
+ #
+
+
��
��
$
+
+ "
$ ��
+
+
+
+ ��
+
����
�� ��
��
����
+
+
��
���� ��
����
+
��
+ ��
+ ��
+
������
��
+
+
����
+
+ ��
! &
% * - "
+
! * . / 0 -
)
+
��
��
+
$
+
!
*
+
( $ %
+
+ %
+
&
+
! "
+
+ ��
��������
+
+ �� �� �������� �� ��������
+ �� ���������� ��
������
+
+
�� �� ������
+
+
+ ������
��
+
����
+
����
+
��
������
$
+
+
+
% &
% ( + + '
+
"
����
+ ����
%
+
(
% !
%
+ !
+
+
# ��
+
+
+ ����
�������� �� �� ������
+
+
+
+
+ ����������
+ ����
������
+
�� �� ������
������
��
+ ������
����
��
������
#
%
" ) +
) , / . ,
& ��
+ ����
+ %
+ "
!
+
,
( ( ! &
&
+
&
" $
+ ����
�������� �� ������
��
+ ������������
����
����
+
+
�� ���� ������
������������ ��
��������
+
����
+
��������
+
+ ������
+ ��
������
"
+
% $
$ ( + ( &
������
����
'
+
+
,
+
' !
'
+
$
+
+
#
+
+
��
!
���� ��
+ �� ��
+ ��
+
�� ����������
����
����
+ �� ��
+
+ �� ������
��
����
��
��
������ $ '
% , . !
" * 0 2 3 -
! *
��
����
+
+ ' "
"
!
#
- #
+ ) # (
+
* #
*
+
$ & #
+
������
+
���������� ���� ��
����
+
����������
����
��
��
+
������ ���� ��������
�������������������� ���������� ������ �� ��������
+ ������ �������� ����������
$
% % ��
) - 0 - *
+
#
������
������ ��
'
$
+
. !
) % # )
&
'
! $ "
+
+
+
����
+
�������� ������ ����
+
+ ��
+
+
���� ������������ ���� �� ���� �� ������
�������� �� �� ��
+ �� ������ ���� �������� ������������ ���� ����������
������ �������� ����������
"
+
+
& *
% * , + )
+
+
)
������ ��
#
!
!
+
+
+
( !
) & # &
( !
+
" +
%
+ - !
) &
# !
" &
! ! $
��
�������� ��
��������
+
+ ��
+
+
+
������ ��
+
+ �� ������ ����������
+ ���� ����
������
+
������ ��������
+ %
$
+
+
+
& '
+ 0 1 2 0
)
+
+
+ ����
+
* %
!
) "
# #
#
1 (
. , & )
+ #
!
!
*
" % )
$ !
!
�� ��������
+
��
+ �� ������������
+ ����
�� ��
+
+
�� ���� ������������
��������������������
���������� ������ ���� ���������� �� �������� �������� ��������������
+
+
+
+
+
+
+ ������
% * - , )
+
!
+ �� ������
������
+
& "
( !
, !
) & # )
% !
(
+ # #
! " "
!
+
!
��
+
�� ������������
���� �� ����
+
+
+
+
+
��
��
+ ������ $ ��������������������
����������
�������� ! ��������
������ ��������
������������
# $
" - % " $ $ . "
! ) 1 2 & !
! $ " ' - 6 : = = < )
# # $ ( % ) $ ' ' - 9 + $
�� ! !
������
�� " 5 1 ! " " % + , + * * & ( , 5 - ( $ & - . + * %
" ! . # #
+ $ ' !
!
' &
"
" '
' ; 0 & !
& + 7 5 1 $
2
! ( 5 . % #
% ) ' $ % & ! & , % ! ' ! "
$ # % % 2 ! $ * % #
$ - 1 % " . * $ ! $ & #
% ) # $ % % # $ ( ) ) & $ ! (
"
$ " # # # ������
���� �� #
���������������������������� ������ ��������
%
����
!
������
+
�������������� �� ��������
+ �� ������������ % ������
+ �������� �� ������
��������������������
���������� ������
�� ������
+ ������ ���������� ������������
"
!
! " ������
* / 2 3 0
& ��
+
������
( & " % # " # ! " # , $ !
! "
/ ' , * & (
+
) !
+
" $ &
% !
"
# " # "
�������� �� ��
+
+ �� ������������ �� ���� �� ��
+
+
���������������������������� ������������������������������������������������������������ ������������������������������������������������������������ ���������������������� ������ ������ ��
+ ���� �������������������������� �������� " " $
+
�������������� �� ����������������
+
!
�� ��������
+
�� !
!
���� ����
+
��������
+
+ ������
+ ����������������������������
+ ������ ���������� ����
+
+ ������ �������������� ��������������������������������
+
������ �� �� ��
�������� �� ��
��������������������
���������� ������
����
������ ������������
��������������
& #
+
# ! ! / 6 7 9 6
!
# / ! ������
. +
" ( , / , + * ) + 4 , ' ! " ) ' # !
"
+ ! !
#
! 5 *
" / + ) )
, %
% !
! ! (
%
! .
$
' +
( $
$
& $ $ $ "
% !
+
��������
+
������������ �� ����
+ ��
��
+
+
�� ���� ������
���������������������� �������������� ��������
�� ��������
+
+
������ ��������������
��������������
" !
+
+
+
������
) 0 1 3 0
% ��
+ ������
+
+ * '
& ( ( ( * % & ' / ' "
# !
1 '
, ) $ )
+ ) #
!
# "
*
+
!
$ '
& "
!
& & ' & # & "
! #
+
+
�� �� ��
+
+ ������������ �� ���� �� " ��
��
��
+ ���������������� ���������� ��������
���� �� ����
������
+
+ ������������
��������������
+
"
+
+ # $
" ( + - ,
+
% 5 %
������
& "
# + ' !
' * % #
$
+ ��
+ (
+
& % $
+
* "
&
"
% &
!
+ ���� �������� ��
��������
���� �� ����������
������
+
��
+ ������
+
�� �� ������������ ���������� ��
+
+
������ ��������
&
" ! & ( # ' , 1 ,
' 5 (
+ ����
+ '
! ! ! * & !
' * & $
#
(
+
( % %
" - %
& ��
!
( & #
+
"
+ ������
��������
+
+ #
$ $ ��
+ ����
+
������
������
�� �� ������
+
���� ������������ ���������� ������������
������ ����������
+
������ ������������
��������������
+
+
+
+
+
+ ! #
+
" ' ' ' %
+
,
��
������ ����
+
!
+
�� "
+
#
$
+
�� ��
+
+
�������� ���������� ������������������������������ ������ ����������
����
���� �������������� ������������ �� ������������
+
������
+
+ ������
��
+ �� ������ ����
+ ���������� ����
��
+ �� ��
+ ��������
$
! % * +
+
+
$ ) / 2 .
! ( 6 '
����
* '
* %
& , ' %
(
+
+ !
, ' " )
% / & " "
'
+
$
( )
' $
!
����
+
��������
+
��
+ # $ ������
��
+
+
+ �� ��
+
�� �� ��������
�������� ������
+
$ % # !
$
$ �������� $ "
��
0 6 4
+
+
+ & % / -
! (
# $ " - -
+
����
( ( " + $
" # % "
+
%
+
9 - "
* '
( * , "
+
! *
% %
+ �� ( , ! - 6 % $ 0
+
&
��������
��
+ ��������
+
�� "
1 -
+
+
�� %
$ % ��
��
�� ������ ��
�������� ������
����
��
�� ��������
$ * ,
+
& ) - . *
$ / #
����
+
( " $
$ $ "
$
+
*
+
( % (
" ,
%
+ $ # "
+
��������
�� ����
������������ ��������
+ ������
+
+
+
��������
+
����
+ ������
������
+
������
+
������
+
�� ������
��������
��
+
+
��
+ ��
+
��������
#
$ + -
" % , 0 -
$ 1 #
�� * '
% !
$ ' #
#
+
+
*
+
* & '
# . #
#
&
+ #
' ( #
+
"
������
��������
+
+ ��
!
% %
+
��
��
��
+
+
������
+
+
��
+ ����
��
������
# $
! ' 0 / $
* - 1 3 -
% 1 #
��
) $
%
$ % " ! $
- #
, ) %
( " - %
+
+
"
% ' $ !
+
+
����
+
��������
+
������
+
��������
+
+
��
+
+ �� ��
+ �� ������
+
��
����
+
��
��������
"
& , . "
# ( , / *
+
$ 0 "
��
+ ) % $ # ' # " #
*
* ' # )
# - #
' ��
"
% ( "
+
+
+
������ ��������
+ �� !
+
����
+
+
��
+
+
������
+ ��
���� "
������
% )
# * 2 4 '
"
! & / 3 7 6 2
% 0 #
+
��
+ * % #
$ % !
'
! #
% !
$
+ 2 &
! 0 - '
, # . '
" !
"
! $ " 0
&
) )
& $
$
�������� ��
��������
+
+ ������
��������
+
+
��
+
+
+ ��
����
��
����
+
������
% ) / "
+
& * - + )
-
+
��
" "
#
$
+
* # &
+ !
)
" % !
+
+
+
��������
��������
+ ��
������
+
����
+
����
��
+
+
������
��
+
+
+
��
+
����
# !
+
' / 1 #
" $ * , (
# .
" ��
+
+ * '
#
! $ !
+
(
, ( ! % ! , !
'
+
+ "
$ ) $
+
������
��������
+
+
'
"
" ��
+
��
+
+
+
+
����
+
+
����
! %
+
! ' . / $
) - . . ,
+ ! ,
��
%
+
#
*
+ & " &
(
+
*
! $
+
��������
+ �� ��
��������
+
+
������
+
+
+
��������
������
+
+
+
����
+
+
+
+
��
+
! $
+
' . 1 %
# ' * * (
! ,
+
+
��
+ ( #
#
)
+ ( ! '
+ #
*
" ' !
+
+
��������
+
��������
+
���� !
+
+
������
+
+
+
+
����
��
+
����
+
+
����
+
+
+
+
+
+
+ ��
$
+
+
& , - "
# ' ( & &
'
" ��
+ # !
+
(
' $
%
+
(
+
(
$
+
��������
�� ���� ��������
+
������
������
+
��
��
+
����
+
��
"
+
& + . "
# $ # #
+
'
+
+
+ $ ��
& '
"
+
'
* & ! %
+
+
! " )
"
+
��������
��������
+ "
������
" ��
+
+ ���������������������������� ���������������� ���� ����������
������ �� �������������� �������� �������� ����������������
�� ������������������ ���� �������� ���������������� �������� ���������������� ������ �������������������������� �������������������� ������ ����������������������������
+ ������������ ������������ �������������������������������� ������������������������ ������������ ������������ ���������������� �������� ���������������������������� �������������� ������������ ������������������ �� ���������� �� �� �� ���������� ���������� ����
�� ��
����������
+
�������� �������� ������ �� ��
��
+ ���� ��
�� ��������
������������ ���� ���������������� ������ ������ �������������� ��
+ �������������� ���������������� �� ���� ���� ���������� ������
�������� ����
+ ���� �� ��
���� ��
+
���� �� ��
+ ���� ������ ����
�� ��
���� ��
�������������� ������ �� �� ���� ����
+
+ ���� ����
������
������ ����
����������
+ ����
��������
����
���� ����
+
+ ������ ����
���� ��
����
+
+ ��
��
��������
+
+ ���������� ��������
������ ������
+ ���� ������ �������� ����������
�������� ����������������
+
���������� ������ ���� ��
+ ������ �������� �������� ���������� ��������
������ ����
+ ���� �� ������
+
������ ���� �� ����
+
����
��
�� �� �� �� ���� ����
+
����
������
+
����
������
+ ������������
+ ���� �������� '
$ ��������
��
+
+ ��
+ ��
+ ����
��
������
������ *
+
+
����
+
+ "
��
"
+
+
+
��
+
������
+
+
��
�� %
�� �� ������
+ ������
�� ��
+
������
����
!
+
+
+
!
! $ "
+
+ # ����
��
+
+
����
+
!
" ����
��
��
��
+
+
+
��
+
������
+ ��
+ ��������
�������� �� ���� ���������� ���� �� �� ����������
��
+
����
�� ����
+ ��������������
��
��������
�� ��
������
������
��������
+
+
+ ������
+
+ ��
��
��
+
��
+
+
+ ! �������������� ���� ���� �� ��
+ ��������
+ ����������
+
��
�� ��
��������
������
���� ����
����
������
+
+ ��
+
+
+ ������
+ ������ �� �������� �� ��
�������� ������
+ �� ���������� ���� ������ ����������
+
��
�� �� ������
+
������ ����
�� ������
+ !
������
+ ��
+
��
#
+
$ %
! % & % %
+
+
&
+ �� ! ��
+
+
$
"
+
+
+
+
+
+
��
+
+
+
��
+
������ ����������
+ �������� ���������� �������� �� ������������
����
�� ����������
��
+
������
+
�� ���� ������������
���� �� ����
�������� ������������
������ ���������� �������� ��������
+ ������������
+ �������� �� ���� �������� �� ������
+ ������
��
���� ������ ������ ���� �� ������ ��������
+
����
+ �� �� �� ���������� ������ ��������
������ ������ ���� �� ���������� �� ������
+ ���� ���������� ���� �������������������������� �� ���������� ����������������
�������������������������� ����������������������������
������������������ ��������������
+
�������������� ������������ ����������������
����������������������������
��������
+ ����
+
+
+
+
+
����
+
+ ��
����
+ $
$ * +
+
' + , , )
)
+ �� ! ��
+ #
+
+
+
+
%
& #
$
"
+
$ ��
��
+
+ ������ ������
���������� ���������� ������������ �� ����������
+
+
+
�� ����������
��
+
������
+
+
���� �� ������
+
����
+
+
������
+
+
+
+
+
!
+ ��
"
��
+
+
+
+
+
+ !
"
+
+
+ ��
+
��
+
+
+ ������
�������� ����������
+ ���������� �������� ����������
+
+ �� ����������
+ ����
+ �� ����������
+
+
��
+
+
��
����
+
+
+
����
+
+
����
+ #
& & ! % $ $ $
$
+ ��
" ��
+
+
+
+
$
#
#
+
#
+
! ��
+
+
+
����
+
������ �������� ���������� ���������� ������������
+ ����������
+
�� ����������
+
��
������
+
+
+ ��
+
����
+
+
����
+
+
+ ��
+
+
+
+
+
!
% "
+
+
��
+
����
+ # ��
+
+
��
+
+ !
!
!
+
+
����
������ �� ����������
+ ��������
����������
+ ����������
+ �� ��������
+
�� ��
��
+
������
+
+
+
+
����
+
+
+
+
#
+
+ ! ' (
+
# ! !
+
+
#
" ��
"
+
+ "
& ! #
+
*
)
+ " '
+
+
+
+
+
+
�������� �� ��������
+
+
+
+
������
+
������
+
����
��
��
��
������
&
+ ��
+
��
���� ��
�� 0 "
��
+
+ 3 % ����
+
+
�� ��
����
+ / ���� 5 �� ����
'
%
��
������ ����
���� , ( 3
��
8 !
��
*
��
+
������ �� ����
����������
+
%
+
������ ����
+
+ ������
����
+ ����
+
����
��
+
����
+
!
+
+
+
! #
" ��
& + &
+ �� ' "
%
*
+
! 4 $
%
# !
+ ����
+
+ &
+ + ' #
'
" ,
# % 5 $
+
" + $
������
+
+
+
������ ' ��
+ %
) # !
��
��
���� ��
+ . $ ������
����
��
"
+
" % ! ��
+
+ " 1 &
+
$ &
) . "
+
!
+
# #
����
+ ����
'
���� # ����
*
- ��
+ *
"
��
# $ ( " !
+ &
+ ��
+ ����
��
+
!
�� %
����
! ��
����
��
����
( 2
����
+
����
+
�� ��
%
+
#
+ ��
+
+
(
! )
+ ' #
����
��
+
+
�� "
( !
+
+ # "
+
+
#
#
+
��
��
����
+
"
' !
+
+
+
+ �������� ������������������ ��������������������������
+ ���������� ��������������
�� ���������� ������
+ �� ��
+ ��������
+
����
�� ���� ������
������
+ �� ��������
+
�� �������������� ����������
���������������� ���� ���������������������������� ���������� ��
�������������� ��������
+ �������� ��������
+ ���� ��
�������� ���������� �� ���� ��
����
+ ���� ��
������
+
+
+
+
+
+
+
������
+ "
��
+
+
������
����������
+
���� ����������������
+ ������ ��
+
���������������������������� ���������������������������� ������������ ����������������
+ �������� �������� ������ ���������������������� ������������ ��������
+ ���� ��������������
+ ���� ���������� ��������������
���������������������������� �� �������������� ���� ���� �������������������������������������������� ��������������
�������������������������� ������������ ������������ ���� �� ���������� ����������
+ ������ �������� ������ ���� ���� ������������ ���������� �� ���������� �������� ���� �������� ���� ���� �� ��
���� ������������
+
+
��
���� ��
���� ���������� �� ����
+
�� �� ��
�� ������������
+ ������
�������� ���������� ������
+
������ ������ ��������
���� ������
����
������ ����������
������ ���� �� ����
��
+ ����
������
��
+
��
���� ��
����
+
��
+ ��
+ ��
��
+
��������
+ ��
��������
����
��
+
����
+
��
��
+
# �� '
��
+
������
�� &
��
��
��
+
����
%
��
" ������
�� $
+
+ ���� (
+
"
������������ ������������ �������������� ���� ������������ ���������� �� ��������
������������ �� �� �� �� �������� ������
�������� �� ������ ������ �� ��������
+ �� �� ���������� ��
������ �������������� ������������������������������������������������������������
�������������������������������������������� ����
+ �������� �������� ������
������
��������
+
���� ���� �� ��
��������
+ �� ���� �� �� ����
������
+ ������
+
+
��
��
+
+
��
��
������
+
����������
+ ���������������� ���������� ���� �� ��������������
����
������ ������ ���� �� ���������� ������
+ ������������ ������
+ �������� �� �� ������
+ ������ ����
������ ���� ������������
������ ������������
+ �� ��
������������ ������ ���� �� ����
��������
���������� ������������ ��
�� �������� ���� ����
���� �������� ������������
������ !
�������� �� �������� �� ���������� ������������ �������� ������������ ������������
���������� ���������������� ������������
+ ������ �� �������������������������������� ���������� ��������������
������������������������ ���� ���� ���������������� ����
���������������� �������������� �������� �� �������� ���� ������������������ ���� ������ ������������������������ ����
+ �� ������ ��
���� ���� ��
+
��
+ ������
��
+ �� ����
+ �� ��
+
+ �� ������
��
����
+
+ �� ��
+ ����
+ �� ��
���� ��
+
+
��
����
���� ���� �� ��
+ ��
��
����
��������
���� ��
��
��
��������
��������
+
+ ��
+
# &
��
+
'
+ #
��
����
+
+
����
+ ��
+
+
�� ����������������������������
+ ���������� ���� ����
������������ ��������������
������ ������
+ ������ ���� ��������
����
+
��
����
��
�� ��
+ ��
�������� ��
+ ���� ������ �������������� �� �� ���������� ������������ ������ �� �������� ��
������������ ������
��������
+ �������� ��������������
+ ������ ���������������� �������� �������������������������������� ��������������������������
������������ ����������
+
+ ���������������������� ���������������������������������� ������������������������������������������������������������������ ������������������������������
+ ������������������������������ �������������������������������������� ������������������������������ ���������������������������� ������������������������������������ ������
+ ������
+
��
+
+
������
+
+
+
+
�� �� ��
+
+
+
��
+
+
+
+
+
����
+
����
+
+
!
������
+
+
+
+ ��
+
+
��
+
+
+
���� �������� ������ �� ����������
+ ���������� ����������
�������������� ���� �� �� ����������������
����
+ ����
���������� ������������
������
+ ������ �� �� ����
+
+
+
+
+
+ ��
+
+
+
+
+
+
+
+ #
+
+
+
+ !
+ (
+
+
+
+
+
+ ��
+
!
+
+
����
+
+
+
+
+
+
����
+ ��
+ �� ���� ������ �� ����
+ ���� �������� �� ���� �� ������ ��
�� ������ ����
+ ���������� ������������ �������� ������ ������������
+ ��������
������
+
+ �������� ��
+ ���� ����
����
���� �������� �� ����
+ �������� ����
���������� �� ������������ ��
���� ��������
+ �� ��
+
����
����
�� ����
+
+
����
��
����
�� ���� ������
����
����
+ ������ �� ����
+
�� ���� ��
���� ��
+
+ ����
��
+ ��
�� ��
��
��
+ ����
��
��������
��
+ ����
����
��
�� �� ������
+
+
��
��
+
���� ����
- �� ����
+
��
+
��
+
+ ���� ��
��
+ ���� ����
! ������
��
+
��
�� ��
�� ��
+
�� ����
+ ���� ���� ��
+ ������
������ �� ����������
����
������ ���������� ' )
��
��
������
+
�� ���� ������ )
+
������
+
��
+ �������� �� % ������
+
��
+ ��
+ ������ ����
����
+
����������
��
����
+ + ��
+ ��
$
+
*
+
+
+
+ & ����
"
# ! ����
!
*
$
+ ) % #
! ����
'
" % $
+
#
+ % ,
+
+ +
& (
$
+
%
! ) % &
+
+
+
"
# $ $ # $ ������
�� ��
����
+
+
+
+ ����
��
+ ��
����
% ����
+
����
������ �� ��
' # ����
��������
������ ! %
��
+
$ %
+ ' # ��
#
�� ��
+ ������ ��������
+ "
��
+
��
+ ( ' �� ( ����
+
+
����
����
& ! &
& #
�������� #
#
������ ���� & %
���� & ������
+ ������
+
+
������ #
�� ������
#
���� " ��
��
����
+ '
��
�� ! �� ��
+
+ ��
+
+
������
+
��
+
+
!
,
+
* 9 " ��
0 +
+ #
!
$
����
+
+
�� $
����
&
+
+
+
%
+
# . !
$
+
+
& #
+
* ! #
& '
+
& !
+
��
��
+ �� #
��
+
����
��
��������
' ����
+
��
# ! ����
+
"
!
���� $
)
" " !
&
7 2 &
' " " $ ' ) " $ ( !
+
+ ��
)
) ( % �� %
!
+
"
"
"
#
% ) "
$ ( & $ #
,
( $
�� # , #
#
(
�� $ '
. , !
+
+
+
*
! ) "
�� % $
+
#
+
$
+
+
$ # % " !
���� ����
+ ����
+
+
��
��
+
��
+
+
&
! '
+
0 ,
!
+ ����
��
��
"
+
+
+
��
+
������
���� ��
+
+
+ !
+
+
+
��
+
�� ��
����
+
+
��������
�� ��
������
��
��
��
!
����
+
+
+
!
+
��
+
��
������
+
+
������
��
+
+ �� �� ��
+
��
+
+
+
+
��
+
!
������
+ !
���� ��
+
+
+
�������� ���� �� ���� �� ���������� ����
+ ��������������
+ ���� ����
+
������
��
+ �� ��
���� ����
+
+
+ ��
! ������
������
+ ��
"
+
��
��
+
+
+ ������������ ������������������������
���������� ������������ ����������������
���� ������������ ����������
������
+ ���� �� ��������
+ ��
��
+
+
+
+
��������
+ �� ��
���������� ��
+ ���� ������������
�������� ������ ���������������� �� ���� ��������������
+
������������ ���������� ���������������������� ������������������������������
������������������ �� �� ����������
�������� ����������
+
+
+
��
+
$ % " ������
+ - ) (
(
��
+
" ����
+
+
+ - % ! # ' & & % # & & # - " "
�� ��
������ %
$
+
& !
+
+
+ ! ��
" !
+
+
+
# ) & ' ! + ! ( %
! $
����
) $
+
$ #
2 (
! !
$ (
+ ��������
��
�� �� ����
$ �������� ������������������ ���� �������� ������
����������
�������� ��������������
����
��
+
+
������
%
$
+ !
' 3
��
% ! "
+
,
+
+
2 )
( * $ % % & % % * # !
$ % !
+
+
��
��
+
�� �� #
+
+
%
)
�� ) &
+
+
+
+
) ( % "
' ' !
��������
( &
+
" 1 "
+
+ ) ( ��
����
+ �� ��
��
������ ��
' ! ����x�|����� F , 1 ��' ] Y , ����������������y�h�p������� /
* 0 2 1 = Q f _ 2 - 3 ��������( : �� 0 1 ; H D g & .
! A C G C C = J Z n R ! ������3 ; D . . P m n � y F O . '
��< � � � ^ K G V ~ j r a ; < I [ R ? 1 T e D A X k L V M 6 E � � r R ^ 7 @ C 8 5 I \ j A J X _ o X 1 + < B E v � � � W �� $ # E M D J ] T \ 8 # ���� % ( < < A G C
H [ g E V m " E W - / O E - / ) f \ E +
9 *
( 6 * : "
@ 8 L 1
? 6 ����% Q 4 5 / " ; . 8 / U 6 2 Y * 1 / 0 0 * Q M 6
? - : 1 , ' X ; - . / Q Z F U + 3 ����
7 ) 4 #
% 0 G <
0 X x { ] = �� U @ ���� < % ����"
! . ( , + + > > s h ������ 2 % ) [...]
$ ! . , - U T ] e �������������������� ��Q t F ����������������������k��������� ��
4 > N 1 �� ? H Z � ~ 7 ' 1 ��* K I ������H ` _ ; H 0 @ ) �� 2 ; d R c T c b j r � | O 8 �� B < S K T ] s v � � d t Y \ M C s z � � � o [ � � \ Z k v q p b E C A a w e \ j h N f P J d � � � c o R U \ V e � � w g V ] c c ] B 7 L W c � � � � v 7 8 2 8 / Z l v � ` V 0
�� & " 1 - E U d g a
[ n � k t � I P { u N D K ; $ 7 j o Y P = H B 8 Z ] S / & 8 ; V B @ @
[...]
��
6 B
+ $ I L e k Y c | v � � � X n � � \ Z U E * ? T d � P [ ^ * ��> /
? M ` g 3 . 1 ������* &
+ 7 @ < L L [ b [ @ ��
������������0 0 K H * , : G ^ f b V @ ������������������������4 A G W z � � y b ��������������s�a�v������� M > V O ������������ �� " 2 * 6 $ F ^ n � � { U ��������* ��
+ 1 7 A I q v � �
+ �������������������� % ��. T I ��������������������v�c���������
* / 4 # ��$ - A C \ V 6 + 3 �� % & ������ # ) M J N
! : B > 8 D N [ Z j h > ����
1 " * > T h m p t G Y / 3 # ) Y n k j W L I O c X k V T K b j C . % O G ? < ^ b C J . ) H p { p Y ] < C L 5 7 \ n k E H = N a M 1 ) M V b � � � � Y �� .
+ 8 Z j S F : �� # ' 8 B L P C
, : P m Q Y k ' $ P J + 9 I 1
, [ T 4 , + ) ) ( ? < P 6
1 ?
+ < # * ' 3 ,
* * ' I 8 : = P 0 + " 2 . ' % H O ? ( $ ' : #
Q 6
# ( T X : L B 7 ���� ? + 1
% & B E 0 # �� * T h s ^ B ��
G 8 ' ��0 & $ �� . + 3 7 5 $
, 8 } ` �� ( F % % 1 7 P [ S [ o o | � � E T m Y A K I M ( : R S Z g J ? P ' �� 0 4 B F * $ . $ ��������
�� �� 9 0 9 = a ` S + ��
+ ���� ������+ ; C $ 6 ` i \ B / ������������������������ " ' 9 V � b S [ ����������������f�{���������2 ( : & ���������������� > ? + , 5 < ! ? _ n � � p N ��������
�� �� 4 & + 9 : c f x x +
����������������
. + ��> i ^ , ������������������z�r������� / . - : - ( < J P ] \ A 5 ; �� * /
����
7 - ? b W _ 6 * " 0 M C L K W [ d c t m B
����9 O B A L ] v � � � Z i @ G 9 > o � � � s e d o q ~ m n b x | c G A k i g c � d h Q L f � � � p z \ ` l N W u � ~ ^ _ W a x q Q F a s ~ � � � � q . # G < = , T u | p \ T # ) # . + , : @ V [ b ] W & / ? 6 R e � _ h ~ ? 7 ] ] D H Z H
4 G u m H A 1 : 6 ) , ; > C @ ) 4 R N g P [...]
+ " 3 M F L 4 4 8 4 9 0 Q U H < +
A q � � q X
��. [ V A
: 5 . > 6 3 G I F 2 4 B P v o $
"
8 T 2 5 G S j h a k � v � � � U b ~ l S b [ [ 5 H X X \ o V L ] 4 "
> = F R 3 * 1 . + , J B N K a [ Q 6
����0 - H J 6 , / F c f a M 5 ����������������������* 2 3 B ] � j b ^ ���� ����������l�}������� 1 & > % ������������ ? A 2 4 @ B % # C ] p � � h H �������� < = F L T w t � �
�"��
��
�
�$�'�-�&�$�(�)�
�� ��!���
�"�1�%�#�
�
�
��
�� ����
��
�"��*�'����.�
�"������ ��
�$�$�)�"�%�
��
�'��
�
���� [...]
+������
+�
+����
�
� ����
+��������
+�
��
+�� �� ���������� ��
�����
�#�����
�
���#�#�
�
�$�
�!���
�
�
�
�����
�����%��
�.�
��
��
������
� �� �%��
���
+���
���� �
+�
+��
+��"�"��!�
����#�����
�*�
�$�"���-�
�(��������"�
�
�*�"�#����&�-�#�'�
� �:�)�-�#�*�&��#�%�'�(�-�+�%�+�.�
�-�)�
�
�$�*� �,�
�(�(�.�$�+�$�
�&� �,�&�#�"�2�+�0�"�"�0�6�(�
� �,�
�,�$�*�,�7�-�2�4�2�&� �;�3�<�4�2�@�9�6�.�.�4�-�4�>�B�G�M�H�Q�R�G�B�<�D�7�E�V�R�W�P�>�B�O�[�^�X�R�U�Z�I�F�R�`�T�_�d�h�e�b�c�\�`�f�[�]�o�m�n�p�l�n�}�i�~�s�p�z�x�q�r�z�n�n�u�~�v�u�s�j�r�s�~�z�������v�s���t�y���|�{�������������������������|���~�x�����������}�������w�~�x�~�������������~���u�e�u�y������ [...]
�� ��
���� ��
��������
+ ��
+ ������ ������ ��
#
'
!
������������
+ �� ��
+ ����
+ �� ���������� ������ ��
��������
+
+ ��������
# ! ����
��
����
����������
+ �� ���� ��
+
+ ������
���������� ����
��������������������������
+ ���������� ��������������������������������
���������� ��������
+
+
������������������ ������������ ��
���� �� �� ���� ���� ���������������� ������
+
+ ������
��������
������
+
����
��������
�� ���������� & # " $ (
# &
' $
! ! % ' ' '
#
+
��
$ $
������
! # & , % $ - #
+ - " ' &
+ ) "
+
$ ��
% * *
!
"
+
��
+
������
�� & ) )
+
* & !
��
���� ��
+ ��
+
���������� ������������
������������ ������������������ �� ������
������ ��������
���� ����������
+
������
+ &
�� ���� ���������������������� !
���� "
' $ "
����
��
(
% + "
+
"
+ " % & 6
+
+ . #
�� ����
+ % '
�������� ��
" $
������
�� ! ����
"
)
+ $ $ '
&
$ ��������
, ����
��
+ �� ����
+ ��
+
��������
�� �� $ & & ����
+
��
+ ( * �� ������ �� ����
+
�� ����
+
����
���������� �� ��������
+ ���� ����
�������������� ������ �� ����
�������� -
*
�� ����������
+
��
�� ���� �� �� ���� ��
+ ��������
������
����
����
+
����
��������
�� �� ��
+ % "
% '
!
%
$ % , '
���� " "
��������
�� # &
������ ��
+ ��
! ! ' " . "
+ ,
$ $
* ( #
& ��
+ $ ( (
' &
+
����
+ ������
�� ) * ( ��
* ( $
��
+ ����
+
��
+
��
+ ����
+
+ ���������� �������������� ������������ ������ ���������� �� ������ ���� ��������
+
���� �������� ����������
&
��
�� �� ���� ���� ������ ������ ��
������
" !
��
����
+ ����
������ ��
+
( + , " $
* ' $ , - 0 )
$ ( + & ! & . & # ( ' - % ( ( ! & *
# . * # - # *
&
! ( &
+
& & ����
$ '
# & ' 1 ( ' / (
, 0 ( , / " " ! 0 , )
$ & ' .
+
+
+
) - * !
%
! ' , % )
+
+
����
���� ( * ,
# ! & 2 + (
����
��
!
+
�� ������
����������
������������ ����������������
��
+
+
�� ����
������
- $
+
���� �� ������ ����������
������
# "
����
����
�� ����
! ( ( /
!
&
) 0 3 ) "
) $ ' ! % + "
' $ - % ( ! ! ) ,
"
! / 2
% 2
, %
+ ) !
" " + , ��
# 0 / # ����
# &
& ( , " # , * +
& )
$ * + '
! +
+ ! ) "
# �� *
+
������
+ ���� ( ) +
���� ' & %
��
!
+ ����
+
+ ��
+
�� !
��
+
+ ���������� ������������
���������� ����
+ �������� ���� ��
�� " " '
+
��
������
, !
�� %
������
! #
+ �� " ��
����
! ��
+
$ % '
! # '
#
$
" #
! %
( '
(
# ��
+
!
������
" !
������
�� ��
+
! &
&
#
" #
& ��������
!
+ "
���� ��
����������
���������� ! # ������
+
"
�� ������ �� ���������� ��
+
��
+ ����
���������� �������������� ������������������������������������������������
+ ����������������������
+
�� ������ ����������
%
+
��
��
+ ���� �� ������ �������� ������
������
+ ����
����
���� �� �������� �� ���� ��
!
# %
"
"
������
������ ��
+ ��
+
!
!
$ #
+ )
!
+
+
����
����������
�������� ! % ��
(
��
+ ���������� ���������� ��
+
+
��
+
���������� ��������������
+ �������������������������������� �� ������
+ �� �� ��������
+
����������
����������
$
���� �� ������ ����������
������
+
��
����
����
�� ��
����
��������
�� ������ �� ���� ��
+ ����
+
+
$ ���� ��
+
+
+ ������
+ ����������
���������� % ������
+
���� ���������� ���������� ��
��
���� ��������������������������
������������ ������������������ ���� ������
����������������������
������
������������
+ "
+ ��
����
������
��������
������
����
������
����
�������� �� ����������
+
+
�� ������
+
������ �� ���� �� ������
+
+
! " ( �� ��
+
����
+
+ ����������
+ ���������� " ����
+
+
��
+
+ ������������ ���������� ��
��
���� ���������� �������������� �������������������������������������� ������
�� ������������������
+
+
����������
����������
&
+ ���� �� ���� ������
+ " ������
+ ������ ����
������
+
����
+ �� ����
+
!
#
$
"
%
+
"
��
! " ������
��
!
#
$ & ' !
$ # +
!
! ! ! #
+
���������� ������
# % ��
+
+ #
+ �� ���������� �������� ��
��
��
+
+ ���������� ��������������
+ ������ �� �������������� ������ ������������������
+
������ ����������
$
���� �� ���� ������
$
����
��������
����
��
+ �� ��
% ( "
# # * ) " #
'
"
$ "
"
#
#
$
����
������
+
+ ��
$ & #
! & # -
+
+ "
+
��
���� ������ $ ) ��
+
&
" ���������� ����
+
��
������
+
���������� ��������������
+ ���� ���� �������������� �� ��������
����������������������
+
���� ������������
$
+
+ ����
+
��
"
������
+ ������
+
����
�������� �� �� #
+
"
��
������
+
������ �� �� ����
+
$ �� ��
+
����
+ ����������
����������
" ������
���� ������ ��������������
���������������� �� ����
�������� ��
������������������������������ ���������������������������������������������� ���������������������� ����
�� ���������� ������������
+
+
�� ������ �� �� ���� �� ���� ������
������
����
������������
+ ������
+ ������
���� ����������
����������������
#
% &
+
+
+
����
+
������ ��
+
��
+
"
$ ��
!
+
+
+
��
+
��������
����
# (
#
��
+
������������ �������� ��
+
+
��
+
������������ �������������� ���� ������������ �������� ����������������������
+
+
+
+ ����������
+
+ #
+ ������ ����
+
+ " * " ��
��
������������
+ ����
��
���� ��������������
+ ��
������
+
+
+
��
���� �������� ����
+ ���������� �������� ������������ ������������������
��������
+ ������
+ �� ��
��
��������������
+ ���� ���� ��
�� �������� ��
����������
������������
�������������� �� ������
�� �������������� ��������������
�������������������� ������������ ���������������������� ���������������������������������� �������������������������������������������������������������������������������������� ���� �������������������� �������������������� ��������
�������������������������������������������������������������� ������������������������������������������������������ ��������������������������������������������������������������������������������������������
+
+ �� #
+
��
+ ��
����
����
+ ��������
�� ��
��
+
! $ ��
"
+
��������
������
&
��������
��
�������� ������������ ���������������� �� ����
�������� ��
+ ������������ �������������� ���� ���� �������������� ��������������
+ ������������������������ ����
��
+ ���� �� ������������
+
���� �� ������������
+ ������
������ ������
������������
����
+ �� ��
+
+
���� �� �� ���� ������������������������ ����
+
�� ��
+
��
+ ��
+
+ ��
+ ��������
���� ���� ������ ��
+ �������� �� ������ �� ���������� ������ ��
����
+
������������������ ��
+ ��
����
�� ��������������������������
+ ���������������� ������������
������
+
����
�������������� ������������
����
�������������������� ���������������������������� ������������������������������������������������
����������������������
�� ��
+ ��������������������������
+ ������������
�� ��
��������������������������������������������������������������
������
+ ����������
+
+ ��
+ ������
+
+ ������
+
���� ��
+ ��������
����������������
��
������ ���� �������� ��
����������������������������������
����
����
������������������ ��
+
+
+
+
�� ������������ ����������
+ ������������
������
+
+
+
+
����
�������������� ������������ ������ ���� ������������ ������ ������������������������������������������������������������������������������������ ����������������������������������
���������������������������� ��������������
+
+ �� �� ��������������������������������������������������������
+ ������
+ ������������ ������������������ ���� ������ ���� ���������������������������� ��������������������
+
+
��
��
+ ��������
��������
��
������������ ���������� ������ ��
+
����
������������������ �� �� ��
+
�� ��������������������������
�������������� ������������ ���������� ����
�������������������� �������������� �������������������������������������� ������������������������ �������������������������������������������������������������������������������������������������������������������������� ������������������������������ ���������������� �������� ������������������������������������������������������������ ������
+
������������ �� �������� ���� ������ ������ �� �������� ������������������ ����������������
! # '
"
$
!
$ & ! #
" ��
!
������
�� ��
$ ' & + ! # ' ' #
" ��������������
+
! % !
!
#
+
����
+
��������
+ �������� ! % '
+ % ��
+
+
+ ����������
���������� ��
+
��
+
+
+ ���������� �������������� ���������������������������������������� ������ ������ ��������
�� ������������������
+ ���������� (
+
������������������������������
����
$ "
���� ����
��������
"
+
��
+
������
������ ��
��
"
+ ����������������
�������� ��
���������� ������������
������
+
�������� ���� ��������������
���������������������� �������������� ���������� ���������� ������������������������������������������������������������������������������������ ���������������������������������� ������������������������������ ���������������� ���� ������������������������������������������������������
������
������������
+ �� ��������
������ ������ �� ����������
�� ������������
����
������
+
������ �� ������ �� ������
+
+
+
��������������
+
+
+
+ ������ ����������
����������
������
+
�� ��������������
+ ���������� ����
+
�� ������ ��
������������������������������������������������������������������������������������
���������������������������������� ���������������������������� ������������
�� ���������������������������������������������������� #
����
������ ����
+
+
���� �� ��������
���������������� " "
# % ) !
" $
&
# %
% %
(
!
( $
%
$
#
+
$ ' ������
+
+ !
' ! ! ( & + % $ '
) &
! " ) ��
+ " ' "
# % % %
+
��������
�������� $ (
# . ' $
������ �� �������� ��
+
+
+
+ �� ������ �������������� �������������������������������������� ������ ������
+
�� ���� ����������
+ ������ ��
+ *
���� �� ������ ��������
����
$ "
��
����
�� ����
+
��������
+ ��
+
�� ��
+
��
+ ��������
+ ����
+ ���������� �������� ��
+ ��������������������������������
������
��
+ ����
+
+ ������������������ �� ��
���� ��
+ ��
���������� ������������
�������������� ������������ ���������� ��������
�������������������� �������������� ��������������������������������������
+ ������������������������ ���������������������������������������������������������������������������������������������������������������������������������������������������������� ���������������� �������� ������������������������������������������������������������
������
+ ����
������������
������
������ ������������ �������������� ����������������
!
+
������
+
������ �� ���������� ������
+
+
+
+
" ������������
+ �������� ��
+ ����������
������������ ������
+ #
��
������������ �������������������� ��
������ ��
������������������������������������������������������������������������������������
����������������������������������
+ �������������������������� ������������
������������������������������������������������������ ������
������
+ ����
����
+
���� �� �������� ����������
+
+
+
��
������
+
������ �� ���������� ������
+
+
+
+
! ��������
+
+
+
������
+ ���������� ��������
����
+
+
+ ����
+
+ ������������
��������������
+ ��
������
+
������������ ������������������ ���������������������������������� �� ������ �������������������������� �� �� ������ �������� ������ ��
+
+
&
+ ������ �� ���� �� $ / # ��
������ ��
���� ��
!
!
"
" "
#
%
$ #
��
������ ���� �� ��
+
"
% �� ��
#
+
��
+
����������
����������
$
�� %
��
+ ������������ ���������� ��
+
+ ��
��
�������������������������� �� �������������������������������������� ������
���������������������� ���� �� ������ ����������
+ ������������
+
!
���� �� �� �� ���� ���������������������� ������
��������
����
+
������
+
����
+
�� ����
+
! ! "
!
+ !
+
��
������ ������ �� ����
+
" ��
+
+
!
��
+
���������� ����������
!
+ ������
+ ��
+ ������������
����������������
+
+ ��
����
������������������������������ ���������������������������������� ���� ������
����������������������������������
+ ���� ������������������ ����������
+
���������������������������� ���������������������� &
����
������������
+ ����
��
+
����
+
���� �������� ������
"
#
" & & $
$
#
$
+
!
������
��
+
+
!
&
!
"
+
��
+
���������� ��������
#
����
+
+
������ ������������
������������������ ������
+ �������� ��
�������������������������������� �������������������������������� ���� ��������
���������������������������������� ������������������������ ������������
���������������������������� ������������ ��������
%
������
+
����
������������
+
����
+
+ ����
+
����
+
+ ���� ����������������
#
$ %
!
#
!
#
��
������ �� �� ��
& �� ����
+
+
#
+
+
+
��
���������� ��������
#
������
+
+
��
������������
���������� �� ����
������
�������������������������������� �������������������������������� ���� ��������
���������������������� ��
+ �� �� �������� ������������
������������ ������������ ����������������������
+ !
������
+
+ ������������
����
+
���� ����
�� �� ������ #
!
%
& # ! ' ( !
) ! "
&
& %
"
!
# ������
+
+
! $ %
" % % +
$ ' %
! % #
' '
������
���� # (
%
+ ��
����������
+ ������ ��
+
��
+ ������ ��������������
+ ������ �� �������� ��
+ ���� ����������������������
+
+
��
��������
+
'
��
���� �� * " ��
������������
+
+
!
!
��
+
������
��
��
+
'
+
!
! !
��
������
������ &
��
+
���� �� ������������
���������� �� ����
������
+
���������� ��������������
���������� ���������������� �� ������ ������������������������ ������
�� �� ��������
+ ����������
+
+
+ �������� ���� �� ��
+ $ ������
+
+ ����
+
+ ������������
����
����
���� �� ���� ���� ��
���� �� �������� ������ �������� ������ �������� ���������� ���������������������������������������������������������������������������������������������������������������� ������ ��
+
+
+
+ ��������
+
+ ���� ���������� ������ ��
+ ������������������������ ���������� ������������
���������������� �� ���� ������
+ ������
����
�������� ���� �� �� ������ �������������� ������������ �������������������� �������������� ���������������������������������� ��������������������������
+ ������������
������������ �� �� ���� ������ ����������
+ ���������� �� ����
������������ ���� ��������������������������������
������ �� ������������ ����������������
��
+ ��
����
+ ���� �� ����
+ �������� �� ������ ��
+ �� �������� �������������� ������
+ ��
+
����
+
+ ������������������
+ �� ���� �������������� ����
+
�������������������������� �������������� ������������ ������������ ���� ������
�� ������ ���� ����������
������ �� ����
������ ��
����
���������� ������������ �������� ������ ����������
+ ���������������������������������������� ��������������������
�������������� ����������
�������������������������� ���� �������� ����������
����
+
+
���� ����
��
+ ��
�������� ����
����
�� ����
�� ������
+
+
+ ��
����
������
+
�� ������ ��
+
������
+ ��
������������
+
+ ���������������������� �� �� ����������������������������
+ ����������
������������
��������������������������
+ �� ������
������������
�������� ������ ������
+ ����
+ ���� ��
+ ����������
+
������
+ �������� ������ �� ����
+ ���������������������� ���� ���� ���� ����������
��������������
+ ��������
������������ ����
���� �� �� !
+ ������
��
����
��
+ �� �� �� ����
+
�� ���� ���� ���� $ )
!
" & ' $ #
"
" '
+
$ ) !
# & # " # * "
" "
* %
" % $ &
��
����
����
#
������
+
+
+
+
+
+
+
!
+
+
+
+
+ ! "
+
+
! $
" ����
+
+
$ - ��
$ !
! " "
+
+
+ "
+
+
+
+
+
����
+ ��
+
����
+ ����
����
+ ���� ��
����
+
+
"
+
+
����������
+
���� �� �� ������ ����������
����������
���������� �������� �� ��
���������� ������������
������ ��
��
������ �� �� ����
+ ��������������
���������� ���������� ������ �� ������ ���������������������� ���������� ������������������������ �������������� �� �� �������������������� ������ ���� ������������������ ������
+
������
+
��
������
����
+ �� ����������
+ ���� ������
+
��
+
+
��
+
+ ����������
����
��
$ ��������
+ #
�� ��
��������������
������
���������� ���� ���� ������������������ ���������� ����������
�������������������������������� ����������������
+ ��������������
+ ������������
������ �������������� ����
+ �� ���� ������ ��������������
�������� ������������������ �� ������ ����������������������
���� �� ������������ ������������ ����������������
�������� �������������������� �� ���� ��������
��������
������
+ ������
��������
+
���� �� ������
������
���������� ����������������
+
+
+
+
+
��
��
+
������
+
������
%
" )
���� ��
+ �� �� �� ��
+ ��������
������ ��
%
+ ������ ��
��
���������� �� ��
+
+
�� ��
+ ������ ��������������
���������� ���������� ���� �� ������ ������������������������ �������� ��������������������������
���������������� ��������
�� �������������� ���� ���� ������ �� ������
+
������
+
+ ��
����
��������
+
������ ����������
���� ������
�� % �� "
$ % #
+
����
+
+ ��
�� ! ����
������
+ ���� ���� ��
��! ������ ���� ����
������
+
������
+
+ ��
2 +
������ #
��������������������
+
�� ������������������
���� �������������� �� ���������� �������� �� �� ������������������������ �� �������� ����
������ ������ ���������� ����
+ ������
�������������� �� �������� ������������������ ������
����������������
+
�� ������
+ ��������
������ ������
���� �� ������ �������������� ���� �� �� ���������� �� ���� ���������� ���� ��
�� +
����
+
����
�������� �� ��
��������
+ ���������� ������
����
+
+
+
+
+
+
+ ��
������
+
����
+
+ ! !
+
' " !
! ��
+
��������
��������
$
������
+ ��
+ ������
������������ ������
+
������ �� ������ �������������� �������������������������������� �� ������
+ ������������������������ �������� ��������������������������
+ ������������
+ �� �� �������������� �� ���� �������� ���� % ��
�� ����
+ ������
+
����
+ �� ����
����������������
+
&
+
!
!
# % ����
$ ����
+
' *
! ) (
. 0
* . ( $ $
. ' " " " #
+ # &
+
+
��
�� ���� ���� # . ������
�������� �� ����
��������
�������� ��������������
+ �������� ���������������� �� ������ ����������������������
+ �� ������ �� ���������� ����������������
���� !
�������������������� ������ ��
������������ ��������
+ ! ������
������
����
+
��������
+ ������ ���� ���� ����������������
$
' !
" " " ! #
#
%
!
$ $
# ' * !
+
+ - !
# % % , & & - -
- 3 . ) . !
# 0 ( !
! & ( * $
% &
+
+ $
+
) , 0
+
!
+
+ ����
+
+
+ ����
+ ����
+ ��������������
+
�������� �������� ����
+ ����
��������������������
�� ��������
+
������ ��
' ��
+ " / ) ��
$
$ ' & (
+ ��
+ $ &
$ # !
�� (
% ) + & "
����
(
��
! "
# ����
,
���� ����
#
+
����
, - "
+ �� ( & 1
' )
$ & " ' + �� * 3 2 3 / / ! !
%
����
' ' ( # " $ )
����
+ �� 2 + " %
+
����
��
������ ���� 1 &
+ ���� ����
( ' #
������ /
% ����
< * �������� #
��
)
+ ��������
���������� ����
������ ! �� �������� �������� ������ " ���� 7 ,
+ ����
+ ��������
+ ! ����
����
+ ������
+
�� �� ������ ��������
! ������
�� ����
�������������� ���������� ���������� ��������������
+
��
+ ��
����
+
!
# #
& ) % # % &
"
��
+
�� �� ������
��������
������ " $ ) ��
+
+
+ ������
�������� ��
���������� ��
�� ���������� ��
������������ �������������� ���������� ������������������������ ������ ����������������������
���� ���������������� ������������ ��
���� �������������� ��������������������������������������
������
+
��
+
������
������
+
+ ����
�� ����
��������
! "
! " '
$ &
&
!
" !
" % $
+
# %
����
+ # &
# $ * " ! ' ! ' + % ' (
) "
# ��
+
! #
����
+ ��������
��������
# $
����
"
��
����������
�� ����
+
+ ��
���� �� ���������� �������������� �������������������������������������� ������
+ �������������������������� �� �������������������������� ������������
�� ���������� �� ������������ ������������ ��������
$
��
+
+ ��
��
+ ��
"
#
! �� $ ��
+
������
+
! ������
+
% !
#
# ' " #
��
+
����
+ # ������
�� ! % '
+
#
��
���� ��
����������
+
+ ���� �������� ��
+ ������������ ��������������
+ ���������� ������������������������ ������ �������������������� �� ����������������
�������������� �� ���� ���������� ���������������������� ������������������
������
����
����
+
������
+
+
����
�������� ������������
# !
$ " !
!
!
+ *
�� #
+
+
+
!
������
��
+ ! #
������
+ �� #
! '
$ " "
������
��
+
��
+ ��
+ ����
�������� ���������� % ���������� ��
+
������
+ ���� ��
+ ���������� ���� ���������� �������������� ������������ �������������������� �������� ��������������������
#
�� ������ ������������ ��
���� ���� ����
�� ���� ����
������ ������ " ��������
����
+
+
���� ����
+
��
�� ����
+ �� ���� ����
+
��
����
+ ������
�������� ������ ������
+ ��
+
����
+
+
# �� �� ��
+
+
��
+
����������
����������
������ ����
�� �������� ����
+
�������������� �������������������� ������������ �������������� ��
+ ������������ ������������������ ���������� ������������������ ������������ ���������������������������������� �� ���������������������� ���������������� �������� ���� �������������� ������������ ����������������������
+ �������� �� �������� �������������������� �������� ���� ������
������ �� ���������� ����������������
+
��
+
��
+
��
+
������
��
����
+
����
$
+
#
+
+
��
+ ��������
������
& ����
+
+ ��
�������� �� ������������
���������� ���� ������
+ ����
+
���������� �������������� ����
+ �������� ���� ������ ������������������������ ��
�� ��������
+ ����������
+
���� �������� ��
+
+
+
! ������
+ ����
+ �� ��������
+ �� �� ����
+
+
����
�� ������ �������� ������������
+ ������������������������������ ���� ����
��
+
�������� ���������� ���������� ��
+
���������� �������� ��
����������
�� ���� ������
����
+
# $ % ��
+
��
�� ��
+
����������
���������� ������������ ���������� ������������
������������ ��������������������������������������
������������������������ ������������������������������
+ ���������� ������������ �������� ���������������������� ��
�� ���� ������������
����
+ % .
��������
+ ������
+
����������
�� ������
������ �� ������ �� ���� ���� ���� ������
# $
+ #
! ��
+
+
+
! ��������
+
+
# ,
+
�� & #
!
+
����
����
# ������
����
+
�� ������ �� ������������ ��������������
+
+ ������
������
�������� ���� ������ �� �� ������ ���� ������ ������������������������ ��
+ �������� ����������
+
+
�� ������
+
+
+
!
������
+ �� ����
������
��
�� ��
+
+ ���� ���� ����
��
# &
+
!
! '
+ ) "
+
+
"
! # �� �� ��
% ' ) " * &
# ( $ !
! ! *
��
����
' ������
+
# �� ���� ��
������������ ����������
+
����
��������
����
�� ����
+
��
�� �� ��
+ ��
������������������������ ����
������
������������
+
����
+
+
+
#
+ ����
+
��
����
��
����
���� �� ��
* ,
+
+ $ + ( �� %
. !
+ 1
+
" ! + '
' '
+ ��
+ ����
/ '
+
" " ��
. , 2 , ���� ����
�� !
+ %
% 6 # 1 +
0 F *
�� �� ! % ( ���� & ) * "
����
����
* #
+ ���� ��������
"
+ �� ��
����
+
+
��
+
"
����
+
+
+ �� ������ ������������
+
+ ! ��
��������' ���� ������
��#
+ &
+
+ , :
��������
.
��������
+ " & "
����
��
+ % ��
! "
" '
" (
#
+
!
+
"
��
+
( % # % )
+
!
+
+
" ! ��
+
+ ����
' ����
+
����
�� ������������ ��������
����
���� �� ��
�� ��
�������������������� ��
+ ��
+ ������������
$ ��
0
��
��
+ ���� ��
�� ����
$ $ ���� �� " ! # '
������
������
��
��
+
+
�� ���������� �� ����
��
�� ����
!
����
��������
$
����
��
����
��
��
������
������
��������
��
��
+
+ ���� ��������������
�������������� ��������������
+
��
�������� ������������
+ ��
���������� ���������������� ���������������������� ������������ �������������������������� ����������
+ ���� ��������������
+ ������������ ������ �� ����
����������
�������� ��������
+ �������� ����
��������������
��
������ ���� ������������ �� �������������������� �� �� #
!
' "
(
5
(
%
"
"
, !
��
+
+
3
' &
# 5 1
+
�� #
$
$ & ��
�� #
'
��
# " �� ����
�� ������
+ �� ��
�� ��
����
��
��
+
+ ��
������������������ ��
+
+ ��
+ ������
��
+
+
+
+
��
+
:
��
+ ( ��
+ ��
��
�� ����
�� ���� �� �� ����
�� ����
+
��������
+
������
+ ������
+
#
������������������
��
+ "
��
+
+
��
! & 1
���� ����
��
+ &
���� �� +
����
+ ������
+
������
+ ���� ���������� ��
�������������� ����
+ �������� ���� ��������
��������
������
�������� �� �� �� ���������� ������������ ������������������������������ ���� ���� ������������
������������ �� �������� ���� ������ ����
�� ������ ������������ �� ������������
��������������
+ ������������ ������������������������������������������������ ������������������
+
"
!
% !
+
!
��
+
+
+ $
! ! &
+
% ��
����
! % ����
+ ! ����
+ ��
�������� ������
+
+
��
+
����
��
+ ��
+
+
+
�� ��������������������
��
���� ������
+
" 1 ��
+
+
��
�� ��
��
% #
+
( ! !
" (
�� # * "
#
+
+ # &
! % ����
!
+
��
!
+
" ���� %
"
+
+ ���� & )
! ����
# +
����
����
+ . ����
��
+
������ ��������
���� ����
��
+
�������� !
������
������ ������ ���� ����������
������
��
+
+ ����������
������
�� -
����
+ ����
��
+
���� ������
+
$
"
+
!
"
+
��
+
+
"
$
+
+
!
������
" '
$
+ # % ' ����
+ �� ��
��
+
+
+ �� ������ ���� ����
+
����������
+
+ !
������
' 1
��
����
+
!
$
) ' # " ! % + "
! ! ! ! # %
"
+
% %
��
+
!
" $
+
! #
! %
$ -
%
% ) +
'
+
��
����
+
��
��������
�� �� ���� ����
+
���������������������� ����
�� ������ ��������
������������
+
����
+
+
+
�� ������ �� ����
������������
+
+ ����
+ �� ��������
������ �� ���������� ����������������
% ' #
! &
$ % $
( "
" , % " ! # + #
" % $ & #
+ $ # $ !
" "
! % # "
& * )
��
%
+
#
" " )
+
+ !
+
+
) "
+ ! & $
��
+ #
+ ������
��������
+
��
+
& $
��
+ , ��
+
+
'
" " #
!
" + ; - ��
" !
!
$
!
!
#
'
%
$
% # ��
+ !
!
+
+
+
+
+
(
# $ ����
��������
+
�������� ��
+ ����
+
��
! "
+ �� �� ������ ��������
+
+
" ����������
+
/
��
+ ��
+
��
+
����
��
��
+
��
+
+
+ ��
+
+ ��
�������� ��
������
+ ���� ����
+
+
�� �� ����
�������������� �� ��
������������ �������� ��
���������� ����������
����������
������������
���������� ��������
������������ ����
��������������
������������ ���� ������ ��������
������������ ��
������������������������ ������������ ������ ���������������������������������� ���������������������� ������������
+ �������������������� ���� ���� �� ���� ������
+ #
������
+
������������
����
+
�� ������
+ ����
+ �� ����
���� ������ ��
+
�� ��
�� ��
��
+ ��
�������� ���� ��
+
+ ������
+
�������������� �� ���� ������ �� �� ������������������������ ����������
���������� ������ ��
��
���������� ������������
+ ���������� �� ���� ��������
������������
�������� ������������ ������ ������
+ ���������������������� �������� ���������������������� ������������
+ �� ���������������������������������� �� ������ �������� ������
+ ������������ ��
+ ������
����
+ �������� ��������
+
+
��
+ ������
+ ������
+
+ ��
+
��
+ �������������� ��
���� ��
+ �� �� �� ��������
+ ���������� ������������
���������� ������
�� �������� ����
��������������
���������� �� ������ ��������
+
������������ ��
������������������������������ ���� ������
������������������������ ��������
���������������������� ������������
+ ���� �������������� ����
+
)
��
������������
����
�� ������
������ �� ��������
���������������� ��
+
+
+ ��
+
+ ��
+
+
+ ��
+ ����
+
+
������
+
+
������������
+ ���� ��
+ �� �� �� ��������
����������
������������ ������ ������ �� �������� �� ������������
���������� �� ��
+ ������ ���������� ��
����
������������ ������������������������ ������������ ������ ������������������������ �������� ����������������������
������������
+
+ ��
+ �������������������� ���� ���� �������� ������
#
������
+ ������������
����
������
���� ��������
�� ����������
+
+
+
+
����
+
������
+
+
+
+
+
����������
+ ��
+
��
������
+ ���������� ������������
�������� ������
�� �������� �� ������������ ���������� �� ������ �������� ������ ���������������� �������������������������������������� ������ ������������������������ ��������
+ ���������������������� ������������
������������������ ���� ��
( ��
+
+ ��������
+ ����
������
+
+
���� �� ��������
+ ����������������
+
��
+
+
��
+
������
����
$
!
# ����
��
�� ��
+ ������
+ ��������
+
��������
������
+ �� ������
+ ������������ ����
+
+
+ ��
������ �� ���� ������������
������������������������ ������ �� ������
���������������������� ��������
������������������������
��������������
�� �������������� �� ���� ������ ' ����
+
����
�� ����
����
+ �� ����
�� ����������
+
+
+
+
��
+
������
+
+
���� ��
+
��
��
����������
����������
������ ������ �������� �� ������������
���������� �� ������
+ ���������� �� ������ ������������������ �������������������������������� ���� ������
+ ����������������������������������
+ ������������������������ ������������
���������� �� �� ����
+ ��
+ ��������
+
����
������
+
���� �� ������
+ ��������������������
+
��
+
��
+
+ ������
������
+
+
!
+
+ " �� ��
+
+
+
+
+
+
��
+
+ ����
+ ����������
����������
�������� ����
�������� �� ������������
���������� �� �� ������ ���������� �� ���������� ������������������ �������������������������������� ���� ������ ���������������������������������� ������������������������
������������
+
+
�� ���������������������� ���� �������� ��
* ��
+
+ ������
����
������
+ ������ �� ���������� ��������������������
+
+
+
+ ������
+
������ ��
+
+
���� �������������� �� �� ��
+
�� �� ��������
����������
������������ ���������� �������� �������������������� �������������� �������������������������������������� �������������������������� �������������������������������������������������������������������������������������������������������������������������� ���������������������������� �������������� ��������
������������������������������������������������ ��������
#
������
+ ����
+ ���������������� ���� �������� ������������ ���������� ������������������������������������������������ ��
+
+
+
��
+ "
����
+
!
!
+
+
! ��
+
��������
+
��������
!
������
��
������ ������������ �������� �� ����
������ ������ ������������������ �������������������������������� �� ������
+ ����������������������������������
+ ������������������������
������������
�������������� ������ ���� ����
+ " ��
+
������
����
��
+
+
+
���� �� ��������
����������������
+
+
��
+
����
������
+
+
!
%
! "
+
"
+
+
��
��������
+ ��������
#
������ ��
+
�������� ������������
���������� �� ��
+ ���� ���������� �� ���������� ������������������ �������������������������������������� �������� ���������������������������������� ������������������������ ������������
�� �������������� ������ ���� �������� ���� ' ��
��
+ ����
������
������ �� ��������
+ ����������������������
"
+
&
��
#
+ $ ����
��
!
������
" % ������ �� ���� �� ���� ! "
"
#
+
+
% " # #
+ ����
! ' ��������������
# $
! �� ��
�������� ��
����������
������������ # ( ����������
������
! ���������������� �� ��������������
�������������������������������������� ������������������������ �������������������������������������������������������������������������������������� ���������������������������������� ����������������������������
+ ������������
������!
���������������������������������������������������������� # 1 ' ������ #
������
������������ �� �������� ���� ������ ������ ���������������������������� ��������������������
+
+
+
+
+
��
+
����
+
������
+
"
+
+
��
+
+
+
+ ����
+
+ ����������
���������� !
������
�������� ������������
���������� ������ ����
+ ���������� �� ������������ ������������������ ���������������������������������������� �������� ���������������������������������� ���������������������������� ������������
�� �������������� ������������ ���������� ������
) ��
������
+ ����
������
���� �� ���������� ��������������������
+
+
+
+ ��
+
+ ��
+
+ ����
+
������
+
������
" & $ !
��������
+
+
+
��
�� ��
+ ������
���������� ������������
������
+ ���� �� �������� ��
��������������
�������������������� �������� ������������������������
+ �������������������������������������������������������������������������� �������� ����������������������������������
�������������������������� ��������������
��
+ ������������������������������������������������������������ ������
�� ����������
+
������
+ ������
������ �� ���������� ���������������� ��
+
+
+
+
+
+
+
����
������ ��
+
!
"
+
" ��
+
+
��
��������
+ ��������
& ��
!
��
������������ ���������� �� ����
������
���������� ������������������ ���������������������������������������� ������
����������������������������������
������������������������
+ ������������
+
���������������������������� ���������� ������ ( ��
������
����
+
���� ��������
��������������
+
+
+
+
+
��
+
+ ������
+
+
������
& " #
���� ��
+
+
����
��������
��������
! % ��
+
+ ������
������������
���������� ������
+ ����
�������� ��
������������ ������������������ �������������������������������������� ������ ����������������������������������
�������������������������� ������������
������������ ������������ ������������ ��������
' �� !
+
��
����
����
+ �������� �� ����������������
+
+
������
+
������ �� ������ �� ������
��
�� ����
+
+ ��������
����������
+ ����������
�������� ��
+
�������� ����
�������������� ������������������ �������� ���������� ��
�������������������������������� �������������������������������������������������� ���������������������������������� �������������������������� ������������
+ ���������������������������� �������� ��������
'
������
����
+
��������������
������
������
+ ������ �� ���������� ����������������
" #
"
"
+
������
��
��
+
!
! )
+
"
�������� ��������
#
������
������ �� ������������
���������� �� ����
������
+ ���������� �������������� ������������ ���������������� �� ������
+ ����������������������������������
�� ������������������
������������
+
�������������� ���� �� �� �� &
����
����
+ ������������
+ ���� ����
+
����
����
������������������������
+
��
+
+
+
��
+
��
����
��������
������������������������ ������
�� ��
+
����
+ �� ����
�������������� �� �� �� ��
+
��
����������������������
�������������� ������������ ������������������������������ �������������������� �������������� �������������������������������������� �������������������������� ���������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������� ��������
������������������������������������������������������������ �� [...]
+
" #
!
"
$
#
"
������
+
+
" !
&
������
��������
$ ������
+
���� �� ������������ ���������� �� ����
������ ������ ��������������
+ ���������� �������������� ����
+
��������������������������������
�� ������������������
+ ����������
+ ������ ����
+
, ! ��
����������
��
����
����
��������������
+
! !
#
# & )
! "
" ' ! ! ' , " " "
$
+
%
&
" $
!
# ������ ��
( # # 4 % (
"
+
+
!
+ # ' ' ' + -
( / /
"
! & , , $ ! �� ������
, ������
! �� !
�������� ������ ����
����
��
+
+ �� ����
+
�� ������������������������
+ ������
�� �������� ��������
+ ��
!
+ ������
+
+
) 6 +
+ ����
+ ������
��
+
+ ����
+
+
+
����
+
������ ��
��
��
�� ����
��
+
�� ������
����������
������������
�������� ������
�� ������������
+ ������������ �������������������� ���� �������� ������������ ��
+ ������������ ������������������ �������������������������������������� �������� ���������������������������������� ��������������������������
������������
+
�������������� �� ����
+ ) ����
+ ����
+ ������������
������
������ ���� �� �������� ����������������
!
!
$ &
!
%
"
+
+
!
������
+
$ !
" # )
+
+
������
����
% ����
+
������ �� ������������ �������� ��
+ ����
������
����
������������
���������� ���������� ��
+ ����
+ ��������������������������
�� ������ ������
+ ����������
+
������
+
+
+
+
* ��
��������
���� ����
+
�� �� ����
+
+
+
+
+
"
������
+
+
+
"
+
+
+
��������
+ �������� ! ������
������ �� ������������ ���������� �� ������
������ ������
+ ������������
������������ ���������� �� ������
������������������������ ��
�� ����������������
������ ����
������ ��
! - # ��
��������
+
���� ����
+
+
+
����
����
����������������
!
"
!
+ ������
��
! $
+
+
������
+ ��������
"
������
+
+
������ �� ������������ �������� �� ������
������ ����
������������ �������� ���������� ����
+
������������������������ ��
�� ������ ��������
����������
����
+
+
+
+
+
+ ��
��������
+ ��
+
+
����
����
+
���� ��������
+
"
+
! % ������
+
+
" �� ����
��
+ ����
��������
+ ��������
" �������� ��
�������� ������������ ��������
+ ��
������
������
+ ��
������������
+ ������������ �������������� �� ������
���������������������� ���� �� ����������������
������ ����
�������� ��
+ " / $ ��
��������
���� ����
+
����
+ ��
+ ����
�� ������������ ��
+
������
+
+ !
��
+
+
�� ����
���� ����
����������
��������
������ �� ������������
+ ���������� �� ������
������ ������������
+ �������� ���������� �� ����
+ �������������������� �� ��
�� ���������� ����
+ ������������
+
�� ������
+
+
+
+
)
��
+
+ ��������
+ ����
������
����
����
+
+ �� ���� ����
+
" '
!
$
"
"
����
+
+
#
" ! &
+
+
��
����
+ $ ������
+
���� ��
������������ ��������
+
��
+ ��
+
�� �� ��
+ ������
+ ��
�������������������� ��
������ ����
+
+ !
0 ��
+
+
��
����
��
����
+
+
+ ��
+
+
��
+ ������
+
+
+
+
+
+
������������
+ �� ���� ��
��
��������
��������
��������
+ �������� �� ������������
������
+ ��
����
+
+
+
������������ �������� �������� ������
���������������������� �� ������������
���� ��
������
+
* ��
��������
+
+ ��
������
����
+
����
+ �� �� ��
+
+
+
+
!
������
+
$
+
+
��
+
�� �������� ! ��������
+
+
����
+ ������������ ������
+
+ ��
����
+
+
+ �� �������� ���� �������� ������
�������������������� �� ������ ��
���� ��
+
+
+
, ��
��������
��
��
+
+
+
����
��
��
+
+
+
+
+
+
+
+
����
+
+
+ ������
+
��
�� �� ��
��
+
��
�������� ��������
��������
+
������ ������������ ����
+
��
��
+
������ ���� ���������� ������
��������������������
+ ����
���� ��
��
+
+
+
+
*
��
������
����
����
����
+
+
+
����
+
����
+
%
+
+
# ��
��
+
$ ��������
+
����
������ ��
+ ��
+
��
�� �� �� ����
�� ��������������������
+
+ !
���� ����
+ - ��
��
+ ����
+
+
+
��
+
+ ��������
������ ������������������ �������������� ������ �������� ���������� ���������� �������� ������ ��
�� ����������������������������
�������� �������� ������
����
����
����
���� ������������ ������������������ ������
���������������������������������� �������������������������� ������������������������������������ ������������������������������������������������������������ �������������� ���������������������������������������� �������������������������� ���������������������������������� ������������������������������������������������ ���������������������������������� �������������������������� [...]
�������������������������� ���� ������������������������ �������� ����
+ ������������
+
���� �������� �� ������ �� �������� ���������������������� ����
+
������
���� �� �� ������ ��������
+ �������� ���������� �� ����������
+ ��
����������������������������
�������� ���� �� ������ ���� ������
+ ������
���� ���� ����
+ ���������������������� ������ ������ ���������������������� ��������������������������
���������� ������������
+
������������
+ �������������� ���������� ������
�������������� ���������������������� �������� ������������ ����
�������� �� ���������������� ������������������������ ������������������������ ���������������������� �������������������������������������� ���������������� ��������
+ �������������������������� ��������������������������������
������������ �� ��
+
��������������
+ ���� �� ������ ���� �� ������
���� ����������
��������������
����
+
+
+ ������
������
����
+
+ ���� ��
+ ����
+ ����
�� �� $
������
+
+
������ �� �� ����������������
������ ������ ���������� ! ������
+
+ ����
+ !
+
���������� ����
+
+
+ ���� ���� ��
+
����
�� ���� ��
����
������
+ ���� �������� ����
+
����
���� ����
+ �� �� ���� ��
+
���� ������ ! ��
+
% ��
+
��
+
+ ��
+ ����
+ ������ ��
+
��
�� ��
���� ���� ��
+
�������� ������
+ ������
+ ���� ����
+ ��
��
���� �� ����
�������������� �� ��
�������������� ���� ��
���������������������� ������������
������������
���������� ������
������������ �� ��������������
+ ������������ ������ ������ ���������� !
������������ �������� ���������� ������������ ������
+ ����������������������������������
+ ���������������������� ������������
���������������������������� ���� ���������������������� ! ������
��������
��
+
������
����
�� ����
+ �� �� ��
+
���� �� ����
���� ������ ������ ��
��
������������������������
��������
+ ���� ����
+ ����
+
��
���������� ������
������������ ������ ����
+ �������������� ���� ����
������������������������ �������������� ������������ �������� ������������������ ������������ �� �������������� ������������ ������
�������� ���������������� " ���������� �������������� ������ �� ����������������������������������
��������������������������������
��������������������������
������������ �� �� �� ���������������������������� ���� �������������������� ) �������� ���� ����������
����������
���� ������������ ������
�� ���� �������� ������ ��
+
+
��
��
����
��
+ ��
������ ��
+
������
+ ����
������
������
��
+ �� �� ����
�������������� ���� �� �������������� �� �� �� �������� ��������
+ ���������� ����������
�������� �� �������� ������������ ��
��������������
����������
+ �� ���� ����
+
+
#
+
������������
���������� ���������� ���� ������ ������
+ ������������������������ ��������
�� ������������������
+ ������������
+
�������������������� �� ���� ���� ������ #
+ ������ ������������
+
���� ���� ������ ������ �� ������
���� �� ���������� ���� �� ������ �������� ������ �������� ���������� ���������� ���������������� ������������ ������
+ �� ����������������������������
������������ ���� �� �������� ���������������������� ��������
�� ������
����������������������
������������������������������
������������������������������ ��������������������������
+ �������������� ������������
������������������������������ ����������������������
�������������� ������������ �������� �������� ������������������ ���� �� ������ ������������������
+ ������������������������������������������������ ���������������������������������� �������������������������� �������������� �������� ��������������������������������������������������������������
���������� ����������������
+ ���������������� �������� ������������������������������������ ���������� ���������������� ����������������������
+
+
��
��
+
��
������
+
������
���� ����
+
+
+
+ ������
+ ��
�������������� ��
+ ������������ �� �� �������� ��������
+ ����������
+ ������������
������������ �������� ������������ ��
��������������
������������ �� �� ���� ������
+
+
+
������������
���������� ���������� �� ���� ������ ������������������������ �������� �� ������������������ ������������
�������������� �� ����
+ ' ����
+
������������
����
�� ������
������ �� �� ���� ������ ��
+
+
+
��
��
+
+ ��
+ ������
������
+ ��
������
+ ������
��
����
��������������
������ �� �� ��
�� �� �� ����������
+ ���������� ��������
�� �������� ������������
��
+
+
+
#
�� �� ���� �������� �� ������
�������������������� ������
������ ��
+ �� ������
+ " ������ ��������
+ ��
������
+ ����
��
+
+
��
+
��
��
+ ������
+
������
�� ���� ������
+
��������������
+ ��
������ �� �� ��
+ �� ������
���������� ����������
���������� ��
�� �������� �� ������������
+ ��������
+
��
����
+
+
������������ ���� �� ���������� �� ���� ������
���������������������� ��
������ !
������ ��
���� ������
+
+ &
������
+
+
+
��������
+ ����
+
+ ����
+
����
��
+
+
+
+
+
��
+
��
����
+
������
+
+
������ ��
+
+
��
+
��
����
����������
+
�������� ������������
+
#
�� ����������
������
�������������������� ������
+ ���� ����
���� ����
! ������ ��
+
+ ������������
����
+ ����
����
+ �� ��
+
+
+
����
+
+
����
+
��
��
�� �� ��
+
��
+
+
�� �� ������ !
��������
������ �� ������ ����
��
��
�� ��
��������
+ �� ������
������������������
����
���� ��
+ ��
+
+
+
+
* ��
+ ��������
��
+
+
��
��
��
+
����
)
+
��
��
������
���� ��
0
��
��
��
����
+
! # �� ����
+
+
+ % &
��
�� ' / 4 ���������� ��
+ ������
���������� �� '
+
������
��
( 0
������
+ ��
���������� ��
�� ���������� ��������
���� , 3 �� ����
+
��
��
+
. 2
������
%
�� ��
+ ��
��
���� #
+
+
+
!
"
'
! $ ��
����
+
#
������
!
+ ! #
! !
# &
+
* /
+
& $ ' - ������
-
��
+
+ ��
+
+
+
" %
$ #
+
��
��
' ����
$
+
#
* 2
��
#
+
" ����
%
+ %
!
#
! $
!
�� !
!
"
������
����
+ ����
! !
����������
"
+
+
+ ��
��
+ !
"
+ ��
+
) ����
��
" $ % - ��
����
# ! ����
+ ��
������
�� ���� ���������� !
������
+
����
���� �� ������ ��
�� �� ��
& �� ����
+
��
+
+ ! $
+ ! -
%
����
" ��
��
��
+
#
!
"
+
����
+ ��
+
+
�� $ *
+
% )
" ����
��
+ ������
+
+
��
+
+
+
+ ��
������
+
+
���� ���� ����
+
. ��
+
+
+
+
+
+ ��
+ ��
+
����
+ ��
��
�� ��������
+ ����
������ �� �� ���������� ������������
+
�������� �� ����
����
+
��
�� ����
+ ���������� ���� ������
+ �������������������������������� ��������������������������
������������������������������ ��������������������������������
����������������
�������������� ������������ ������ �� ������ ������������ �� ��
���� ������ ��������������
+
���������� �������������������� �� ������ ������������������������ ������ ���������������������������� �������������������������������� �������������������������� ���� ������������������������
���������� ����������������
������������
+ ������ ������������������
+ �������� ���������������� ������������������������ ������ ������ ������ ����
������ ������ ��������
+ ���������������� �������� �������������� ������������������������������
�������� ����
����
������
�� ��
���� ��������
+
���������������� ������ ������������������������������ ��������������������������
�������������� ������������������ ������������������ ������������ �� ���������������� �������������� ���� ���������������������������� ������������ �� �� ������ �� ��������������
+ ����������
��������
���������������������� �������������������� ���������������������������������� ������������������������������ ���� ���� ������������ ���� ���������� ������
+ ������������
+ ������
+ ����������
+ ��
����
+ ������
+ �� ������������
�� �������������� % * #
�� % �� #
+ ��
��
+
��
+
+
#
+
��
����
+
��
+
+
+ ,
+ ������
����
$
��
+
������
��
�� ����
# ����
+
��
+
+
+
����
�� ����
+
��
+
����
+ ��
& . !
+
+
$
"
+
+
�� (
+
+
+
+
+
��
��
+
+
+
!
+ ����
+
+
+ ��
+
������
+
+ ������
+
+
+
+
+
+
+
����
+
+ ��
+
+
����
+ "
��
+
+
+
+
��
+ ���������� �������� ��������
+ ���� �� �������� ������������ �������� ����������
���������������������������� ���������� �������� �������������������������� ������ ������������������������ ���������� �������� ���������� �������������� ���� ����������������������������
+ ��������������������������������
+
+ �������������������������������� ������������������������
�������������� ������������ �� ���������������������������������� ���������������������� �������������� �������������������������������������� ������������������������ ������ ������ ������������������ �������������������������������������������������� ����������������������������������
���������������������������� ������������������ ����������
+ ����������������������������
���� ���������������������������� ������������ ���������������� ������������������������������ ������������������������������������ ����������������������������
����������������
%
+
! !
+
+
+
��
) 0
��
��
&
$
#
"
" "
+
! $ $
+
+
+
"
+ $ $
��
$ "
# *
"
" ) ��
+
+
+ +
�� & $
!
# ' $
+
"
) - &
+
' ' (
�� ���������������������� �������������������������������������������������������������������������� ������������������������������ �������������������������������������������������������������� �������������������������������������������������������������� ������������������������ ������������������������������ �������������������������������� ������������������������������������ ���������������������������� �������������������������� [...]
����������������������
+ ������������������������������ �������������������������� ���� ��������������������������
�������������� ������������
����������������������������
�������������� ������ �������������� ������������ ���������� �������� �������������������������� �� ������ ������������������ ������������������������������������������������ ���������������������������������� ��������������������������
+ �������������������������������� ������������������������������������ ��������������������������
���������� ���������������� ������������������������������������������������������������������ ���������������������������� ����������������
+
��
+
+
+
+
+
+
��
��
+
+
+
+
+
����
+
+
+
����
+
+
+
+
����
+
+
+
+
+
+
��
+
��
+
+
!
��
+
��
��
+
+
+
+
+
+
+
+
+
��
+
+
+
����
+
+
+ ����
+
+
+
+
+
+
+ ��
+
+
��
+
#
+
+
+
+
+
+
+
+
+
+
!
+
+
+
!
+
$
��
+
+
+
+
+ �� ������
����
+
�� ��
����
����
+
+ �������� ��
+ ���� ��
+ �� ������ ����
+
���� ����
+
+ ����
+ �� ��
+
����
������
+
�� ��
��
���������� ������ �� ����
+ ��
����������
+ ���� ���� ��
������
+
+ ������ ��
�������� ������
������
����
��
+
��
+ ���� ������ ��
��
����
����
����
+
�� ����
���� ���� ��
+
��
��
��
����
+
������
��
"
) 4 -
+ $ % $
) $
* 1 "
! �� 0 . % " % '
) ( '
+ % $
!
% 6
& ��
%
7 5 $
( ' $
" $
2
!
! ( > 8 (
���� , , )
" $ / 6
& ) "
' # & 6 & "
! $
% 1 , % 0
* 1 . - ) "
�� ' 1 !
" +
) 4 $
&
' ( , & "
& ( * ����
# " # % # . # % #
- $ !
. * # # , &
(
" ! " ( $
&
! )
" + # " $ # 4 *
+
, 4 6 1 * 4 7 3 * !
% ) + , + . ! # !
$ * 2 + % $
# + & ��
' & / . 5 ; 4 $ # , # " . ( '
# . 2 - ) 4 . , " # ) $
& 7 ; ( , #
��
+ $
+ ������ # $
����
! ' & # ' !
+
!
����
'
+
+
����
0 +
��
+
# # ��������
�� ����
+ "
#
�������� # !
+
" ) $ ����
+
+ ��
( %
��
! &
$ # ����
"
���� ) !
+ ��
+
#
�� " ' ( / ���������� ! &
% $ " ��
! ��
+
����
%
+ ����
*
+
+
+
+ ��
�� !
+
+
- / ��
�� # ��
+ ����
+ %
�� # ( 2 $
" " &
!
(
�� ��
# /
, "
' / !
$ $ %
+
$ # ( !
!
! !
*
' * & " ( % !
" % %
( " * 0
$ ( ,
#
" " " $ &
! " & ! + . *
%
%
+
*
"
%
"
"
# / !
" . . '
!
"
# . 3 "
% ) 1
" *
# #
$
+
$ ! / ,
+
%
+ (
#
' ! ) * + $
6 $ #
"
#
$ ( $
" " (
! &
# & ! !
+ $ ! ! !
$ % * ) * $ % !
% * $ ' ( % + %
. 3 "
$ , + 0 % !
" " ) + + )
!
& & ' " ' + , 2 /
���� ! ! $
( $
$ #
'
!
! ! $
$ & 1 '
"
" $ # # - - *
) %
+ -
! !
5 * # ��
& . /
. - $
" # # &
! ! " ' 1
����
!
$ - 0 )
%
% ( ( ' ' ! -
$ " %
" &
" ) +
+
&
$
#
#
+ !
# ) ! # # $ 0 / ( ( * ) #
& % " - ' " + / ( ) '
' 0 0 # ��
$ & ( * $ %
+ " * ' $
! * ) ( & / % !
" "
$
+
+
!
+
���� " !
+ ������
+
+ ��
+
+
����
+
+ ����
+
+
+
+
+
'
+ ��
"
��
+ ����
���� ��
����
����
+
��
+ �� �� ������ ��
������ ��
+
+
+
+
, ��
+
��
��
��
��
��
+
+
��
+
����
% ( $ &
#
( %
����
# !
'
" ! #
�� ��������
+ ������ ��������
��������
+
+ ��
����
+
+
+
+
��
+
�� ������
+
��
+
+
+ �� ��
��������������
������������
+
�� �� ����
+
& ������
+ ��
������
+
�� ������
+
������ ���� ���������� ���������� ����
��
+
+
+
����
+
���� ����������
+
�������� ��
������ ������ ��
������
�� ������
+
����
+
��
+ ���������� �� ���������������� ��
+ ��
�� ���� ��������
����������
+ ���������� ������������ ��
+
����������
+ �������������� ���������� �� ������
�������� ������������ ������������
��������
+ �� ������ ����
������ �� ������ ��
���� ���������� ������������
����
������
��
���������� ������
��������������
�������� ������������������������ ����������������������������������������������
+
%
! $
+
������
+
�������� ����������
������ �� ��
+
+
��
��
������������
�� ���� ������������
+ ���� �������� ���������������� ������������ ������������ ������������ ��������
�� �� �� �������������� ���������� ������ ����
+ ���������� ��
��������������������������
+ �� ������ �������������������������������� ��������������������
����������
+ ������������ �� �� �� ������������ ������ �� ���� �� ���������� # ���������� ����
+ �� ����
������
��������
������ ������ ������ �� ���������� ������������ �� %
+
+
+
��
��������
+
����
�� �� ����
+
+
+ ��
����
�� ��
����
+ ����������
����������
������������
���� ������ ����������
������������ ������ ������ ������ ��
+ ������������ ������������
������
�������� ������������������������ �������������������� �� ���� ������ ��
+ ������������
������
���� ����
+
��
( �������� �� ������
�� ������
������ ������ �� ������ �� ������������ ���� ������F + / 1 ; 8 # / 1 - % - > < 8 ] � � � � � 4 ��i��� ' 2 > 6 8 > H 9 ; N ^ l � p S f * + 1 C G T y � � t � � 7 ���� G 1 0 0 " * ( P Y p H R / + ? / !
$ 9 2
8 ; 2 Z D M
����
������0 3 %
+ ��������) X [ / 3 > )
< 9
+ : + 8 6 J ; . # F < " + " 6 �� ! ( N V <
( : A ? H 9 ����
$ ; - $ 5 ! +
1 # - , Q A D 0
+
, �� # ������
���� M R ��
& 0 H < ���������������� - ( ���� * % ) 7 7 H E E
������������, D <
+ ������������ ������ U $
/ 3 < I R N d Y Z U 8 > T < - 8 G N F 2 ��
+
+ ������
��
+ �������������� ��
������������������
" �� ������������������|�����|��������� ���� < ! ������������F���^���������W�`�8�p���" : ������ ��` � ] # ������ % 2 m � � ( ������u���6 P � ? �� .
{ ������� e� w _ : �� 3 3 P - 0 ] u z Q ? a � ������O � o h � � q � w S Z O ��t������ ] D � � � � � \ F ? F ��y�
� � j [ C i m J � m ^ f O . ' ? / * S { m p S A @ - & ? 8 = = = ) 5 D T S P x � � � � � n ������ 2 Q [ B 5 H T H M i � � � � h d 5 5 . @ 4 ` s � � � � � � A ���� N / 8 E K c i � � � ` ] 4 2 5 # & C ] a " B < < S > P �� 4 8 !
��3 * ' * �� 0 5 U k / ���� 5 3 1 1 / - Q c I ; 9 7 A 1 3 2 . 2 R ] W [ B +
> G H < 4 J Q 3 2 # # . ? V t S ����2 D L , % B J W 1 E P 6 ; > i i d ����+ ; [ B ! 5 �� 6 �� k { @ 5 5
% P Q ���������� [...]
+ ������
?
���� 1 %
�� �� ������������ B A W �� �� ��������
��
C W R B 3 2
����������������v�{����������� �� Q R
����������]�Y�\�|������������������� ,
9 P M B } e B ����
8 P 0 ? D + ( 2 * 2 - A Z ^ S 6 C @ V A ) X \ � � � F 5 ����: B S Q Q g h � � g N 0 4 N A B > G R [ m � � } z X ' C \ ? u g 6 U P Z l p W F I r b M K 4 \ r ] c � � � g T b q i L I e i _ l q y [ A 7
! 6 ' ) : 7 7 * " 0 E K P w � � � � � ] ����������
/ 6 7 G N V > = ] { � � � G O 1 ; - K Y � � � s � � K ������
8 ! " , ( " P w s 4 ; $ # % ) B 9 ��" 3 , 6 2 ���� �� ��
+
������ ����. 2 ��
- & # D D ! ) ) , B ) # " ' @ B A D ��
��
" # ( * + 9 A
���� $ )
������ 8 " $ 1 L < ? ���� / '
��
�� " ����@ c ! ���� 6 J 8 ������������
% 2 $
������ ! Q V L \ 4 ! ��������
4 G P ������������������ % ^ M - < 3 9 6 V O j \ ] S < . K 4
4 9 R J 8
�� ��
' ������.
�� �� ������������
$ ������������ �� �� ) 3 1 3 $ 2 %
��������������u�w�����������
�� F 1 ����������I�Y�y���������������������
$ 9 ; j \ A ���� ����
Q I ) + ����
$ B
. # ��( C � � b .
���� 0 6 B H M Z g Y H .
)
$ - / H < D a X L f h , �� 8 S K ' $ ? + A d a = + / c > . B ) U @ - X j W b N D X D " L Q ; ; K T f H : $ ; M J G Q S O E / 9 I e f d � � � � � � m ���� ! * J T Q d i n W Y p � � � � c l 9 3 R ] 0 H b q � � � � � � P �� + L : 5 < A @ = Z � ~ N Y G 3 H B & + ( + B Z Y + > K F O 7 K 6 4
) 3
9 1 ( 4
$
E J ' ) + 0 = > % 2 4 T U 5 5 0 4 ? E [ I B > B \ V V [ ,
* $ , 5 , / [...]
* A o h 2 B O I Q N f [ } r p d P B W D 8 F L b a N % ��
( # : ( �� H / !
#
����
�� 6 . - ) " ����
$ ; C 9 = 3 ; '
���������������������������� P G $ ��������T�c����������������������� , " . J O � n V �� %
+ " a Y > ;
. D + : 1 / )
: [ � � k 7 % ����* ) 9 B O ] R b q h Z 5 + = ( , > ; N A K c f Y f ] 1
J R T E > Q = P f m N = A p L ; M * < c V E e y i k Y I W H , , O ] 9 ; H T
����������������������������������~�������������������������������������������x���y����������������������������������������~�����z�|�~�x�r�t�t�v�w��y�|���s�n�u��k�x�f�r�|�o�r�k�q�y�p�e�b�i�o�o�^�_�g�k�h�k�j�d�h�]�d�f�\�S�\�X�]�V�c�W�c�Z�_�U�R�V�W�V�P�L�J�J�A�A�L�D�D�7�H�J�J�H�Q�P�P�H�D�D�<�H�H�P�D�>�4�6�=�9�>�;�2�5�E�<�C�@�4�8�.�.�!�.�9�%�'�0�>�?�=�8�<�B�6�@�4�<�=�>�4�4�=�*��*�8�D�G�D�4�<�A�B�D�H�>�J�R�V�N�L�T�V�_�e�R�L�T�Z�a�`�p�e�Y�n�n�l�b�b�Z�j�s�j�{�����n�j�d�b�Z�p�v�z�}�x�|�l� [...]
+����������������y�k�d�`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+ ��
����
+
��
������ ����������
+ ������ ���������������������������������������� �� ������������ ������������ �������� �������������������������� �������������������� �� �� ���� �������� ���������������������� ��������
+ ������ ��������������
������
��
+
������ ������ ���������������������� ������
������ ���������� �� ���� ����
������������ ��������������
+ ����������
+
+ ���� ������������ �� ���� �� �� ������������ ����
���� ��
+ ����������
��
�������� ������������������������
�� �� ���� ���� ���������������������������������� ���������������������� �� ������ ��
+ �� �� ���� ��������
+
+
+
+
+
+
" / $
" '
% ' 0 ( $
# &
+
+ ��
+
�� ��
����
+ ��
��
"
+
������ # #
+
#
+
#
! ( (
����������
% $ !
+ ��������
+
!
��
+
+
��
��
+
+
+ ������
+ ���� ���� ����
+ ������������
���� �������������� ��������
��
+ �� ���� ���� ������������������
������ �� ���� ��
���� ���� ��
+
+
�� ��
+
+ % &
*
! )
) , )
'
+
+
��
����
��
��
��
+
�������� �� ) ) �� ����
���� ��
��
(
����
���� �� ���� ������
"
!
�� ��
�������� ���� ������������ �� �������� ���� ��
���� ������ �� �� ��
+
������ ��
�� ����������
����
�� ���� ����
����������
+ ���� �������� ����
������������������
+ ������
�� ���� ������������������ ������������ ���������������������������� ������ �� �� �� �� �������� ��
+
+
+
+
+
�� ��
$
% ��
+
+
�� ���������������� ��
������������
+ ������������
����
+ �������� ���� ������
������������
+
���� �� �� ����������������
��������
��
+ ����
����
����
+ ������������������
+
���� ���������� ������ ���� �������������� �� �������� ���� ��
+
+
����
+ ���������� �� ���������� �� ������������ ������ �� ��
+ ������������ ��������������
+ ���� ����������
���������������������������� �� ������ �������������������������������� ������������
+ ���������������������������� ������ �� �� �� ��
"
+
+
- !
$
" $ . & #
& &
��
����
�� ����
��������
���� ��������
�� ��
+
+
+
+
���������� ����
��
������
"
�� ����������������
���������������������� ���� ����
+
���������� ��������
���� ��
+
+ ����
+ ������ ��
���������� ������������������ ���������� �������� �������������� �������������� ���� ����������
+
���������������������������� ���������������������������������������������������������� ������������������������������������ ��
+ ��
+ �� ������
"
+ ��
+
+
+
" % " . "
# )
$ ' 2 $ $ #
& ! * * #
!
+
+
��
��
��
!
+
+
- -
+
+
��
+ % & $ %
+ �� �� ����
(
�� ��������
+
+
����
��
+ ����
+
+
��
��
��
+
������ ��
+
���� ����
���� �� ������ ���� ��������������������
+ �� ������ ������������������������������ �� ���� �������������������� ��
+ ������ ����
���� ������ �� ���������� ��
�� �� ��
��
+ �� ��
��
%
(
# #
+
��
+ ����
�� ��
�������� ���� ��������
+ �� ��
+ ����
+
+
+
����������������
����
+
����
+ ������
���� ���������������� ��
+
������������������������ ������ ������ ����
�������������� ��������������
+ ������������
���� ���������� �� �� ���������� ���� ������������ ���������������� �� ������������
+ ���������������� ��������������������
+ ���������������������������� ���������� ���������������������������������������������� �������������������������������������� ��
�� �� ����������
!
+
+
+
+
,
#
% ( 0 + ) #
" "
+ ������ ��
+
�� ��
����������
����
�������� �� ����
����������
����
+
+
+
+ �� ��
��
��
��������������
+
�������������������� ���� ������
������������ ��������
+ ���� ��
��
��
�� ��
�� ���������� ������ ��
����
����������
+
�� ���������������������������� ������ ���� ������������ ���������� ������ ����
+ ������������������������ ������ ������ ���� ���� ���������� ��������������
�� �� ���� �� ����
�� ��
+
+
*
! ' !
��
��
+
�� ������ �� ���� ��
+
+ ������������
+ ����
+ ����
�� ��
+
��
+ �������� ����
+
+
���������������������� �� ������
+ �� ������������ �� ����������
+ ������������
+
�� �� �� �� ���� �� �� ������������ �������� ���� ��
+ ������
+
������������ ������������������
�������������������������� �� ���� ������������������������ ������������ ���������������������������� ������ ��
�� �� �������� ����������
+
"
+
+
+
+
+
+
$ % - ' #
+
+
+ ������
+
��
+ ������
����������
���� ������
�� ��
+
+
+ ��������������
+ ��
��
�� ��
��
+ �� ���� �������������� ��
���������������������� ������������ �� �������������� ��������������
������������
+ ������
�������� �� ���������� ������������������������������ �������� ������������
+ ������������ ��������������������
���������������������������� �������������������������������������������������������������������������������������������������� �� ��
+ ���� ����������������������������
#
/ &
% & ( ! * / 0 8 5 0 '
!
"
+ ��
+
+ # )
�� ����������
���� ������
#
+
��������������
+
+ !
+
+
�� ��
���� ���������� �� ����
+ ������������ ��������������
+ ����
��
�� ��
+ ���� ���� ������������������ ���������� ���� �� ������ ����
����������
+
���� �������� �������������������������� ���������������������������������������������������������� ���������������������������� ��������������
�� ������ ����������
+
+
+
+
0 $
" # $ ) ) / - ) "
+
# ( &
+
+
+
+
����
+
+
+
+ ��
+
+
# (
��
�� ������
! ��
��
+
+
������
����
+ ��
+
+
��������
����
+ �� �� ���� ������ ���� ������������������
+ ������������������������������������������������������
�� �� ����
+ ��������
����
+
'
' & "
+
��
������
+ ��������
+
��
+ �������� ������������ ������
������
+ ��
+
+ �� ���������� ����������������
������
��
�� ��
����
+ ������������ �������� ���� ����
��
+ ���������������������� ����������������������
+ ������������������������������ ������ ������
����
�������� ��
+ ���� �� �� �������������� ���������� �������� ������ ����
+
����������
�������������� �������������� ������
���������������������������������������������������� �� ������������������ �������������� ����������������������������������
#
+
+ ��
+
+
��
+
0 %
! $ * ) 3 0 , #
������
������
�������� ������������
+ ��
+
!
���� ���������� ������������������ ������
+
+
+
+
+
+ �� ��
������ ������ ��
���� ����
+ ��
+
���� ���������� ������������
������ �� ����
��
+
�� ��
+ �� ������������ �������� �������� ������������
����������
+
�� ������������ ��������
���������������������������������������������������������� �� ������������������ ���������������������������������������������������������� �������������������������������������������������������������������������������������������������� ������ ��
+ �������� ������������������
���������������������������������������������������������������� ������������������������������������������������������������ ���������� �������������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������
+ �������������������������������������������������������������������� ��������������������������������������������������
+
�������������������������������� ���������������������� �� ���������� �������������������������������������������������������������������������������������������������� ������������ �������������������� ���������������������������� ����������������������������������������������������������������������������������������������������������������������������������������������������
�� ����
�� �� ���� ��
*
"
* ) $
��
+
������
+
+
��������
������������
����
+
+
+
+ ������ ���������� ��������������
�� �� ��
���� ��
����
������
������ ����
���� �� ������������������ ���������� ���� �������� �� �� �� ����
���� ��
+
��
+ ������������ ���� �� �� ��������
�� ���� ������ �� ������
�������� ������������������������ ���� ���� ������������������
������ ������ ������������������������������������������ ������ �� ������������������ ������������������
+ ������
+
# �� ������
+
�� �� ���������� ���������������� �� ���� ������ ���������������������������������������������������������������������� ���������������� ��
������������ �������������� ��������������������
������������ ������ ���������� �� ����������
�� ����
+ ����������������������������������������������
���������������������������������������� ����
������������������������������ �������������������� ������ ���������� ������������������������
+ ������������ ������������������������������ ������������������������������������������������ �������� ����������
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ���������������������������� ��������������������������������������������
������
+
+ �� ������������ �������� �������������������������������������� ��
�� �� ������������������������������������������ �������� ����������������
���� ��
+
��������������������������������������������������
+ ������������ ������ ��������������
���������������� ������������
+
��������������������������������������������������
��
���������������������������������������� ����
�������������� �� ����������
+ ������������������ ������ ���������� �������������� �� ��
���������� ������������������������������ ���������������������������������������������� �������������������� ���������������������������� ���������������������������������������������������������� ������������������������������������������������������������������������������������ �� ���������������� ���������� �������������������������������������������� �� ������
�������������������� �� ������������������������������������������������������ ������ ���������������������������������������������������������������������������������������� ���������������� ���� ���������������������������������������������������� �������������������������������������� ������������������������������������ ���������������������������������������������������� ���������������������������������������������������� [...]
+ ��
�� �� �� ����
!
+
+ ��
��
+ " * !
+
+
+
�� ������ ��
���������� ������������ ����
�������� �� ����
����
����������
+ ��
+
+
��������
��
�� ����������������
+
���������������������� ���� ����
+
�������� ����
��
+ ������
��������
���� ��
�� ������������ ���������� ���� �� ������������ ��������������
�� ������ ���������������������������� ���������� ���� ���� ������ ���������� �� ����
+
+ ������������������������ �������������� ���������������������� ���������� ��
������������ ���� ������ ��
+ ����
+
- "
! ' ) / & %
#
+ ������
#
��������
+
��
+ ����
!
��������
+
%
! #
& ! ���� ������������
+ "
+ �� ��
����
+ ����
+ ������������ �������� �� ���� ����
+
������������
���������� ��������
������ ��
+ �� ���� �� ��
+ ������������������ ���� �������������� ���� �� �������� ����������
��
+
+ ��������
��
+ #
" ! * $ #
+
������ ������ ���� ��
+
+ ������������ �������������� �������� �������� �� ����
+ ���� �������������� ����������������
+
+
+
����������
+
�� ����
���� ��
��������������
+
�������������������� �� ��
���������� ���� ���� ��
������ ������
���� ����
�� �������������������������� ���������������������� �������������� �� ���������������������������� ������������������������������������������ ���� ��
+ ������������������ ���� ������
�� �� ��
+
+
- "
% ' . ( '
+
" #
�� �� ��
��������
+
+ ������������
�� ������
+
+ ��
+
��������
������ ��
��
��������������
+
���������������������� ����
�������� ��������
����
���� ��
+
+ ��
�� �������������� ���������� ���� �� ������������ ������������
�� ���� ���������������������������� ���������������� ������������ ���������� ������ ����
+ �������������������������������������������������������������������������������� �� ������������ ���� �� ������������������������������������ ������
�� ������ ���������������������������������� ���������������� ��
���� ���������������������������������������������������������������������������������� ������������������ �������� ���������������������������������������������������� �������������������� ��������������
���������������������������������� ������������������������������������������ �������� ������ �� ����������������������������������������������
������������������������������
+ ���������������������������������������� �������������� �������� ���������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������������������������������������������������������������������������������� ������ ���������� ���������� ����������
����
+
+ ��
����
'
# " * $ #
+
�������� �� �������� ��������������
+
+
������������������������������ �������� �������� �� ����
+
+
+
+
+
+ ���� �������������� �������������������� ������
+ ��
����������
�� ������
+ �������������� �������������� ��
+
����������������������������������������
����������������������������
������������������ �� ������ ������������ �� �� ������������ �������������������������������������������������������� ���������������� ��������������������
+ ���������������������������������������������������������������������������������������� ������������������������������������ �� �� �� �� �� ����
#
+ ��
+
+
+
����
+
*
$ & * . ) *
+
������ ��������
+
+
������������ ���������������� �������� ��������
!
�� ���������� ��������������
+ �� ����
���������� ������ ��
������ ��
���������������������� ��
���� �� �������� �� ��
������
����
+
�� ��
�� �������������������������������������������������� ������������
������������ ���������� ������������������������������ �� �� ��
�� �������������� ������ ������ ����������������������������������
+
+
+
+ ����
+ (
# $ * + 3 . - %
������ �������� ���� # �������� �������������� �������� �������� �� ����
+
�������� ����������������
+ ����
+
����
+ ������ ���� ��������������
+
+ �������������������� ���� ������
����������������������������
+ ����
���� �������� ��
���������� �� �������������� ���������� ���� �� ������������
+ ������������ ������������
���������������������������� ���������������������������������������������������������� ���������������������������� �������������� ������������������������������������
+
+
������
'
! " ( ( 0 , * #
������������������������������ ��
���������� ���������������������������� �������� �� ��
���� �������������� ��������������������
������
+
�� ��
+ �� ������
������������������ ��������������
+
����������������������������������������
���������������� ��������
+ ����
+
������
+ ���������� ��
+ ���� ������ ������������������������������������������������������ �������������� �������������� ���������������������������� ���������������������������������������������������������� �������������������� �� �������������� ����������������������������������
��
+
+
+ �� �� ���� ��������
+
#
# # , $ %
��
������������������������������ ��
+
+
+
+ ������������������������������������������ ��������
+
+ ����������������������������������������������
������
+
+
+
+
+ ���������� ������������
������������������ ������ ����
+
+ �������������������� ��������������
������������ ��������
�� ��
+
������
+ ��������
+ �� ��
���� ���� �������������������������������������������������������� �������������� �� �� ���������������������������� ������������������������������������������ ������������ �������������������� �� �������������� ������������������������������������
#
+
������
*
" $ %
& , . 8 0 . %
+
�������� ������������������ ����
+ $ ���������� �������������������������� �������� �� ������
�� �������������� ��������������������
+
������
+
��
������
������������������ ��������������
�������������������� ��������������
+ ����������������������������
����
����
���������� �� ��
���� ���� ���������������������������������������� ������ ����
+ �������������� ��������������
���������������������������� ���������������������������������������������������������� ���������������������� �� ������ ������ ���������������������������������� )
+
��
. $
& & ' " ) . 1 9 4 2 +
������ ����������������
+ ! " ! # ' *
+ ������ �������������� ������
����
%
!
+ ���������� ������������������
+
+ ����
+ !
+ ������ ����������������
������
���� ������������ ���� ��
������������ ����
+
����
+ ������
�� ��
+ �� ������������ ���������� ���� �� ������ ����
������������
���������� ������
������������������������������ ���������� ���� ����
������������������
�������������� ����������������������������������
#
��
+
����
* "
! $
$ ' * 0 * ( "
������ �� ��������
�������� �������������� ���� ����
+
+ "
���� ������������ ������������������
������
+
��
���������� ���� ������ ������ ��
+
+
�������������������� ��������������
������������ ��������
����
���� ��
+ ���� ��
�� ������������ �������������������� ������ ����
����������
������ ���������� ������
���� ���������������������������������������������� ���� ������������������
+ �������������� ���� ���� ������������������������������
�������������������������������������������������������������������������������������������������� ���������������������� ������������������������������
���������������� ���������� ���������������������������� ������������������������������ �������������� ������ ��
+ ��
+
+
+
( & ' / ,
+
+
����
+
+
+
+
#
+
+
+
+
+
+
+
+
+
�������� �� �� ������ �������� �� ���� ���� ������
�� �������������� ������ �������� ���� ��
��
��
��������
�������� ������ �� ��
���� ��
�� ��
������������ ��������
+ �������� ���������������� ������������������ �������� ����������
����������������
+
+ ��
+
+
��
������
����
����������
����
������
+ �������� ������������ �� ���� ����
������������
����
+ ���� �� ���������� ��������
�������� ��
�� ��
+ ���� ������������ �������� �� ��������
�������� ���� �� ���� ����������
+ ������ ���� ������ ������ ������ �� ����
�� �� �� �� ��
+ �� �������� ���� ����
+ �� �� ������ ����
$ ���� �� ���������� ���� ���������� �� ������
+
+ ����
��
+
���� �� ��
+ ��
+
������ ������
���� �� �������� ������������
+
��
�������� ��������������
+
+
���� ������
�� ��
���� ���� �������������� ���� ����
������ �� ������������������������ �������� ��
�������������� ���� �� �� �� ��
+ ��������
����������
+ ���� ����������
�� ��������
+ �� ��
�� ��������
��������
+ ����
+
+
+ ��
�������� ��
����
+
+
,
! (
$ / $
" !
# # . ) ) %
& % , + . % $ % " ' & $ ! $
$
!
' % #
"
"
# !
) "
& ) "
# ) 3 1
!
+
��
&
!
! #
"
��
+ �������� ���� �� ������ ��������
+
���� �� ������ ������ ������������ �������� ��������
��������
+ �� ��
�� �� ������
����������
������������ ������ ������ ���� ���� ��
+
�������� �������������� �������� �������� ��������������
������������������ �������� ���������� ������������������
+ ���� ���� �� ��
+ ����
+ ���������� �� ������������������ ������ ������ �� ���������������������� �� ����
�������������� ������
���������� ���� ������ ���������� ����������
+ �� ���� ������������ ���������������� �� ���������� ������������������������ �� ������������ ����������������
+ ��������������������������
���������������� ���������������� �� ���� ��
���������������������� ����������
�������� �� ���� ����������
�� ����������
�������� ������������
���� ����
���� ������
��
����
������ ��
�� �� ��
+ ������
������ ��������
������ ���� ������ ������
+
+
���� ��������������
+
��
+
����
& % ��
+ �������������� ���� �� ������ �������������� ������
�� ������
������������
������
+ ������������������
������
���������� ���� ������������
���������� �������� �� ���� �� �������� ������������
+ ����
���������� ��������
+
+ ������ ������ ������ ����
������������ ���� �� �� ������
�� �� ����
+ �� ������������������ �� ��������
+ ������
�� ��
+
+ ����
+ ������
+ �� �������� ������ ���� �� �� ����
��
������������ �������� �������� ������ �������� ��������������
+ ���� �� ���������� ������������������
��
+ ������ �� ��
����
������ ������������������ ������ ������ ��
���������������������� ���� ����������
+ �������������� ������
+ ������������������������ ��������
���������� �� ���� ������������ ���� ������������ ������
+ �������� ���� ������������������ ���� ��������
�������������� ���������� �� ���������� �� ���� �� ���� �� �������������� ���� ���� ���� �������� �� ��
"
+ ���� ����������
+
���������� �� ���� ������%
��
�� ���� ������������
, ������������������
+ ��
�� ����
����
+
+
�� ������ ��
��������
���������� ����
+ ���� ��
���� �������� ��������������
������ �� �� ����
��
+
������
+ ������ ������������ ������
+ ����������������������
�� ��
+ ����������
+ ��
��
# ���� ���� ��
�� ��������
+ ������
+
��������
�� �� ���� ����
+ �� ����
��
��
�� ����
������������ ��
�� ����
������ ���� �������� ����
�� ���������� ���� �� ���� ����������
���� ����
���� ������������������������ ��������
+ ������
+
�� ������
���������� ������������ ���������������� ��
�� �� ������
�������������� �������� �������� �������������� ����������������
�������� �������������� ��������������������
+
������ ���� ����������
+ �� ����
�� ������
�������������� �� ���������������������������� ������
+
���������������������� ������������������
�������������� ������
�������������������������� �������� ���������� ��
+ ������������ ������������������ ���������� ���� ������������������ �������������� ������ ����
�������������� ������������ ���������� ���� ���������������������� ������ ���� �������������������������� �������������� ��
�������������������������� �� �������� ���������� ���������������������� ����������
���� ����
��
������������
������ �������������� ������ �������� �� �� ������ �������� ��������������
������
+ �������� ������������ ������ �������� ����
������ ���������� ������������ ����
������ �� ��������
��
+ �� ��
+ ��
�������� ���� ������������������ ������ ������ ��
����������������������
������ ������������������������������������ �������� ���� ���������������������� �������� ������������������ �������������� ������������������ �� ������ ������ ���������������� �������������� ������ ���� �� ���������� ��������������
+ ������ ���� �������������� ������ �������������� ����������������������������
������
��
+
#
+
+ ����
+ #
* & !
+
����
+ �� ��
����������
+
������ ������
����
+
+ ����������
������������������
+ ������
+
+
��
���������������� ����
��
+ ����������������������
�� ����
�������������� ����
+ �� �� ������ ����
+
+
�� ������
+ �� �������� �� �� ��
����������
�� �������� ��
�� �� ����
+
+ �������������� �� ������������ ��������������
������������������������ ������ $ ������������ �� ������������������
+
���� ������
&
+ �� �� ��
�� ��������
+ ���� ��
������������ ���������� �� ��������
+ ����������������������
+
������ �� ������������������������ �� ��
+ ������
������������
����������������
������
��
��
+
+
+ ����
(
+ ������
+ ������������
+ ��������
-
�������� ������������������
+ ��������
+
������������ ��������
�������������� ������ ��������
��������
+
+ ����������
+ ������������������������������ ������������������������������
����������
+
���� ��������
������������ �� ����������
���������� ������������������ ������ ������ ������������
����
������ ������
+ �������� ���� ���������� �� ��
������
����
��������
����
��
+
������ �� ������
���������������� ��
�� �� ����������
+ ������������ �������� �������� ���� ��������
������������ ��
+ �� ���� ������������ ������������������ ������ ������ ��������
�� ��
+ ����
���� ������ ��������������������������
��
�������� ������������ ���� ������ ��
�������������� ��������
+ ���������� ������ �� ������
����������
+ ��
����������
+ �� ���������� ����
���������� ���� ��������������
+
���� �������� �������������� ����������
������ ���� ������������ ���������� ������ ���� ������������������������
������
+ �� �� �� ��
#
+
+
+
+
������ ��
!
) !
+
+
+
������
+
���� ��
+
+
������
+ �������������� �������� �������� �������������� ������������
+ �� ���� �������������� �������������������� ������ ������ ����������
����������
+ �� ���� ������ ������ ��������������������������
��
���������������������� ���� ������ ��
�������������� �� �������� �������������������� �� ������ ������������ �� �� ���������� ������������������������������ ������������������������ �� �������������� ������ ��������
+ ���������������������������� ���������������� ������������������������ ������ ����
������������������������ ������ ����
+ ������������������������������������
������ ����
+ ������
+ ����������
����
+
���� ����
������
������
+ ���������������� ������ �� ���������� ������������ �������� �������� ���� �������� ���������������� �� ���� ���������� ���������������� ������ ������ ���� ��
�� ��
��
���� �� ��
+ ������������������ ������
���� ���������� ���� ����������
+
�������������� �� ����������
������������������
������
������������ ��
���������� ������������������ ������ �� �� ������ ����
��������������
+ ������������������
��������������������������
+ ���������������������������������������������������������� ���������������������������� ���������� �� ���������� ������������ ���� ������
�� ����
+
+ ��
+
+
+
+
(
+ ! ����
����
$ #
+
+ �� ��
��������
+
+ �� ������
�������� ������������ ����������������
+ ������
�������� ��������������
���� �� �� �� �� ��
������
+
���� ����
+ ����������������
+ �� �� ���� ���������� �� ���������� �� �������������� ���� �������� ��������������
����
���������� �� ��
��
+ ��
�� ���������� ����
+ ��
+ ����
+
��������
������ �� �������������� ������
�� ���� ���������������������������������������� ������������������������ ���� ������������������������������������������������������ ����
+ ����
�������������� ������ ��������
������
"
��
+ ���������� ������������������ ��
+
+
������������������������������ �������� ������
��
���������������������������������������������� ������ �� ��
+ �������������� ������������ �������������������� �������������� ������ ������ ��
��������������������������������������������
������������������ ����������
+ ������������ ����
+ ������ ������������ �� �� ������������ ���������������������������������������������������������� �������������� ��������
+ �������������� ������ ���������������������������������������������������������� ����������������������
+ �������������� ����������������������������������
������ ����
�� ���� �� �� ��
+ "
! $ %
������
+ ��
+
+
+ ���������� ������������ ��
+
+
+
������ ����������
���������������� �� ��
+ ������
+ ����
+ ��������
�� ����
+
+ ���������� �� ��
+ ��
+ �������������������� ���������������� ������������
�� ������
+
����
+ ����
��
+ �� �� ���������� ���������� ���� �� ���� �� ��
���� ������
+ ����
+ �� ���� �������� �������� ����
�� ������������������
�������������� �� �� �������������������� �� ���� �� �� ��������
�� ���� ���� �� ������
+ ��
+
!
+
��
�������������� ������ ���������� �������������������� ���� ����
�������������� �������������������������� ��������
������������ ������������������������������������������������������������������������������������������������������������������������������������������������ ����������������
+ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ��
[...]
(
+
��
�� ����
#
" % ! ��
+
+ ������
����
��
+
+ ���� ������
+
������������
+
��
+ ���� %
+ �������� ���� ������������
�� ��
+
+
+ ��
��������
����
����
+ �� ������
+
+
����
�� ������ ������ ����
������������ ��������
+ ����
+ ����
�� ������������ ��������
+
+ ��
���� ����
+
�������� ��
��
+ �� ��������
�� �� �� ��������������
����������
+ ���� �� �������� ���� ����
&
+
���� %
%
������
�� ������
+
+
����������
�������������� �� ��
+
+ ����
+
+
������ �������� ��������������
����
+
����
����
+
+
����
+ ������
���� ����
+
��
����
+
���� ��
����
��
������������
������������ �� �� �� '
��
��
+
+
+
���� ��
��
�� ����������
+
��
���� �������� ��
������
��
+
)
*
& !
' - + 0 1 " ! $ ) ) + * * "
0 !
' 0
$ ) )
! # , $
# . #
) ,
3
+ ���� ��
������ ! # %
����) ����
+
&
#
��
( ' ( #
$ $
$ $
,
+
!
+ �� $ -
% $
#
��
" '
+
+
# ��
# & (
&
# $ + * ' & ��
& % * &
����
)
" !
& 5 4
+
"
��
% ! ����
! ��������
+ # !
!
$ 5 "
&
% ! * $ ��
�� ���� ��
+
'
+ ��
$
!
+
������
��
+
+
���� ��
���������� ��
+ �� ��
+ ���� ��������
�������� ��
+
+
����
+
��
������
��
+
+
+
+
+ ���������� ���������� �� �� ��
��
�� ��
���������� ��
�� ������
+
�� ������ ��
+
������������������ �������������� ����������
������ ��������
+ ��������
������ ���� ������ �������� ������������
����������
+ �� ����
+ �������� ������ ���� �� ������
���� �������� ������������������ ���������������� �� �� ���������� ��������
���������������������������� ������������������������������������������������
�������� ������ ������������
�� �������������������������� ������������ ���� ������������ �������������� ��
������ ���������� ���������������� �� ���������������� ��������
+ ����������
+ ������ ��������
���� ������ ������
������������������������������ �� ���� ����������
����������������
+ ������������������ ���������������� ���������������������������������� �������� ������������������ ���������������������� ������ �� �� ���� ���� &
+ ��
+ ���� '
+
#
��
+
+
��
��
1 �� �� ��
�������� ����
��
+ ���� ����
+ ������ ��
��
+
�� �� # !
+
����
+
+
��
��
4
+
+
+
��
+
��
+
�� ������ ����������
$ ��
���� ��
��
��������
+ �� ��
�� �� ��
�� ����
��
���������������������������������� �������������������� ���������������������� �������� �������������������� ������ �������� ��������
+ ��
��������
+ ��
+
�� ����
+
+ ����
�� &
���� ��
����������
+ ��
�� ����1 ����
+
������
+
����
��
��
��
������ !
��
+
+ ���� ���� ��
�� ������ ������ ����
" ������ ���� ��������
��
����
��
+
+ ���� ���� ������������ ��������
��
������
��
����������
+ ���� ����
���� ������ �� ����
�� ��
����
���� �� ��
"
��
+
+ ��
$
+
��
+
��
+
+ ��
��������
+
��
���� ����
+ ��������
+
+
+
+
+
��
+
+ ������
! $
+
+
+
+
+
+
+
����������
+ ������
+ �� ��
�� ��
���������� ���� �� ��������
���������� ��
+
������
+
��
������
���� '
+
+
����
���� " '
+ ����
+
+ ��
����
!
��
��������������
"
�� ����
���� ����
��
+ ��
%
���� + '
+
������
������
+ ��
��
��
! #
"
+
����
������
+
+
+ ������
!
����
������
+ ����
+
���� ����
+
��
����
+ ����
����
+
%
+ ����
+
"
+
�� ��
+
�� ��
+
������
��
+
+
����
����
+
+
+ ! "
+
��
+
����
����
����������
+
+
+
+
+
����
��
+
+
������������ �� ������ �� ������
+
��
+
+ ��
�� ��
������
+ ����
+
+
��
+
+ ��
+
������
+
�� �� ��������
�� ��
+
�� ���������� ����������
+
��
!
��
+
+ ��
+ #
+
+
����
!
%
+
+
+ ���� !
+
& &
! % )
$ /
! " & $ '
! ) '
$ " # #
)
)
#
! & #
( # &
#
+
"
% !
%
! - ,
& '
%
# !
% *
(
%
# & ' + %
" $
* -
+
*
$
$
+
+
+
+
+
+
����
+
+
+
+
��
% "
��
+
+ ��
��
+
+
+
+
+
+
��
+
$
+
+
+
+
���� �� �� �� ����������������
+ ���� ����
+ �� ���� ����
������ ������ �� �������� �� ����
���������� �� ����������
����
+
�� ��������
���������� �������� ������ �� ������ ��������������
���������� ������������
����������������
����
�� ����
+ ��
����
������ ��
������ �� ���� ������
�������� ������������
+
������������
+
+
���� �� ��
���� ������ ������������������ ���������� ������������������������ �������������� ������������ ���������������������������� ���������������� ����������������
������ �� �� ������������ �� �� ����������
+ ���� ���� ��������
�� �������� ������ �� �� ������ ������ ���������� ������������
������ �������� ��
+ ���� ��������
���������� ��������
+ ������ ������������ ����������������
���������� ���������� ������������������ ����
��
+
����
+ ���� ������ ��������������
���� ������
�������� ����������
������������
+ ���� �� ��
+ ������
+ ��
��
���� ���� ���� �������� �������� ������������������������ �������������� ������������ ���������� �� ����������
+ ������ �� �� ������������ ��
�������� ���������� ���� �� ������������������
����
+ ����
�������� ����
������
+
�� ���� ����
�������������� ���������������� ����
��������
+ �������������� ��������
������ �� �������� ��������������
������������������������ ����������������
������ �� ����
�� ������
+ �� ���� ������
�������������� ���� ������ ���������������������� �� ������ ��
+ ������������
+
����
�� ������������ ������������������������������������������������������������������������������ �������������� ���� ���������������������������� ���������������������������������������� ���� �� ���������������� ���� �� ���������� �� �� �� ����������
+
���� ����
��������
����
����
+
+
�� �� ����
���������� ������������
����
+
������
���������� ��������
������ �� �������� �������������� �������� ������������ ������������������
������ ���� ���� ��
����
�� �� �������������� ���� ������ ���������������������� �� ����
������������
�� ������
�� ��
+ ������������ �������������������������������� ������������������������ ������������������ ������������������
���������������������������� ���������������� ������������������
�������������� �� �� �������������� ���������� ������ ����������
���� ����
����������
����
����
+
�� ������
������������������������������ �� ����
+
+
+ ������
�������������� ��������
�������� �� �������� ����������
�������������������������� ��������������������
������ ���� ����
�� ������
������ ������ ���� �������������� ���� ������ �� ���������������������� �� ������ �� ������������
+
�� ������ ����
��
+ ������������ �������������������������������������������������������������������������������� �������������������� ���������������������������������������������������������������������� ���� ���� ���������������������������� �������������� �� �� �� �� ����
���� ����
���������� ��
+ ������
������
������ ���������� ������������ �� �� ������
+
��
�� ��
���������� ��������
�������� �� �������� ���������������� �������� ���������� ������������������
�� ���� ���� ��
���� ���� ���� ���������������� ��������
+ ������
���������������������� �� ����
������������
��
�� �� �� ������
��������
��
������������ ���� ������������ ���������� ���������������������� �������������� ������������ �������������������������� ���������� ���� ������������ ��
��
+ ���������������������� �������������� ���������� ��������������������
+ ����
����
������������ ������
��
+
+
�� ������
������������������������������ �� ��
�� �������� �������������� ���������� �������� �� ������ ���������� ��
�������������������������� ��������������������
������ ������ ������ ��
+ ������������ ���������� ���������� �������������� ������ ������
+ ���������������������� ������������������ �������������� ��
�� �� �� �������� ����������
+ �� ������������ �������������������������������������������������������������������������������� ��������������������
������������������������������������������������������������������������ ������ ���� �������������������������������������������� ���������� ����������������������
+ ������ ����
�� ���������������� ������ ������
����
�� ������
+
������������������������������ ������ ����
�� ��
������ �������������� �������� �������� �������������� �������������� ��
+ �������������������������� �������������������� ������ ���������� ���������� ��
������������ ����������
������������������ ���������������������������� ������ ��
���������������������� ����������������
�������������� ����
���� �������������������� ���������� ����������
+ �� ������������ �������������������������������������������������������������������������������� ��������������������
+
���������������������������� ���������������������������������������� ���� ���� ���������������������������������������������������������������������������������������� ������������������ �������� �������������������������������������������� �� �� ���������� ������ ��
�������������������������������������������������������������������������������������� �������� ���������������������������������������������������������������������������������������� ������������������������������������������������������������������������������������������������������������������������������ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+ ����
�������������� �� ������
+
+
"
+ ����
���������� �� ������������ ������ ��
+
+
���������� �������������� �������� �������� �� ������
+ �� ����
������������������������������������������������
������ ������ ��������
������������ ������������ �������������� ������������������ �������� ������
���������������������� ������������ ��
�������������� ����
���� �������������������������������� ������������ �� �� ���������������������������������������������������������������������������������������������� ��������������������
+ ������������������������������������������������������������������������ ������ ���� �������������������������������������������� ������ ������ ����������������
+
���� ������
������������������������������ ��������
������
+
+
������
���������� �� ������������ ���������������� �� �� ��
�������� �������������� �������� �������� �������������� ������ �������� ��
+ �������������������������� �������������������� ������ ���������� �������������� ������������ ������������
������������������ ���������������������������� ������ ��
+ ���������������������� ������������������
�������������� ��������
�������������������������� ���������� ������������ �� ������������ �������������������� ���������� ������������������������ �� �������������� ������������������
���������������������������� ���������������� ������������������������ ������ ���� ���������������������������� ����������������������������������������������������������! ��������������
+
+ ��������
���������������������������������� �������� ��
���� #
( ! ���� �������������� ����
����������������������������������������������������
+ ���� ������������������������������������������������������������ �������������������������� ������������������ �������� ���������������������������������������������������� ������������������������������������
������������������������������������ �������������������������������������������������������������������� ����������������������������������������������������
������������������������������ ������������������������������������������������������������� [...]
+ ���� �� ���� ������������������ ������ ��������
��
+
+
������
���������� �� ������������ ����������������
+ ���� ������������ �������������������������� �������� ���� �������� ���� ������
������������������������������������������������
+
������ ������ �������������� ������������ ��������������
�������������� ������������������ �������� ������
���������������������� ������������ ����
�������������� ��������
�������������������������������������� �������������� �� �� ������������ �������������������������������������������������������������������������������� ��������������������
������������������������������������������������������������������������ ������������ ������������������������������������������������������������������������������������ �� �������������� ���������� ���������������������������������� �������� �� ������
�� ��
�� �� ����������������
+ ������������������������������������������������������������ ���������������� ����������������������������������������������������������������������
���������������� �� ��
������������������������������������������������ �������� ��������������������������
+ �������������� ����������������
+
���������������������� ����������������������������
+ ������
���������������������� ������������������
�������������� �� ��������
+ ���������������������������������������� �������������� �������� ������������������������������������������������������������������������������������������������������������������������ ���������������������������� ���������������������������������������������������������� ���������������������������������������������� ���������������������� ����������
+
����
��������
����
!
& !
+
+
��
+
������ �������� ������ ����
+ ������������ �������������������������� �������� ���� ��������
+
+ ���������� ������������������������������������
������ �� ���� ��
+ ������������ ���������� �������������� ������������������ ����
�� ��
���������������������� ������������
������������ ��������
�������������������������������������� ������������
+ ��
+ ������������ ������������������������������������������������������������������������������ ��������������������
+ ���������������������������� ������������������������������������������ ������ ���� �������������������������� �������������� ����������������������������������
+
�� ����
������������ ������ ������
+
#
����
+ ������ �������� ����������������
�� ������������ �������������������������� �������� ����������������
+ �� �� ���������� ������������������������������������
������ ���� ��������
������������ ������������ �������������� ��������������������������
+ ��
+
���������������������� ������������ �� �������������� ��������
�������������������������������������� �������������� �� ��
+ ������������ ������������������������������ ������������������������ �������������� ��������������������
���������������������������� ������������������������������������������ ������ ���� ��������������������������������������������������������������������������������
+ ��
��
���������� ������ ��������
+
+
$
+ ����
+
+
+ ������������������������������ �� ������������������������������������������ �������� ����
+
������������������������������������������������
������
���� ���������������� ����������������
+ �������������������� �������������� ����
�� ��
+ ��������������������������������������������
+ ������������������ ����������
���������������������� �� ���������� �������������� ������ ������������ �������������������������������������������������������������������������������� ��������������������
���������������������������������������������������������������������������������������� �������������������������������������������� ����������������������������������
!
+
+ �� �� ���� ������
$
! " * # "
������������������������������
+
������������������������������������������
��������
+
+
+
+
+ ����������������������������������������������
����
+
�� ���� ������������ �������� ����
����
�������������������� ������������
����������
����
��
+
���� ������
�� �� �� ��������������������������������������������������
+ ��������������
+
������������ ���������� ������������������������������������������ ������ ���� ������������������ ����������������������������������������������������������
������������������ ���������� ���������������������������������������������������������������� ������ ��
+
�������������������������������������������������������������������������������������� �������� ���������������������������������������������������������������������������������������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+
�� �� ���� ������
+ #
&
+ ��
������������������������������
+
+
+
������������������������������������������
��������
+ ��
+
+
���������������������� ������������������
��
+
+
�� ������ ������������ ������ �� ����
+
+ �������������������� ��������������
����
+
��
��
+
���� ��
���� ��
+ �������������������������������������������������������� ��������������
+
�������������������������� ���������������������������������� ���� ���� �������������� �� ������ �� �� �� ���� �� ��
+
+
+
��
�� ����
+ ��
"
# ) / ) " #
������
+
# '
+ ���������� �������������� ��������
������
+
(
+ ���� �������������� ��������������������
+
���� ��
�������� ������
+ ����
�� �� �� ��
" " ���� �� ������
�� �� ��
��
����
����
����
���� �� ������������������������������
������������
�������������� '
+ ��������
+ ���� ����������������������������
+ �� ��
����
��������������������������������������������������
+
+ ��
+
+
���������� ������ ��������
+
+
+
+
+
���� ��������������������������������
�� ������������������������������������������ �������� �� ������
+ ���� ���� ��
+ ��������������������������������������������������
+ ������ ��
+ ����
�������������� ��������������
���������������� �������������� ���� ������
+ ���������������������� ���������������������� �������������� ��������
�������������������� �� ���������� ������������ �������� ������������ �������������������������������������������������������������������������������� ��������������������
+ ���������������������������������������������������������������������������������������� �������������������������������������������� ���� �� ������ ����������
+ %
+
+
+
����
"
#
+
+ ���������� ���� ��������
+
���������� �������������� ������ ����
+ ��
+
+
�������� ������������ ����������������
+
+ ��
������
��
��
���� ���������� ���� ����
+ ��
+
+
+
+ ����
+
�� �������������������������� ���������������� �� ���������� ���������� ������ ������������������������������
+ �� ��
������������ ��
+
�������������� ���� �� ���� ����������
+
��
+ ����
����
+
+
+
��
���������� ����������������
+
���������� �������������� ������ ������
����
��
+
+
�������������������������� ��������������������
+ ���� ��
+
������������ �� ������ ������ ��
����
��
+
+ ������
���������������������� �������������� ��
+ ������������
��
+ ������
��
�� ������������ ������������������������������������������������������������������������������ �������� ������ ������������������������������������������������������������������������ ������������ ���������������������� �� �������������� ���� �� ������ �������� #
+
+
+ ��
����
+
!
+
+
+
+
���������� ��������
+
+
�������� �������������� ������ ������
+
+
������ ������������ ����������������
+
+
+
��
+ ����
��
��
+
��
������ ������������ ���� ���� ��
+
+
+
����
+
���� �� �������������������������������������������������������� ��������������
+ ��
�������������� ������������ ���������������������������������� ������ ���� �������������� �� �������������� �� �� ���� ����������
��
���� ����
+
����
+
+ �������������� ����������������
����������
+ �������������� �������� ������ ������ ���������� ������������������������ �������������������� ������ �� ����
������������ �� ������
���� ������ ���� ����
������ ��
+ ���������������������� �������������������� ������������
+
+
+ ������
���� ��
+ ������������ ������������������������������������������������������������������������������ �������������������� ���������������������������������������������������������������������� ������ ���� ���������������������� ���� ���������� �� �� ��������������
��
+
+
����
����
+
+
+
+
+
+ ������������ ��������������
+
������ �������������� ��������
������
+ ��
+ ���� ��
��
�������� ������������ ������������������
+
����
+ ���������� ������ �� �� ��
+ �� ��
���������������������� ����������������
������
+
+
����
��
+ ���� ������ ���������������������������������������������������������� ������������������ ������ �� �� ������������������������������������������������������������������ ������������ ���������������������� ������ ��
��
+ $
+
+
+ ��
+
!
������
��
+ �� ��
+ ���������� ���� ��
+
+
������ ������
������������
��
+
+
+
+
���� ������
+
+
+
+ �� ���������� ���������� �������� ������ �� ������ ��
���������� ������
���� �������� ���������� ��
+ ���������� ��
+
������ �� ��
+ �� ����������
+
��
����
+
+
+
��
���������� ��������
������
+ ���������� ������ ������ ����
+ ����������
�������� ������������
��������������
+
+
+ ��
���� ����
+ ����
�� ����
+
��
������
���������������������� �� ����
+
������
����
+
���� ���� �������������������������������������������������������� �������������� ����
�������������� ������������ ���������������������������������� �� ���� ���������������� �� ������
�� ����
+ ����
+
+
+ �������� ������
+
�� �� ���������� ������ ��
����
+
+
+ ������ ������
������������
��
��
+
+
�� �� ������ �� ������ ����
��
+ ��
���� �� ������������������ ���������� ���������������������� �������������� �� ��
�������������� ������������ ���������������� ���������������� ���� ���� �������������� �� ������
+ ��������
+
��
+
+
+
+
+
+
+
�������� ������
�� ��
�������� ������ ����
+
���� ��
���� ��������
������������
+
+
+
+
�� ��
��
��
�� ��
+ ������ ������
+
+ ����
��
+
+
+
+
���� �� �� ������������ ���������� ������������������ �� �������������� �� ������������ ������������ �������������� ���������������� �� �������������� �� ������
+
+ �� !
��
+
+
+
"
+
��
+ ��
+
��
+ ������
+
��
+ ������ ������ ��������
+
+
+
��
+
����
+
+
+ !
+
+
#
+
����������
+ ������ �������� ����
�� ������
+ ���������� �������� �� ������ �� ��
+
����������
+
�������������� ���������� �� ���������������� �� �������������� ������ ������ ������������������������ �������� �������������������� ��������������������
+ �������� ����������
+
���������� �������� ���������������� ���� �� ������
��������
������ �������� ��������������
+ ���������������������������� ���������� ������������ ����������������
+
+
����
+
$
�� �������������� ��������
������ �� ������������������������ �������������������� ������������������������������
+ �������������������������������������������������������������������������������������������������������������������������������������������������������������������� ������������������������ ���������������������������� ���������������� ������������������������������������������������������������������������ �������������������� �� ���������������� ��
���� ������ ���������� �������� �������������� �������� ���� ������ ������������
������������������
�� �� ���� ������������������
���������� ������������������������������������ �������� ������������ ������������
+ ���������� ���������� �������� �������� ������ �������������������� �� ������������ ������������ ������������������
���������� �� ������ �� ���� ��
+ ���� ��
������������ ���� ���������������� ������ ���������� �������� ��������������
+ �������� ������������
����
���������� ������ �� �������� �������������� ������
�������������� �� �������� �������������� �� �� ������������ ������ �� ��������
+ ������������������ �������� ��������������
+ �� �������� �� ������ ��
���� �� ������
+
�� ����
�� $ �������� ��
����
+
����
+ ������
��
��������
+ ��
+ ������ ��
+ ��������
+
+
+ �� ��������
+ �� ����
+
����
��
+
+
���� '
+ ��
������
�� ��������
���� ������ #
+ �� ��
+
������
����
+
����
��
+ ������
������
+
��
��
$ ��
+ �� ����������
���� ����
+ �� �� �� ��������
+ �� �� ������ ���� ���������� �� ��������
+
������ ��
������
����������
�������� ������ �� ������ ����������������
���������� ������������
+ ���������������� �� ��
����
��
+
���� ������ ��
������ ��
����
+
+
+ ������
�������� �� ������
+
������������
+
+ ����
+
���� ���� ��
���� ������ ���� ������������ �������� �������� �������������� �������������� ������������ ������������ ����������
+ ������ �� ������������
������
���������� �� �������������� ��
������ �� ������
������ ���������� ������ ��������
������ ��
+ �������� ������ ����
+
���������� ���������������� �� �������� ���� �� ��������
����������
���������� ���� ���� ������ �������� ������ �� ���������� ������������
������������
������ �� ����
+ ������
+ �������� !
������ ��
+ ������ ������ ��
����������
+
�������� �� ������
+
�� ������������
+
+
!
������ ����
+ ����
������ ����
���� ������������ ����
+ ���� �� �� ���������� �� ������ ������ ���� ������������������������
����������������
+
+
��
�������� ��
������
�� �� ����������������
����
����
�� ����
������ ������ ��
�������� �� ����
���������� ��������
+
����
+ ������
����������
+ ������ ������ �� �� �� ������������
+
���������� ������������
������������
+ ��
����
+ �� �� �� ��
������ ��
������ �� ��
��
������
�������� �� ������
����������
+ "
���� �� �� ���� ������ �������������������� ���������� ������������������������ �������������� �������� �������������������������� ���������������� ���������������� �� ��
������������ �� �������������� ���������� ������������������������������ ��������������������������
+ ������������������������������ �������� ������ ������������ �������������������� ������������������������������ �������������������������������� �������������������������� ������������������������������ �������������������������� ��������������������������
���������������������������� ���������������������������� ���������������������� �������� ������������������������
+ ���������������� ��������������
+
������������������������������������������������������������������ ���������������������� �������������������������� ����������������������������
���������������������������������������� �������������� ����������������������������������������������������������������������������������������������������������������������������������
���������������������������������������������������������������������������������������� ���������������������������������������� �� �� ������������������
+ ����
����
�� ����
����
+ �� �� ��
�� ���� �� ����
���������� ������������
��
+
+
���������� ���������� �������� ������ �� ������ ����������������
+
���������� ������������
��������������
������ �� ����
+
�� ������ �� ����
+ ������
������
+ ���� ������
+ ���������������������� ���� ������
+ ������������
+
���� ��
�� ������������ ���������������������������������������������������������� ������������������ ����������
�������������������������� ���������������������������������������� ���� �� ���������������� �� ������
����
+
+ ��
+
+
+
+
+
+
��
������
+
+
��
+ ������
+
������
��
����
+
+
�� ��
������
+ �� ��
+ ��
������ �� ��
+
+ ��
+
!
+
+
��
�� �� ������������ ������ �������������� �� �� ������
+
+
+ ������������ ���������� ������ �� ������������ ��
������
������
��
�� ��������
��
+
��
��
�� ����
+ �������� ������
+
+ �� �� ���������� ������ ����
+
������������
+ ������ ������
������������
+
+
+
�� ������ ����
����
����
+
+
+
������
������ ������
��
��
+
!
+
��
��
+ ���� ���� �� ������������ ���������� ������������������ �� �������������� ���� �� ������������ ������������ �������������� ������������������ �� �� �������������� �� ������
����
+
+
+
+ ����
+ ��
�������� ��
+
+
+
��
������ ������ ����
+
������������
+
������������������
����������
+
+
+ ��
������ ���� �������� ������
+ ������
������ �� ������
����
������
+
����
+
+ ��
+ ������ ���� ������ �� ������������������������ ���������������� ���������������� ���������� ����
+ �������������������������� ���������������� ���������������������������������� ���� ���������������������������� ������
+
+
+
+
+
+
+
+
+
������
��
+
+
+
��
+ ������
����
+
+
�� ��
+ ������ ������ ������
+
+
+
��
+
+
+
+
$
+
+
��
+ ������������ ������ ��������������
+
�� ������
�� ���������� ����������
���� ��
�� ���������� ��
+ �������� �� ������
+
+
��
��
2
+ ��
& /
+ '
#
��
+
!
��
�� ( (
�� &
+ +
+
��
4 ; $
+
��
��
����
" #
+
+
+
�� 2 )
+ #
+ ��
+
! % 0 (
��
+
+ + %
�� ) 0 ��
����
+ ��
+ ������
+
+
+ ����
����
+ - ��
+
+ ��������
+
+
��
+
����
��
������
+ ����
&
$
#
#
+
#
#
'
%
% #
+
# ' #
+
' *
��
% ( "
+
' %
# & (
+
$ $
" %
��
+ ��
&
��
+
+
+
���� �� ��
��
+
'
+
��
��
) )
!
����
����
+ ��
+ ��
% ��
+ �� ����
+
+ $
#
����
���� ��
+ ���� ��
����
��
����
+
�� ��
��
+ �� ! "
+
��
������
������
+
�������� �� ������
+ - # ��������
+
+
+
������
+
����
+ ����
������
+
!
+
+
+
+
+
+
+
+
+
��
+
������
+
+
+
+
������
+
+
+
# !
+
+
+
+
+
+
+ �� ��
��������
��
+
+
��
+
+ ��
+
�������������� ������������������������������������ ���������������������������� ���������������������������������� �������� ������������������ ����������������������
������������������������
+
+ ������������ ���������� ������������������ �������� ���������������� ���������� ������������ ���������� �������������������������� �������������������������������������������� ������������ ���������������������� ������ ���� ������������ ���� ����
������ ������������ �� ���������������� �������� �������������������������������������� �������������������� ������������������ ���������� ����� [...]
+ ������������
������ ����������
����������
"
�������������� �������� ���� �������� ������������������ �� ����������
���������������� ��
���� �������������������� ������������ �������� ���������������� �������� ����������
�������� ���������� ������
���������� ������������ ���� ���������� �������� �������� ����������������
+ ����
�� ������
+ ��
+
+ ��
��������
��������
�������� ����
�� �� �������� ������������
�������������� �������� ���������� ���� ��������������
�� ��
+
������ �� ����
��
+ ����
��������
+ ����
+ ������
+
+ ��
��
+
+
����
��
+
1 �� ��
��
+
������
+
+ �� ��
�� ��
+
��
+ ���� �� #
+
+ ������
��
+
+
"
��
��
+
��
!
+ ���� % ����
+
+ ��
+ ��
+ ����
#
����
����
+
+
+
��
+
��
����
+
+
����
+
+
���� ����
+
+
+ ��
+
���� &
��
$
+ ��
"
+
!
+
+ ��
��
'
��
+
+
������
����
+
��
+
+
+
( ( ������
"
+ ��
��
+
������
+
+
! �� ����
����
+
+
+
+
��
+
+
!
���������� �������� ���������������������������� �������������������������� ������������������������������������ ���������������� ������������ ������������������������ ���������������������������������� �������������������������������� ������������������������������ ���������������������������������������������� ���������� ���������������������� ��
�������������������������������������������������������� ����������������������������������������������������������������
���������������������������������� ������������������������ ���������������������������� ���������������������������������������� ������������������������
������������������������������
������������������������������������������ ���������������������������������������������������������������������������������������������������� ������������������ [...]
!
+
#
�� &
��
% (
(
,
+
�� "
" ��
+ %
!
+
#
# #
+
+
$ -
+
(
+ ��
#
# ��
+ $ ' '
����
% #
+ ���� / $
+ *
#
!
+
$
'
! ! ! % $
���������������������������������������������������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ �������������������������������������������������������������������������������������������������������������������� [...]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
���� ��
+
+
+ ��
+
+
+
+
����
+
+
+
+
��
+
��
+ ��
+ ��
���� ��
���������� ��
������ �� ��������������������
������ ��
���������� ������
����������
������
+
$
+
+
+
"
+
!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ���� ��������
+
����
+
+
�� �� �� ��
��
����
+
���� ����
+
�� �� �� ����
+ ����
+
+ ������
��������
������
������
+ ������
+
���� ��
�������� ��������
��������
�� ����
+ �� ����
+
�� ���� ���� �� �������� ����
���� �� ���� ����
������ ������������
������ �� ������ #
������
���� ��
���� ����
+ ��
�������� ���������� ���������� ���� ���� ������������ ����������������
+ ��������������������
+ ���������� ���� ������������ �������� ������ ����
+
+ ������������ ��
+ ������& , . - + $ & * @ % ! + 0 #
' % ) "
0 & "
* 5 # "
) ) # ( - # + $
"
' * ,
' . ! (
" 2 1
+
* & $ ! ' * . . & ( & 2 - %
! * 1 3 , ( $ " ! 0 "
/ = 3 % "
% 5 !
$ . . $
$ ! ��
) / * $ & ' "
$ * # !
! " %
% 5 ' ! $ " & ' 0 2 ,
-
1 7 / # $
!
! "
+ # ! ) $ % % !
( % ! % ) %
' + 0 #
% #
- 2 +
& 4 3 ) $ , " " ! ) $
. + " ' , " $ ! , ' , # % ' # $ %
" # $ & %
) ) " + #
" $ ! & . $
&
+
( / . # ( '
+
" # % , # ( ,
+ - 7 / . %
+
$
" ! 3 (
$ # - * ) . 2 ! #
( $ ��
6 6 1 ) " $
$ ' / $
. # ( %
�� % % $
3 ( #
( ��
&
% ! # "
�� ! ! !
( "
+
+ %
"
"
���� + -
+ �� ! $
����
' $ (
��������
* +
$ 2 $
" &
% %
+
, �� "
' & + $
���� ) 1 - .
"
+
+
+
+
% %
��
$ �� )
& ��
!
( �� "
"
! / '
+
+ # $
"
��
+
+ 2 % ! '
# $ " & #
"
+ - ( ��
�� & %
��
��
$ �� ���� " $ " ' ��
+
+
+
����
# *
%
! '
$ ( "
+
%
&
# ,
+
! # $
, #
#
+ & / ' !
# "
+
+
#
# ! &
+
# " ! !
#
" $ #
+ ( ) " " '
"
! $ $
+
"
"
! $ &
%
!
" !
��
+
( , !
#
& ' % ! 2 "
&
% # $ / / & ' %
#
! (
" # ! $ % " # # * " '
" $ "
�� $ " & (
! & . 3 $ $
( & #
" "
" & * % # , , ( ����
+ $ . , $
$ 1 &
' $ %
* #
% $ * $ )
$ & # , + !
) . #
�� ) 3 1 1 (
$ ��
" ) %
+
# ( ( 0 , !
! ( % ( &
+ ! + "
) ' " " + /
( & ' &
# $ * & "
* * ��
! - $ % ) & # 2 / # #
! # * !
+ . 8 1 ) " # # " # % " % % ( & + %
+ " ( %
! % & ! $
���� & % ! $ ( ( $ # # % - #
& ! !
# $
'
!
$ ! " $ # $ &
+
$ !
!
" " & "
!
# )
+
+
+
+
+
+
+
��
+
+
+ ������
+
+
+
+
"
+
+
+
+
+
+
+
+
+
+
+
#
+
+
+
+ ����
+
+
+
+
"
+
+ ������������
+ �� ������������������ �������������������������� ���������� ���������������������� �������� ������������������
��������������������
�������������������������������� ������������������ ������������ ������������������������������������������������������������ �������������������������������������������������������������������������������������������������������������������� ���������������������������������������������������������������� [...]
+ ���������������������� ���������������������������������� �������������������� ������������ ������������������������������������������������������������ �������������������������� �������������������������� ������������������������������������������������������������ ���������������������� �������������������������������������� ���������������������������������� ������������������������������������������������������������������������������������������������������� [...]
+ ����
�� "
���� !
+
������ ������ ����
������ ����������
������ ������������ ������������������ �� �������� ������������ ����������������
+
����
�������������� ���� ���� ����
+ �������� ���� ����������������
+
�� ���������� ������������ ����������������
������������������ ����������
������������������
���� �� ���������� ������ ���� ����
+ ������������������ ������ ���� ���� ��
+ ����������
+ ��������������
�������������� ������
+ �������� ���������������������������������������� ������������������������������ ��������������
+ �� �� ���� ���� ��������������
+ �������� �� ����
+ �� ����
%
��
+
+
+
��
��
+
�� ��
��
�� ����
+
�� ������ ���� ��
��������
��
+
+
�� �� ��
����
���� �� ������ ������ ������ ������ �� �� ���� ����������
�� ���������� ��
���������� ����
+ ������ ��
+
+
��
+
��������
+
+
����
���� ��
��
������ �� ������ �� �� �� ��������������
+
�� ������` O U 6 < 6 ����
&
& "
9 ? - = !
% , 3 5 / 5 C ; R L ����
9 ? $ + $ ������
�� " % 3 5 @ 9 ��8 G 0 N % @ 8 ������C = ��s�4���Z >H ����V # �� C T c J H P � t � j 4 ! ������ L U | C A @
3 ����7 ����; > Y � @ * @ � t � � { < N G
= q i 8 ��{� c �� = ��
^ ����U s x S �� G c P v
����% - � � �� �� $ ����������a � u n z x K ����Z � < 0 G J b a ] ( & B G " U � T ? ���� R Z O > M X M [...]
+ ��
= = ) �� G 6 " 6
�� ���� # @ V O ` & ����
���� �� ����0 - ����_�n������� 0 0 ���������� ������~�O�g�d�<�K�p������������{�' E ��L��� U < ? # D # 6 �� � P ) , = � � [
�� ' @ Q 9 ��T Y ��z���� � C 9 L T j � � H
�������� @ ����} � � � X B ) ! / � � F \ � W 5 [ ? > � � % . z � � X R M M j � m , ��i , + t � � v f > E n 7 [ I ` L C ����P � ( J
����g s : $ ���� T
! 5
����������- ~ : �� y
! ����
$ = ? ��������, O �������� - ' _ B ^ W h [ . + 5 - 2 * ��' 3 -
/ 6 M \ V X = * , / 2 6 ? @ @ L d a o W ���� # E Z G @ _ Y . ������������ G I V [ i t S
��������h � d ? 4 V I & ����$ 6 X k L 3 - 9 Y p � � n ������
J M A P Q j � ~ ] x A 7 , ��3 + = ; V N (
V ������
F > + , 9 ; = S 0 ? [ 2 Y Q t 4 �������������� ��% 8 : ����
> 7 1 , 7 O 8 ������
2 j a a ��������������
+ , J 4 [ q s o O b l T
+ 1 4 A R T ^ S N C < .
D 1 % = 6 �� + 4 C ? G <
��
������������
9 = ) �� B '
/
���������� < W W ^ + ���������� ������������ ������������x�����$ W I
����������������������d�/�=�o���������
1 2 ����������. Y F / 9 0 L P E 1 5 E P 6 ����@ s a =
M X ] S :
+ @ `
+ % ^ F
C W b t q 8 �� ��
% < Q V N r _ n X 9 ( " % = E a \ E L F ] h Q 9 _ j n X o o E I W F ^ ? g � f W o � z E P H W + p w y � v ] 1 ��
X W a U Y s j � � w ' ����! ����4 u \ L : 1 ��) 3 > : ����
9
) . B D : 2 �� ) 4 $
+ ��# 4 8 P _ ? �� <
���� - 8 " ������I 7 B ; K I ��
���� �� ! & % 0 ���������� ���� * E K ��������
% ����. 6 �� ���� �� & ' / 1 2 7 G
��������$ A 9 S [ [ E �� ' 2 J * ' & ) M u z U ������ ? 7 . . + R c � ] o 6 : 1 ��
��: # / G # "
7 �� �� ) 3 ' ! 1 D C K D ( Q F V : \ 8
������ ����
/ 0 ! ���� &
+ 7 8 ; /
����
+ b L B ����������������
% B ; L b g L 3 G K ; . % ) ? L U > / 1
/ % 9 ) ���� % A A . ���������� C @ # ��
? ) * ����������
�� / 6 : ���� ������������������= A ������@�2�l��� # 3 > ( ���������� ��������_�u�o�Z�W�}������������� ������ %
3 0
��8 +
,
$ E G �� 9 B 7 < 7 * E 4 5 * = 9 [ _ o a - ��
�� 4 % 2 S v i F . 2 ) $
4 @ < C # D : 6 @ O I G X P A 3 A J : E \ 9 0 O f ^ 4 * ] 1 ( ? T a r S 7 ! �� E > A 7 J ? . e j 2 ������������
F ) "
��
+
' �������� ����
������
+ ���� 6 @ ! ���������� ������������ ������T G O B L @
' �� ��
) ! 1
��
$ - +
A C G 5 ����
# / 5 $ ��
��
( ' - 2 : 8 A # ���� �� K C S Y S D
���� " . @ & #
# ; ] \ ?
������ 3 ' $ & B T e T j 3 5 ( ��
+ ����$
2 J * $ 3 �� �� + 4 & ' + > ; B :
E 9 N 3 T ( �������� ����
* ) ����
' + 2 5 * ���� , c R D ���������������� , G ; Q a g N 7 Q S @ 0 # '
/ I I S A 2 0 ! " 5 % 9 1 ��
! * 9 H 5 $
+ ���� �� > C # �� 7 "
����������
) G P L % ���������� ����������
������S�\������� % 0 ���������� ��������e�t�k�U�\����������������� ������ $ 1 .
* + #
7 <
��
+ 3 = 2 2 / 4 0 2 ��$ 3 ; V \ c [ . �� �� $ 6 / 9 ] x d F 3 3 2 1
* , A K D J / 5 T C = P [ V W e d T I Q O N . Z m R G c { p K ? + ` < < W g o v a J 9 �� Q O U H ] [ B i s C ��
4 Y 9 3 ' $
, + ? # ��
! . 4 ' .
���� ! ( . H S 3
������
- �������� , 0
����
������������������������������������������������������������������������������������������������������������������������������"������������N�p���������������������
�)�&� ��
���
� ���������������~�M�>�#��
�������������a�G�0�"��"�������������������������������������������������������������������������������������������������������������������������������� [...]
+�Z�������������4�y�����������������������������������������������~�p�s�\�J�6�'���������������f�\�B�*�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+
+ ���� ����������
��
���������� ���� ��������
������������������������
+ ���������������������� ������ �� �� ���� ���� ���� �� ���� ��
���������������� ������������������������������������ ������������������������ �������������� ����������������
�������������������������������� �������������� �������������������� ��������
+
������������ ���� ���� ������
+
��
+ ��������������������������
�� �� ����
+
+
+ �������������� ���� ����
������������������������ �������������� ������������������ ���������� ���� ���� �� ��
������������������ ������������
+ ������ ��������
������
����
�������� ���� �� ������������������������ ������������ ������������������������
�� ��
���� ��������������������������������
+ ����
! ������
+
+ ���� ����������
+ ��
+ ���������������� ���� ������ ���������� �������������� ���� �� ������
���� ���� ���� # �� �������������� �������� �� ������������������������ �������������� ���������� (
�������� ��
������ ����������
+
��������
+
����������
+
�������������������������� �� ��������
�� ���������������� �������������� �������������� ����������
+
" �������������� ���������� �������������������� �� ������ ������ ���������������������������������������������������� ������������������ �������� ������������
+ �� �� ���� �� ��������
�������������������� ��������
+ ��
+ ����
+ ������
���������������� �� ���������� ����
+ �������� ������ ���������������� ���������������������������������������� ���� ���� ���� ��! ���������������������� �������� ������������������
����������������������������������������������������������������
������ ������
����������������
+
�������������������������������� ������������ ������������������ ��������
+
���������� ���� ��
����
+ ��
���������� �������� ���� ��
+
�� ���� �� �� ���������������� ������
���� ��
�� ������
+ ��������
+
' )
+
+ ������������������������������������������������ ���������� ���������� ������������������������������������������������������������������������������������������������ ����
��
�������� ���������� �������������������������������� �� ���� �� ����
+
�������� ���� ����������
+
+ ����
���������������� ����������
������ ����������������
���������������������� ���� �� �� ���� ���� ��
���� �������� ���� �������� �������������������������������� �� ������������������������ �������������� ��������������
# ������������ ������ ����������
�� ������ ��������������
��������
����������
�� ��
+ ��
���������� ��������������
������ �� �� ��
+
������ ����
��������
����������
+ ������
' '
+
+ ������������������������������������������������ ���������� ������������������������������������������������������������������������������������������������������������ ���� �� �������� �������������������������������������������������������� ���������� ���������� ������������������������������ ���������������� ���������������������������� �������������������������� ���������������������������������������������������������������� ������� [...]
+ ���� ������������ ���������������� �������� �� ������������ �� ��
+
���������������������������� ����������������
������
�� ���������������������������������������������������������������������������� ����
+
#
�������������� ���������� �������������������� ���������� ������ �������������������� ������������������������ �� �� �� �� �� ������������������ ��
�� ��
�� ������ ���������� ����
+ ��
+
+
(
����
+ �� ����������
��
���������� ���� �� �� �� ���������� ���������������������� ���� �� ��
+
+ # ���� ���� �� ���� �������� " ���� �������������������������� �� ���������������� ����
����
+ �� �� , ������
������
����
������
���� ����������
��
!
���� ��
+ ��������
��
��
+ �� ������ ������ ������������ ������������
+ ������
+
+ " �������������������������������������������������������������� ������������������������������������������������������������������������������������������������������������ ���� �� �������� ���������� ������������������������������������ ����
+ ����������
+ ��
���������� ������������������ ������������ �� ���������������������������� �������������������������� ���������������������������������������������������������������� ���������������������������������� ����������������
�������������������������������������������������������������� ������������������������������
" ���������� ��������
�� ������ �� �������������� ��������
+ ����������
+ ��
+
�������������������� ���� ������������
������
���������������������� �������������� ���������������� ���������� �� ��
+ ���������������������������� �������������������� ���������� ������ ������������������������������������������������������������������������������������������������
��
+ ���� ������������������������������������������ ����������
+
! �������� ���� �������� ���������� ���������������� ��������
������ ���������� �������������� ������ ���� ���� ������������������������ �������������� �� ���� #
���������� ����
���������������� ����
, ��
���� ������
��
+ ������ " " # $
�� �� �������� �� ��������
+ ������������������ �������������������������������� ����������
!
+ �������������������������� �������������������� ���������� ������ �������������������������������������������������������������������������������������������������� �� �� �������� �� ������ �������������������������������� ��
��������
+ �������� ���� ���������� ����������
+
����������������������������
������ ���������� ���������������������������������������������� ���� ���������������� ������ �� ������ ������ ������������������������������������ ��������������������
������ ���� ���� �� % ��������
������
+ ���� ������ �� ������������
��������
����������
+ ��
����
+
+ ���������� �������� ���� ��������
+
+
+
+ ������ �� �� ���������������������� �������������� ���������������� ���������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ���� �� ���������� �������������������������������������������������������� ���������� ���� ��
���������� ���������������� ������������������ ���������������������������� ������������������������
���������������������������������������������������������������� ����������������������������������
+ ����������������
���������������������������������������������������������������� �������������������������������� ���������� ������ ���������� ���� ������������ ����������������
��������
����������
+
+
���������� �������� ����
����������
+
������
+
+ ��
+ �� ���������������������� �������������������������������� ������������ ���� ��
�������������������������������������������������������������������� ������ ����������������������������������������������������������������������������������������������������
�� �� ������ �������������������������������������������������������� ������
+
�������� ���� �������� ���������������� ���������������������������� ������������������������ �������������� ���� ������������������������������������ ������������������������������ ���� ������
+
���������������������������������� �������������������������� ��������������������������������
����������
+ �� ���������� ���� ������������������������������ ���������� ����
����������
�������� ���������� ����
����������
��
��
���������������������������������������������������������� �������������� �������� �� �������� �������������������� ����
+ ����
+ �������������������������������� ������������ ������������ ���������������������� ����
+
��
+ ������ ���������� �������� ���� +
+ ������
��������
������
�������������� �� ���� ��
+ �� ��
+ ��
�� �������������� �������� �� ������������������ �� ��
+
+
+
+
+ - ������
+
����
������ ��
��
+
��
+ ��
+
+ ��������������
+ ������������
+ ������������
������
+
+
������������������������������������������������������������ ������ ����������������������������������������������������������������������������������������������������
+ �� ���� ������������������������������������������ ����������
+
$ ������
��
��������
+
+ ���������� �� ����������������������������
+ �������� ���������� ���������������������� ������������������������������ ���� �������������� ���� �������� ��
������ ������
�������������������������������������������������������������� ��������������������������������
����������
+ �� �������� ���� ������ ������������
�������� ��
��������
+
���������� ��������
+ ��
+
����
+ ��
��
�������������������������������������������������������� ��������
+
�������������������������������� ������������������ ������ ����
+ ������������������������������������������������������������������������������������ ����
+
������ ��������������������������������������������
-
+
+ ��������
�������������� ���������������������������� �������� ���������� ���������������������� ���� ������������������������������ �������������� ������������������ �������� ������
�������������������������������������������������������������� ��������������������������������
����������
�������� ���� �������������� ���������� ���� ����������
+
���������������������� ���� ��������������
������ ���� ����
����������������������������������������������������������
+ ������������ ��
+
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ���������������������������������������������������������������������������������������������������������������� ���������������������������������������������������������������� [...]
+ �� �� ������ ������������������������������������������������������ ������ ����
+ ���������� ���� ���������� �������������� ���������������������������� ���������� ������������
���������������������������������������������������������������� �������������� ���� ������������
�������� ������ ���������������������������������������������������������������������������������������������������� �������������� ������������������
���������������� ���������������� �������� ���� ����������
+
+ ���� ����
+
���� ��
���������� �������� �� �� ������ �� ������ �������� ���� ������������������������ �������������� ������������������ ������������
�� ��
��
���������������������������������������������������������� ������������������������������������������������������������������������������������������������������������������������ ���� �������� �� ���������������������������������������������������� ���������� �������������� ���������� ���� ����������
+
���������� �� ���������������������������� ����������������������
���������������������� ������������������������������������
+ ���������������������������������� ���������������� �������������������������������������������������������������������������������������������������� �������������������� ���������� ���������������������������������������� ����������
����������
+
+
���������������������������� ������������
����
��
������ ������
�������������� �������������� ������������
������ ��
������������������������������������������������������������ ������������������������������������������������������������������������������������������������������������������������ �� ���������������������������������������������������������������������������������������������������� ����
+ ������������������������������������������������������������������������������������ ������������������������
���������������������� ������������������������������������ ����������������������������������
+ �������� ������
+ ������������������������������ �� ������������������������������������������������������������ " ���������� �� ���� ������ ������������������ �������� ����������
$ %
��������������������������
������������
+ �������������� �������������������������������������������������� ����
+ " ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+
������������������������������ ���������������� �� �� �������� �� ��
+ ��������������������������������������������������������������������������������������������
�� �������������������������������� �������������������� ����������
+ ������ ������������������������������������������������������������������������������������������������
��
�� �� �������������������������������������������������� ����
��������
+ # ������ ���� ��������
���������� �� ���������������� ��������
���������������������� ������������ ���� ���� ������������������������������ �������������������� ���� ����
+
������������������������������ �� ������������������������ ��������������������������������
$
+ ��������
����
+ ������ �������������� ��������
����������
+
!
" %
��������������������������
��������������
+
��
+
+ �������������� ������������������������������������������������
+
(
�������������������������� ������������������ ������
������ ������������������������������������������������������������������������������������������ ����
�� ��
+ ������������������������������������������ �������� ����������
+
�������� ���� ���������� ���������� �� ����������������������������
������������������������
�������������� ���� �������������������������������������� ������������������������������ ���� %
������������ ����
���������������������� ������������������������������
# ��������
��
�������� ������������������ ��������
+ ����������
��������������������������
+ ����������������
+
+
������
+
+
�� ������������������������������������������������������������������������ ������
"
+ �������������������������� ������������������ ������
������ �������� ������ ������������������������������������������������������������������ ���� �� �������������������������������������������� ���������� ��
+ # ������
��
+ ��������������������������
�������� ��������
������
��
����������������������
���������������������� ������
%
�� ������������������ �� �� ����������
+ .
+ )
������
+
% + !
# & ' * , % &
#
�� �� ��
+
!
���� ���������� ������������
��������
" (
�������������������������� �������������������� �������� ������ ��������������������������������������������������������������������������������������������������
+
�� �� �� ���������������������������������������������� ���� ����������
+ " �������� �� ����������
+
+ �������� ���������������� �� ���� �������� ���������� ������������ �� ���� ������������ �������������� ������������������ ���� ���� ! ������������������ �������� �� ������������������������ ������������������������ &
������
��
������ ��������������
��������
+ ����������
+
"
$ $
�������������������� ���� ��������������
+
�������������� ������������������������������������������������
$
������������������������������������������������������������ ������������������������������������������������������������������������������������������������������������ �� ������ ��������������������������������������������������������������������������������������������
+ ���������� ���� ���������� ����������������������������������������������������������������������������
+ ������������ ���� ������������������������������������������������������������������������������������ �������������������������������� �� ������������������������������������������������������������
����������
+ ����
�� ��������������������������������
+ ��������
����������
��������������������������
��������������
+
+ ������ ��
���������������������� ���������������������������������������������������� ������������
���������������������������������������������������������������������� ������������������������������������������������������������������������������������������������������������ ����
+ �� �� �������������������������������������������������������������������� ���������������� ����
���������� ���� ���������� �������������� ���������������������������� ���������������������� ������������ �� ���� ������������������������������ ������������������������������
���� ������
�������������������������� �� �������������������������� ������������������������ $
������
����
+ ���� ���������� ����������������
��������
����������
!
��������������������������
������������
��
+ ���������������������������������������������������������� �������������� ����
+
+ ������������������������ ������������������ ������
���� ���������� ������ ������������������������������������������������������������������ ��
+
+
+ �������� �������������������������������������������� ������������ " ������ ������
����
+ ��������������������������
������ ��������
������
+ ���� ���� ������������������������������
)
+
+
+
����������������
�� ��������
" +
)
����
��������
�� "
+
( , # ' ' ( ) $ #
" "
& #
+
+ �� ���� ������������ ������������
+ ������
# &
������������������������������������������������������������ ������������������������������������������������������������������������������������������������������������ ��
��
������ �������������������������������������������������������� ���� ���������� �� ��������
+ ���������� �� ���������������������������� ���������� ���������� ������������ ���� ���� ������������������������
�������������������� ������ ���� �������������������������� �� ������������������������ ������������������������ &
������
+
+ ����
�� ���������� ��������������
+
��������
+ ����������
�������� �������� ����
������������
+ ���������������������������������������������������������� ������������
+
!
+ ������������������������������������������������������������ ������������������������������������������������������������������������������������������������������������ ����
+
�� ������ �������������������������������������������������������������������������� ���������� ��
�������� ���������������������������������������������� ������������������������
+ ������������ ���� ������������������������������ ��������������������������������
������
������������������������ �� ����������������������������������������������������
$ ������
+ ����
�� �������� ������������������
��������
������
!
+
�������������������� ����
+ ����������
+ �������������������������������������������������������� ����������
+
������������������������������������������������ ���������� ������������������������������������������������������������������������������������������������������������
+ ���� �������������������������������������������������������������������������� ��
���������� ��
��������
+ �������������������������������������������������������������������������� ������������ ���� ������������������������������ ���������������������������������� �������� ����
+ ���������� �������������� �� ���������������������������������������������������������� ��������
+
����
+ ���� ������������������
+
+ �������� ��
+ ��������
!
�������������������� ���� ��������
���� ���������������� ��������������������������������
��������
+ �� ������������������������������������������������������������ ������ ����������������������������������������������������������������������������������������������������
+
+ �� ������������������������������������������������������ ��������
# ������ ��
�������� ������������������ ���������������������������� ������������ ���������� ������������ ���� ������������������������������
������������������������������ ����
+ �������������������������� �� ������������������������ ���������������� ������ '
������
+
+ ����
������ ����������������
+ ��������
������
$ !
�������� �������� �� ��������
+
��������������������������������������������������������
��������
������������������������������������������������ ���������� ������ ������������������������������������������������������������������������������������������������
+
+ ��������������������������������������������������������������
+ %
�������� �������������� ���������������������������� ���������� ��������
����������
+ ���� ������������������������������ ������������������������������
��
!
�������� ������������ �� �������������������������� ���������������������������� #
+ ������
����
���� ����������������
+ ��������
+ ������
+
���������������������� ����
����������
+
�������������������������������������������������������� ��������
�� �������� ������������������������������������������ ������ ������ ����������������������������������������������������������������������������������������������������
�� ������ ���������� �������������������������������������������� ������
" ������ ��
�������� ������������������ ���������������������������� �������� ���������� �������������� ������������������������������������ ������������������������������ �������� ������ �������������������������������� ������������������������ �������������������������������� ����������
+ ����������
������ ������������������ ���������� �� ������ ��
+
���������������������� ����
����������
+
�� ��
�������������������������������������������������������� ����������
+ ����
+
+
��
+
����������
����
+
+
+
����
+
+
+
#
+ ' ������
����
���� ��
�������� ���������������������� ���� ���������������������������� ���������������������������������� �������������������� �������������������������������������� �������������������������������� ������������ �������� ! ���������� ������ ���������� ���� ������������ �������������� ������������ ������������ ���������������������� ���� �������� �� ���������� �������������� ��������������
������ ���� [...]
+ ��
+ �� ������
�� ��������
������
���� ���������� �� ������
�� ����
������ �� ������ ������������ ��
����
��
# ����
����
����
�� ������������ ������ ��
������ ����������
������������ �� �� ���������� ������ �� ������ ���� ����������������
������������������ ��������������������
������ ���������������� �������������� ������������������
�������������� ���� �� ����
���� ���� ����������
������ ��
��
+
#
��
+ ��
+
�� ���� ��
+ ����������
������������ �� ��
������������
+
��
+ ��
�� �� ������������ ���������� �������������� �� ���� ����
�� ��
�� ������ ���� �� ��
��
+ ��
+ ��
����
������
�� �������� ���������� �� ��
�� ������ ��
������ ���� ��������
�������� ������
���������������� ������
�� ������
+
���� �� �� #
������������ ��������
+ ���� ������ ������������
������
�� ��
��
+
+
+
+
+
'
��
+
��
+
������������������ ������ ������������
+
����������
���� ���� ��
������
+
+
������������
+
������
+
+
+
��
������
+
"
, ! ��
��
+
+
+ ������ ��������
+ ��
+
+ �� �� �� ��
�������������� �� ������ �� ����������
+
+ ��
&
��������
���� �������� ���� ������
+ ����������
������
������
+
+
+
+
+
+
+
#
+
��
��
������
��������
+
�� ������ ������
���������������� �� ���� ������
+ ���� �� ������������ ������������ �������������������������� �������� ������ �� ������
��
+
������������������������������ ������ ���� �� ! ����
�� ������
���� ��
��������������������������
�������� ���������� �������������� �� ���� ������������������������������
+ ���������������������������������� �������������������� ������������������������ ������
+
���������������������� ������������������������������������ �������������� ������������������ �� ���� �� ������ ��������
��
��
���� �� ��������
������
���� �������� �� ����������������
�������������� ���������������� �������������� ������������ ����
��������������
����������
����
��������
+ ���������� ������������ �� ������������������������
�� ����
�������� �� �� �� ��
+
+
���� ��
2
+
������
+
+ ��
������������
+ �� �� ���� ���� ������
+
�� ��������
����
����
+ �������� ������ $ ������������ ���� ������������������
���� ���� ���� ������
������������ ��
������ �� ��������������
��
��
+
��
+
+
��������
������
+ ������������ ����������
�� ��
�� ������ �������� ���� ������ ����
����
���������� �� ���������������������������� ���� �������������������������� ����
�� ������ �� �������� �������������������� ���� ������ ��
+
& ��
������
�������������������������� ���������������������� �������������� ���� �������������� ������������ ���������������������������������� ������������������ �������������������������������� �������������������� �������������������������������������� ���������������������� ���������� ���� ��������������������������������
������
��
+
���� ������
+ ��
���� �� �������������� ������������ ���������������� �������������� ������������ ���� �� ��������
�� ����
��
�� ����������
���������������������� ���������� ��������
+
+
+
����
+ ������ ��
$ !
��
+ ��
������
��
% ������
) % ����
+ !
+
����
��
�� ��
������
������
����
����
+ ��������
�� ���� ����
��
�������������� ��
���������������� ���������� ���������� �� �� �� �������������� ������ * �������������� �� ����������
���� ������
������������
+ ���� ������ ��
+
�� ����
������$
��
+
+ �� "
��
�� # # ��
+ ����
����
+ ���� ����
�������������� ����
�� �������� �������������� ������������������ �� ������ ������ ������������ ������ ���������������������������� ������������������������������������ ������ �� �� ��
+ ���� �������������������������������� �� �������� ����
$ ��
������
�� ���������������������������� ������������������������ �������������� �� ���� ������������������������������
+ ���������������������������������� ��������������������
�������������������������������� ��
������������������������������������������������������������
+ ������������ ������ ��������
+ ������ �� ������������
����
���� �� ��������
��������
�� ������������ ���������� �������������� �������������� ������������
����������������
������������ ���������������� ���������� ������ ������������ ������������������������������������ ������������������������������������ �� ������ ������ �� ���� ������
����
������������������ �������������� �� ���������� ���������� ��
�������� ���� ���������� ���������� ������������������������ ���� ������������������������ �������������������������������� ���������������������������� �������������������������������������������������������� �������������������������������������������������������������������������������������������������������� ���������������������������������� ������������������������������������������ ���������� �������������� �� ������������
+ �� �� ��
����������������������������
+ ������������ ���������������������� ������
���������������������� �������������� ������������������������������������ ������������ ���� ������������������ ����������
��������������
+ �� ������
+ ��������
+ �� �������������� ������������ ���������������� ������
+
+
+
�������������������� ���������� ������
+
����
+
+
+
& �� ������ ��
+ ���������������� �� ����
+ ���������� ������������
�������������� �� ���� ����������������������������
���������������������������������� ������������������ �������������������������������� ��
+ ���������������������� ��������������������������������
������������ ������ ���������� ���� ������ ������ ��������������
������
+
���� �� ����
+ ��
��
+ ���������� ������ ������������ ����������
����
������������ ������
�� ������������
������ ������ ���������������� ���������������������������������� �������������������������� ����������
���� �������������������������������������������������������������������� ��
���������������������� ���� ��������������
+ ������������������������������������ ��������������������������
������������������������������������������������������������������������������������������
+ �������������� �������������� ������������������
�������������������������������� �� �������������������� ���������������������������������������� ! ���������������� ���������������� ���� ���������� �������������� ����
������ ����
+ ���� ������
! �������� �������� �� ����
������
����
" ������
+
�� ����
+ ���� �� ������
+ �� �������������������������� ������������������ ���������� ������ ���������� ������������������������������������������������������ ���������������� ��������
+
����
�� �� ���� ������������������������������������ �� ���������� ����
" �������� �� ����������
���� �� �� ���������������������������� ������������������������
���������������������� ���� ������������������������������ ���������������������������������� ������������������
�������������������������������� �� ������������������������������������������������������������
+ �������������������������������� �������������������������������������� ��������
+ ������ ��
+ ��
+ ����
+
+
���������������������� ����
��������
���� �� �� ����������������
������������ ���������������������������������� ������ �� �������������������������������� ������������������ ������ ������ ���������� ������������������������������������������������������������������������������������
+
��
������
�� �������������������������������� �� ������
��
& ����
�� ������
�� ���������������� ��������
���������������������� ������������
+ ���� ���������������������������� ���������������������������������� ����������������
+ �������������������� �������� �� ������������������������ ��������������������������������
+ $ ����������
����
������ ������������
������
�� ��
+
+
+ ��������������������������
�������� ��
+
������ ������ ���������� �������������� ������������
��
�������������������������� �������������������� ������������������������������������������������������������������������������������������������������������ ��������
���� �� �������� �������� ��������������������������������
����
+ $ �������� ���� ����������
������ �� ���������������� ���������� ������������������������ �������������� ������ ���� �������������������������� �� ���������������������������������� ���������������� �������������������������������� �� ������������������������������������������������������������
������������ ������������������ ������������������������������������ ��������
������ ��
��
�������������������� ����
+ ������ �� �� ��������������������
���������� ���������������� ��������������
����
�������������� �������������� �������������������� ����������
+ ������ ������������������������������������������������������������������ �������������������� ����
+ ������ �� ���������� �� �� ������������������������������
+
����
+
% �������� ������ ����������
+ ���� ��
�������������� �� �� �������� ���������� �������������������������� ���� �� ������
�������������� ���������� ������������������ �������������������������������������������������������������� ������������ ������������������
���������������������������������� ����������������
������������
��������
+
������������ �� ���� ������ �� ��
���������������������� ����
+ ������ ���� ���� ����
������ �������������� ������������ ���������������� �������� ��
������ ���������� ������������������������������������ ������ ������ �� ��������������������������������������������������������������������������������������������
+
�������� ���������������������������������������������������� ��
+ ! ������
������
�������������� ���������������������������� ���������� ���������� ������������ ���� ������ �������������� ������
������������������������������ ����
+
+ ���������� ������������ �� ������������������������ ��������������������������������
����������
+ ������
+ ���� ����������������
��������
�� ��
���������� ��
+
+
+
+
�� ������ ������ ������������������������������
����������
+
���������� ���������������� ������������������ ������������ ������ ������������������������������������������������������������������������������������������������������ ��
+ �� �� ������ �������� �������������������������������������������� ������ ��
+
�������� ���� �������� ���������� ��
+ ���������������������������� ��������
+ �������� �������������� ������ ������������������������������������
�������������� �������������� �������� ������ ���������������������������������� ������������������������
+ ��������������������������������
���������� ���� ��������
�� ������ �� ��������
�������� �� ��
���������� ����
+
+
��
�� �� ������ ������ ������ ������������ ������������
������
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ������������������������������������������������ [...]
+ ������������
+ ������ ������
�������������������������������������������������������������� ��������������������������������
+ �������������� ������ ���������� ���� ������
+
+ �� ����
���� ������ ��
�������� ���� ��
+ �� ��������
�� �������������������������� ������������������������������������������������������������ �������������� ���������������������� ���������������� ���������������� ���������������� �������� ������ ������������������������������������������������������������������������������������������ ������ ���� ����
+ ��
+ ���� �������� ���������������������������� ������������
" �������������� ��������
��������������
���������������������� ���������� ���������� �������������� �� ���� �������������������� �� �������������� ������������������������ �� ������ ������������������������������ �������������������� ���� ���������������� ������������ ����������
��������������
��������
+ ���������������� ��������
+
+
���� �� �� ���� �� ��
��
+ ������
+
�������� �� �� ������������������������ �� " ��������
+
+ �� ������ ���������������� ���������������� ������ ������ �� ���������������� ������������������������������������������������������������������ ����
�� ����
+ ��
+
��
�������� ������������������������������ ���������� �������� �� ����
+ �������� ������ �������� ��������������
�������������������������� �������� ����������
+
���������������� ���� ���� �������������� �� �������������������������������� ���������� ������ �������������������������� ��
�������������������� ��
+ ���������������� ���� ����
+ $
+ ������
+ ������
+ ��
���� ������ ������
+
+
��
+
+
�� �� �� ������ ��������
��������
+ ������
% ' '
! $
$ / !
% & !
) '
���� ��
�� "
��
!
!
< 6
(
( * # + % % �� / !
% $
7 "
"
% @ 3
& 8 ,
+ # !
�� . , ��
! 4 ( ��
��
��
+
) ! �� ! 0 (
����
��
��������
+
��
!
- 6
" # '
*
# ! !
+
* " ! �� ( 0 '
" ( , 5 *
) - ( . - 7 0
&
% 0 ( ' " )
' # + 1 2
% $
+ - = 1 $ . 7 F % %
) $
��
(
# * ���� # . & 5 ,
��
( &
! 1 .
2 % ! ( /
������ �������������� ���������������� ������
+ ������ ���� �������� ������ �������������� ������������������������������������������������ ����
+
��������
������������������������������ ���������� ������������ ��
+
# �������� �� ������
������
���������������������������� �������� �������� ���������������� ���� �� ������ ������ ����
�������������������������������� ���������� ������ ���������������������������� ������������������
���������������� ���� �� '
������
�� "
��
�� �������� ����
!
��
+
!
+ �� ��
��
����
+
������
+
+
�� ������ ���������������������������������������� ������ ������������������������������������������������������������������������������������������������������������������������ �� �������������������� ������������
������������������������������ ������������������������������
������������������
+ �������� �������������������� ���������������������������� ���������������������������������������������� ������ �������������������������� ���������������������������������������� ������
�������������������������� �� �������������������� ����������������������
+ ����������
+ ���������� ��������������
+ ����
+ ����
+ ������������������
������
������
+
����
�� ����
+ ������
��
(
" ! % )
����
����
�� ��
+
��
������
��������
+
���� ������ ����������
����������������
+ �� ����
������ ���� ���������������� ������ ������ ���������������������������������������� ������
+
+ ��
+ ����
+
�� ��������
���� ���� ���� ����
�������� �� �� ��
�� % �������� �� ��������
�� ��
+ ������������������ ���� ��
������
# " ���������� ����
+ ����
�� ���� ������ �������� ���������� �������� �������� ��
�������������������� ����
+ �������������������� ���� �� ����
+ ���� �� ( ����
����
�� ��
+ ������ ����
+
��
+
��
+
) ����
+ "
+ $
+
��
���� �� ��
0
�� ����
+
�� ����
�������� ���� ����
+
�� ������
������������ ������ ������������������������������������������ ���������� ������������
������ �� �� ������ ������ �� ���� �� �������� ����
+
������������ ���� ��������
������������
+ ������ �������� ��
��������
+
������
�������� ��������
+ ���� ���� ������ ��������
���� ����
+ ����
+
���������� ��
+ ���������� ���� ��
+ ������ ���������� ����
�������� ��
+ ����
%
�� ����
���� ��������
��������
������
+
+
��
+ #
���������� �� �� ����
% �� ���� ������ �� ��
�������� ������������
������������������ ����
�� �� ������ ������������ ���������������� ������ ������ ���������� ���� �������������� �������������� ���� ���������� ������
+
��
+
+
+
+
+ ���� ������ ���������� ���� ������ �� ����
+ %
�� ��
+ ��
��������
����
������������������������ �������� ������
������������ ����
��������������
�������� �������������������� �������� ������ ������������������������������ �������������������� �������� ������
) ������
+ �� $
+
��
����
��
+
+
+ ��
+
+
+
������
+
+
+ �� ��
�� ������
������������ ������
���� �� ������
������������ ������������ ���� ����
����������
+ ����
+
+ ��
+ ��������
������ ������
������
+ �� & �� �� ����
+
������������������ �� ��
������ ������������
�� ������������ ����
+ ���� ����������
��������
������������ �������� ������������������ �� �� ��
����
*
������ ! ����
������
+ ������
+ �� $
����
��
+
����
%
$
����
+
+
����
!
+
+ ��������
+ #
��
+
�� ������
������
������ ����
�������� ����
�� ��
+ �� ��������
����������
�������� ��
��
+
����
+
����
+ �� ������ ���� ����
��
% ����
��
������ ��
+ ����������
����
��������
���� �� ��������
+ ���� ���������� ����
�� ��
������������ �� ����
���������������� �� ��
(
��
+
+
+ �������� ����
+
����
+
+
+
+
+ !
+
+
������
����
+
+
��
���� �� ����
���� ����
+ �� ��������
+
�� �������� ������������ �� �������� ����
+ �� ��
������ �� �������� ����
( �������� ������
������ �� ��
��
������
+ �������������������� ���� ���������������������������� ������ ���� �� �������� �������� ������
���������������������������� ���������������� �� ���� �� �� �� ����
+ '
������ ���������� ������������������ ������������������ ���������� ������������ ����
�������� ��
+ ����
���������� �������������� ����
+ �� �� ��
���� �� �� �� �������� ������������
������������ ���� ���� �� ����������
+
+
�� ��
+ ����
+
+
+
����
+
+
+
+
+
.
!
+
&
+ ��
��
%
!
+
+
!
' 6
+ -
+
!
+ !
*
"
"
" #
# "
" & 1
, ( ! % ( #
+
+
$
+
!
+
+
��
�� �� ������
�� �������� �� ����
+
����
�� ��
+
��
+
( ��
����
���� ��
��
��������
+ �� ��������
+
+
+
���� �� ����
+ ��������
+
+
+
+ (
+ ! ������
������ ����
������
+
+
$
"
��
����
+ ������������ ������������
���������������� ���� ������ �� ������
��
�� ��������
+ ��������
�� ������������������ ������
����
+
+
������
�������� ��������
+
+
+ ������ ���� ����
+ # ����
��������
+ ���� ���������������������������� �������� ��������
+ ������������ ����
�������������������� �������������������������������� ������������������ ����������������
���������������� �� �������������������� ������
����������
+ %
+
+
+
+
+
���������� ������ �� ������������
+ ���� ������
+ �� �� ��
����
�� ������
������������ ������������
+ ��
+ ��������������
������
������ ������
��
����
����
+ ������������
+ ��������
������ ������ ���������� ������ ����
+ ��
+ ������ ��������������������
+
���� ���� ����
+
! ����
+ �� ��������
+ ���� ��
��������������������������
+ �������� ���������� �������������� ����
+ ���������������� ���� ���������������������������������� ������������������ ��������������������
+ �� ������������������ ����������������������������������
������������ ������ ��������
����
+ ������
����
+
+
+
������ �� �� �� ��
+ ��������
+
���� ������ �� ������ ���� ������ �� ������ ������������ ������������ ��
+
���������������������������������� ������������������ �������� ������ �������������� ���� ������������ ������������ �������������������������� ����
����
+
+
������
+ ������������������ ������ ��������
+
+ " ����
+ ��������
+ ���� ��
���������������������������� �������� �������� ������������ ����
�� ������������������������
���������������������������������� ������������������ �������������������� ��
���������������������� ����������������������������������
����������
(
+
+
+
+
�������� ���� �� ������������
���� ������ ��
+ ���� �� �� ����
����������
������������ ������������
������������������ �������������� ���������������� ������ ������ ����������
�� ������������ ������������ �������������������������� ������ ����
+
+
������ �������������������� ����
��
$ ��
������
��
����������������������������
+ �������� �������� ������������ ����
+ �� ������������������������ ���������������������������������� ������������������
�������������������� �� ������������������ �� ��������������������������������
���������� �� $
+
+
+
+ ���� �� ���� ��
+ ��������
+
+
�� �� �� �� ��
����
+ ������
+ ������������ ������������
���������������������������������� ������������������ �������� ������ �������������� ���� ����������������������������������������������������������������
+ ����
+
+
������ ���������������������� ������
+ �� ��
# ��
+ ������
+ �� ��
���������������������������� �������� �������� ������������ ����
+ �� ������������������������ ���������������������������������� ������������������ �������������������� ����
����������������������������������������������������������
����������
&
����
+
+ !
+
+
+
���� �� ����
+ ��������
�� �� �� ��
����
�� ������
������������ ������������
������������������ ������������
+ ���������������� ����
+ ������
�������� �� �������������� ������������ �������������������������� ������ ����
+
+
+ ������ �������������������� ����
��
+ '
+
������
+
��������������������������
�������� ����������
+ ������������ ���� ����������������������������
���������������������������������� ������������������
�������������������� ������ �������������������� ����������������������������������
���������� �� ������ ����
+
������
��
+
�� ��
+ ������
��
�� ������ ����
������ ������������ ����������
���������������������������������������������������������� ���������� ������ �������������� ������ ����������������������������������������������������������������
+ ����
+
�������� ��������������������������������
+ ���������� ����������
+ " ��
+ ��������
+ �������� �� ���������������������������� ������������ ���������� ������������
���� �� ������������������������ ���������������������������������� ������������������ �������������������� ����
+
���������������������������������������������������������� ����������
&
+
+
+ ������ ��
���� �� ���� ����������
+
+ ���� ��
+ ��
����
�� ������
+ �������������� ����������
������������������������������������ �������������������� ���������� ������ ������������ ���� ���������������������������������������������������������������� ����
+
+
������������������������������������ ����
�������� ��
&
+ ������
���� �� �� ���������������������������� ������������ ���������� ������������ ���� ������������������������������ ������������������������������������������������������
�������������������������������� ��
������������������������������������������������������������
������������ ���� "
+ ����
������
��
$
���� �� ���� ��
+ ��������
+
�� �� ���� �� ������
�� ������ ������������ ������������
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
+ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����������������������������������
�������������������������������������������������������������������������������������������� ������������ [...]
+
������������������������������������������ ���������� ������ ��
" �� ������
+ ������������ ���������������������������� ������������������������ ������������ ���� ������������������������������ ������������������������������������������������������ ���������������������� ������ �� ������������������������������������������������������������
����������
"
+
���� �� ������
������
+ !
+
���� �� �������� ����
����������
+
��
���� ������ ������������ ���������������� ����������
+ ���������������������������������� �������������������� ���������� ������ ������������ ������ ������������������������������������������������������������������ �������� ����
+
+ �� �� ���� ������������������������������������������
+ ���������� ����
# ����
������
+ �������� �� ���������������������������� ������������������������ �������������� �� ���� ������������������������������ ������������������������������������������������������ �������������������������������� �� ������������������������������������������������������������
���������� ���� ������
���� ������������
������
���� �� �������� ���� ��������
+
��
������������ �������� ������������ ���������������� ����������
+ �� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �� ����������������������������������������������������������������������������������������������������������"
���������� ����������������������������������������������������������������������������������������������������
+ �������������������������������������������������������������������������������������������������������������������������� ������������������������������������������������������������������������������������������������������
����������������������������������
+ ������������������������������������������������������������ ��������������
+ ��
+ ���� ������
�� ������������������������������ ������������������������������������������������������������ ���������������������������������������������������������������������������������������������������� ������������������������������������������������������������ ���������� ������ ������������ �������������������������������������������������������������������������� ������
+
+
�� ��
���� �������������������������������������������� ���������� ����������
+ ! ���� �� ��������
�������� �� ���������������������������� ������������������������ ������������ ���� ������������������������������ ���������������������������������� ������������������ �������������������������������� �� ������������������������������������������������������������ ����������
����
���� ��������������
��������
+
"
���������� ��������������
����������
+
+
+
��
+
+
+
+ ������������ �������� �������������� ���������������� ����������
�� �������������������������������������������������������������� ������ �������������������������������������������������������������������������������������������������������� ���� �� �������� ���������� �������������������������������������������� ���������� ������
$ ����
��
+ ����������
+
+ ���������������������������������������������� ������������������������ �������������� ���� ���� ������������������������������ ���������������������������������� ������������������ �������������������������������� �� ������������������������������������������������������������
���������������������� ���������� ���� �������� ���������������������� ������
�� ��
���� ����� [...]
�� ������������������������������������������������������ �������� ������ ������������ �������������������������������������������������������������������������� ����
+
+ �� ���� �������������������������������������������� ���������� ������������
+
! ����
��������
+ �������� �� ���������������������������� ������������������������
+ ������������ ���� ������������������������������ ���������������������������������� �������� ������ ������������������ ������ �� ����������������������������������������������������������
+ " ��������
+ !
+ ���� ��������������
+ �������� �� ��
%
! $ �������������������� ����
��������
��
+
+ ��������������
�������������� ���������������� �������������� ������
+
+ �������������������������� �������������������� �������� ������ ������������ �������������������������������������������������������������������������� ��������
+
�� ��
������ �������������������������������������������� ���������� ������
+
! ������
��
+ ��������
+ ������������ ������������������������������ ������������������������ �������������� �� ���� ������������������������������ ���������������������������������� ���������������� �������������������������������� �� ���������������������������������������������������������� ���������� ���� �������� ������������������
+ ��������
������
!
��������������������������
+ ������������
��
+
+
+ �������������� ������������ ���������������� �������������� ������ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����
+
��
������ �������������������������������������������������������������������������������� ���������� ��
+ �������� ������������������������������������������������������������������������ ������������ ���� ������������������������������������������������������������������������������������
������������������������������ �� ������������������������������������������������������������
������������
+
����
�������� ���������������������� �������� �� ����������
�������������������� ����
����������
+
+
�� ��
+
���� ���������������� �������������������������������� �������������� ������������
�������������������������������������������������������� �������� ������������������������������������������������������������������������������������������������������������
+
�� �������� ����������������������������������������������������������������
���������� �� �������� �������������������������������������������������������������������������� �������������� ���� ������������������������������ �������������������������������������������� ������ ���������������������������� ��
+ ������������������������ �������������������������������� ��������
+
����
���� ����������������
��������
������
"
+
�������� ������ ��������
��
+
+ ���������������������� ������������������������������
����������
+ �� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+
�������� ����������������������������������������������������������������
��������
+ �� ��������
�������������� ��������������������������������������������������������
������������
+ ���� �� ������������������������ �������������������������������������������� ������ �������������� ����
���������������������� �������������������������������� ��������
+ $
���� �� ��������
�������� ������
!
���� �� �� �������� ��
+
�� �� ���� ���������� ������������ ���������� ��
�� �������������� ������������������������������ �������� ������ �� ����
�������������������������������������������������������������� ������ ��
+
��������
+ �������������������������������� �������������������� ��
" ��
�������� ���������������� ���������������������������� ���������� ��������
���������� ��
+
+
�� ���� ���� �� �� ���� ������ ��������������������������
���� ���� + !
+
+ ���� ���������� �������������������������� ���������� �������������������� �������� ��
����
������ ���� ���� �� ��������
+ ������
! �������� ��
+ ����
+
��
����
������������ ������������
������������
+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ��
�� ��
���� ��������������������������������������������������������������������������������
+ ���������� ��
�������� ��������������������������������������������������������������������������
�������������� �� ���� �������������������������������������������������������������������������������������� �������������������������������� �� ��������������������������������������������������������������
+ ������������
+ ������
������������ ������������������ �������� �� ����������
+
+
+
+
���������� ����������������
������������
������ �� ������ ���� ������������������������
�������������������������������� ������������������������������ ���� ���������������������������������������������������������� ������ ������ �������������� ������ ������������������������������������������������������������������ ����
+
+
�������� ������������������������������������������������������������ �� �������� ��
+ ������
+ �������������� ���������������������������� ���������� ����������
������������
+ ���� �� ���������������������� �������������������������������������������� ������
�������������� ��������
������������������ �� ���������������� ���� ��
$
������
+
��
+ $
�������� ����
"
+ �� �� �� ����
+ �� ����
����������
�� ������������������������������������������������������ �������� ������ �������������� ������ ���������������������������������������������������������������� ����
+
+
+ �������� �������������������������������� ���������������������������� ����
��������
�������� �� ���������������������������������������������������� ������������
+
+ ����
�� ���������������������� ���������������������������������������������������� �������������������� ����
���������������������� �������������������������������� ����������
%
������
��
+ ������
���� �� �� ��������
��
+ �� ��
+
����
+ �� ������
�������������� ����������
�������������������������������������������������������� �������� ������ �������������� ������ �������������� ������������������������������������������������ ����
+
+
+
+
+
������ �������������������������������� ������������������������������ ��
������
+ ��������
+ ������������������������������������������ ��������
+ ������������
+ ����
+ �� ���������������������� ����������������������������������������������������
������������������ �� ���������������������� ������������������ �������� # ��������
%
������
����
!
+ ��
+ ��������
��
+
+ �� ��
���� �� ������
������������ ������ ��
������������������������������������ �������������������� �������� ���������������������� ���� �������������� ������������������������������������������������
��
+
+
������ ���������������������� �� �� ���������� ������������
! ��
+
��������
���� ��
+ ���������������������������� ������������ �������� ������������
����
�� ���������������������� ���������������������������������� ������������������ �������������������� ����
���������������������� �������������������������������� ����������
+
)
+
+ ���� �� ���� �� ����������
���� �� �� ��
����
�� ������
+ ������������ ����������
���������������������������������������������������������� ���������������� �������������� ������ �������������� ������������������������������������������������
������ ������������������������������ �������������������������� ���� ��
��������
��������
������������������������������������������ �������� �������������� ����
+ ���� ������������������������ ������������������������������������������������������ ������������������������ ����
+ ���������������������������������������������������������� ����������
��
+ #
�� �� ��
+ ��
����
+
+
+
+
���� �� ����
+ ��������
+
+
+ �� �� ��
�� ��
+ ��
+ �� ������ ������������ ����������
+
���������������� �������������� ���������������� ������ ������ �������������� ���� ������������ �������������������������� ������������������
+ ��
+
+ ������ ������������������������������
�������� �������������� " ��
������
����
+ ���������������������������� �������� ������
������������
+ ����
�������������� ����
�������������������������������� �������� ������
������������������ �������� ������������������
�������� ������
+ ' ������
��
&
+
+
�� ��
+
+
+
+
+
+
��
������
�� ���� ������������������������ ������������������ �������� ������ �������������� �� �� �������� ���������� ������ ���� ������������ ����
��
+
+
+
���� ���� ������ ������ ������������
" ��
������
���� ���������������������������� �������� ��������
+ ������������
���� �������������������� ���������������������������������� ���������������� �������������������� ���������������� ������������������ ���� �� ! ��������
+
+ (
���� �� ��
��������
�� ��
�� ��
�� ��
+
������������ ����������
���������������������������������� ������������������ ������ ������ ������������ �� ������������ ���������� ������ ���� ����������������
+ ����
+
+
+
���� ������ �� ������ ������������ $ ��
��������
����
���������������������������� �������� ������
������������ ����
��������������������
���������������������������������� ���������������� �������������������� �� ���� ������������������ ����������������
$
������
+
+
(
+
+
+
+ ����
+
��
��
��
��
��
+ ������������ ����
������������������ �������������� ������������������ ������ ������ ���� ������
�� �� ��������
������
+ ���� ���������� ����
����
+
+ ���� �� ��
+ ������ ������������
! ��
+ ��������
����
�������������� ������������
+ �������� ������
+
������������ ��
+ ���� ������������������ �������������������������������� ������������������
�������������������� ���� ���������������� �� ������������ �� $
������
'
��
+
+
+
��
+
+
�������� ��
+ ��������
+
�� ��
�� ��
+ ��
��
���������� ������ ���������������� ������
+ �������� ������ ����
������ �� ����
+
�� ��������
��������
+ ���������� ����
����
+
+ ���� �� ��
������ �� ������
"
����
������ ���� �������� ������
���� ������������ ��
����
+ ������������ ������������������������������
+ �������� ������
+ �������������������� ����
+ ����������������
�� ��������
+
+ & ���� (
+
+
!
+
+
+
+
+ ��
+ �������� �� �������� �������������������������������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ������������������ �������� ���������������� �� ���������������������������� ������������������������������������������������������������ ������������������������������
[...]
+ ���� �� ����������
�� ������
�������� ��
������������
�� �������� �� �������������������������� ������ ��
+ ������
+ ������ ���������������������� �� ! ������ ������������ ��
�������� ���� ��������
�������� ��������������������������
�������� �������� �������������� ��������
������������������ ���� �������������������������������� ��������������������
�������������� ����
+
����
������������������������ �� �������� �������������������� ���������� ���������������������� ������������ �� ���������� ���� ��������
���� ��
+ ��
���� ���� ������ �� �������� �� �������� �� �� ������ ���������������� �� ���������������� �������������� ������������ ������������ ������������ ����
������������
+
+ & $ ��
+
+
������
������
+
��
��
+ ����
���� �� ������
1 ! ������
+ !
������
������
+ ��
+ ���� ��
����
+ # ������
+
����
���� ��
��
������
����
+ �� #
������ ����
������
������
��
����
������
+
����
������
+ ����
����������
��
+
���� ������
������ ������
���� ������
+ ��
+ ����
+ ����
������
���� ������ ���������� ���� ����
+
+
+
+ ������
+ ������������������
+
������ ����������
+ $ ������
+ �� �������� ���� ��
����������������������������
+ �������� ��������
+ �������������� ����
���������������� ���� ���������������������������������� ������������������ �������������� ��
+
+ ��
���������������� �� ����������������������������
������������ ������ �������� ����
����
����
��
������ ���������� �������� ��
�������������� ������ �� ������ �� �� ������ ������
����
������������ �������������� ������������ ����
+ ������������
+ ��
������������
�� ������
+ �� �� �� �������� ���������� ����������
���� ������
+
" ������ ����������������������
'
������ �������������� ��
" ��������
+ �� ��������
������
+ �������������������� ����
+ ����
+ ������
������������
���� �������������� ������������������������������ �������� ������ ������������������ �� ���������� �� ��
+ �� ������ ���� �������� ���������� �� ��������
+
���� ������
��
��
��
+ ������
���� ������������ ��
+ ���� ��
�� ������
����
�� ������
���������� ��������
+ ������������������ ������������ ������������������ �������� ������ ����������
��
�� ��������
������
���� ������ ������������������ ����
+
����
������ �� ��
+
+ ������ ���� ������
+ " �������� ��
�������� ����������
���������������������������� �������� ��������
�������������� ���� ���������������� �� ��������������������������������
+ �������� �������� ������������������ ������������������ �� ����������������������������������
���������� �� ������
+ �� ����
����
+
������
+
���� ������������ ��������������
+ �������������� ������ ���������� ����
����������������������
+ ������
+ ������������
+ �������������� ������������ �� ������������������������������������������������������������������������������������������������ ������ ���������������������������� ������������������������������������ ���������������������������������������� �� ���� ������������������������������������������
������������������������������������ ���������������������������������������������������������������������������������������������������������������� �������������������������������� ������������������������������ �������������������������������������������������������� ���������������������������������� �� ����������������������������������������������������������������
���������������������������������� ������ ���������������������������������������������� ���� �������� [...]
+ �� ������������ ���������� �������������� ������������������
����
+
+
+
����
���� �� ��
+ ������ ����������
+ " ������
�������� ������ ���������������������������� �������� ��������
+ ������������ �� ����
���������������������� ���������������������������������� ������������������
�������������������� �� ���������������������� ����������������������������������
����������
��
+ %
+
+
��
+
��
+
+
+ ��
+
+
���������� ������ ����
������������ ������ �� ������ ����
�������������� ��
����
����������
������������ ������������
+ ���������������� �� ������
������ ������ �� ������ ����
������ ���� ���� �������� ����
+ ��
+
��
���� �� ��
+
" ��������
+ �������� ���� �������������� ����������
������ ����
������������
+ �������������� �������� �������������������� �������� ������ �������������� ������������ �� �� ������������ ���� ���������� ��
+ ��
+ ��
����
������
+
��
����
���������� ��������
������������
+
+ ���� �� ������ ���� �� ��
��
�� ������ ������������ ����������
�� �������������������������������� ������������������ �������� ������ ������������ ��
+ �� ������
+
��������
���� ������������������
����
+
���� ��
+
������ ������������
! �������� ��
�������� ������ ���������������������������� �������� ��������
+ �������������� �� ���� ������������������������ �������������������������������� ������������������
�������������������� ���� ������������������ �� �� �������������������� ������ ! ���������� �� #
�� ��
��
+
������
+
��
+
����
���������� ���� ��
������������ ���� �� �������� �� ���� �� ��
����
+ �� ���� ������������ ������������
��
+ ���������������������������������� ���������������������� �������� ������ ������������
�� ������������ ����������
+ ������ ������������������ ������ �� �� ��
������ �������� ���� ��
������ �������������� �� �������� ���� �������� ����������
���������������������������� ���������� ��������
���������������������� ����
�� ������������������������ �������������������������������� ������������������ ��������������������������������
+ ������������������������ ����������������������������������
�������������������� �������� ���������� ���� ��������
+ ��������
+
+ ���������� ���� ������ ���� ������ �� ������������ ������ ���� ������������������
+
+ ��������������������������
���������������������� �������� �� ������
�������������� ������������ ���� ������������������ ������
+ ������ ������ ����
���� ���� ��
+
������
������
�������� ����
+ ����
+
+
��
+
������ �� ���� " ��
�������� ��
+ ������������ ��������
������
+ ������ ������������ ��
+ ��
+ �������������� ������������������������������
�������� ��������
�������������������� ����
+ ������������ ��
�� ������ ��
+
+ % ������
+
+
+ %
+ ��
����
��
����
����
�� �� ��
+
+ ��������
+ ����
+ �� �� ��
+
������ ��
+ ��
�� �� ��
���� ! ���� ��
+ ����
+ ' ���� ' - ��
��
+ ��
+
5
+
+
+
- ���� ��
+ ��
+
' " ���� �� ��
+ ��
+
&
+ ���� ��
�� +
����������
+ + ����
�� �� ��
+
+ @
+
: ��
( 0
# ��
' &
+
+ ��
&
+
! ,
��
+ &
) 3 0
��
�� /
+ 3
3 #
+ ��
+
��
����
����
+
+
��
��
+ ��
) $
��
$
+
�� *
# !
+
+
+
+ �� $ ��
����
��
����������
+
+ ! ��������
+
+
% 1
+
&
#
%
+
& ! & "
' %
&
+
'
+
+
+
��������
��
������ ����
����
+ �� ��
+ ������ �� �� ��
+
+
����������
������
���� ��
������
��
����
��
* ������ ���� ������
+ ������
+
+ ���� ������ �� �� ����������
���������������� ��
+ ��
����������
�� ������������������ ������
+
+
+ ��
�� /
+
+
+
�� ����
$
+
+
+ ������
����
����
& ������
�� ! ' ��
��
+
+
+
�� ��
#
��
+ #
����
"
��
+
������ ��
������
�� ���� ������
���� ��������
�� ��������
����������
+ ��
������
��
+
����
+
����
+ ����
+
+ (
������
������
������ ������
��
����
������������
�������������� �� ���� ��
+ ������ ��
+ ���������� �� ������������ ��
+
�� ��
(
!
��
������ ��
��
+
+
+
��
+
"
+ !
��
+
������
+ ��
����
+
���� ��
+ ������
+
+ ������ ���������� ������ ������ ������������������������������������������������������������������������������������������ �������� ���������������������������������������� ������������������������������������
���������� �� �������������� ��
+ ������������ ���� �������� �������������� ���������������������������� ������������������������ ������������������������ �������������������������������������� ���������������������������������� �������������������� �������������������������������������� �������������������������������������������������������������� ���������������������������������� �������������������������������������������������������� ����
+ ������������ ���������� ���������� �������������� ���������������� ��������������
�������������� ���� ��������������������������������
���������������������������������������������������������� �������������������������������������� ������������ ��
�� ��
+
����
+
����������
+
+ ���� ������
������
�� �� ��
���� ����
���� ��
+
������
+
����
������ ����
����
�� ���� ������
���� �� �� ���������� ����������������
+ �� �� ��
���� �� ������ ���� ���� ������
+
��������������
+ ����
+ ��������
�� ������ �� �������� �� �� �������� ��
�������� �� ��
����
+
+
������
��������
�� ����
+ ������������
+
�������� ���� ������ �� ���������� ������
+ ������������
�� ������ ���� ������ �� �������� ��
+
+ ���� �� ! ��
��
������ ����
+
+ ����
����
+
�� ��
+
��
+ ���� ��������
+
+
�� ����
+
��������
+ �� ����
��
������
+ ����
+ �� ������ �� �� �� ����
���� �� ��
+
����
+ ����
+ ��
��
+
����
+ �� ������
+ ��
$
+ ������
��
+ ������ ( �� ����
����
+ ��
������
���� �� ����
+ ������
��
����
+
+ ��������
�� ����
+
��
���� �� �� �� ��
����������
������
���� ���� �������� ��
!
��
��
+
+
#
+ �� ��
+
+
' ��
+
+
+
+
+ "
��
+
+
!
+
��
-
+ ����
��
��
��
+
+
+
+
+
%
��
+
+
��
������������������������ ���������������������������������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������������� ������������������������������������
�������������������������������������������������������������������������������������� ���������������������������������������������������������������������������� [...]
"
" ! "
#
!
%
!
+
$ $
�� # "
+
" $ !
%
+
+ (
+
%
+
! &
(
��
% "
"
" * 2
+
"
)
��
+
! $ !
+ ��
' " "
$
%
+
#
! ' ' %
+ ��
+
+
$
�������������������������������������������������������������������������������������������������������������������������� ������������������������������������ ���������������������������������������� ���������� ������������������������������������������ ������������������������������������ ���������������������������������������������������������������������������������������������������������������� ��������������������������������������� [...]
+ ����
+
+
���� ����
+ �������� �� ������
+ ���� ��
+ ������
�� ������
+ ���� �������� ���� ��
���������� ����
+ ������ �� ������ �������� ������������ �������� ���� ������������ �� �� ������������������ �� �������� ��������������������
+ �������� �������� �������������� ���������� ����
+ �������������� ���������� �� ���������������� ���������� ���������������������������������� ������ �������������������� ������������������������
�� ������������ ������������ �������������������� ������������ ���������������������� ���� ������������������������������ ���������������������������� ������������������������ �������������������������������� ������������������������������ ��������������������
+
+
+
+
+
+
+
+
+
+
+
&
+
+
��
+
+
+
+
!
%
+
"
+
+
+
&
+
+
+
������������ ������������������ ���� ��������
�������� ����
+ ������������ ������ �������� ���������� ���� �� �� �������� ����
����������
+
+
������������������ ��
+
+ ���� �������������� ���������� ��
������������ ������ ����������
������������ �� ���� ��������
�� ���� ���������� �� �� ����
+ ����������������
+ ������ ������ �� �������������� ������������ ������ �������������� ������������ ������ ����������
�� �� ������������������
��
�������� ������ ������ ���� ������ ���� �������� ��������
+
������ ������ �� ������ ���� ���� ����������
������������������
+ ���� �� ������ ������ ��
�� �� ���� �� ������ ��������������
�� ���� �� �� ���� ������������ ����������������
���� - ) * 3 ,
" % +
& "
+
+
%
" ,
"
! ' 0 %
+
+ " .
' ! '
# 3 $
)
% +
$ 4 ! ��������
' . +
% , !
"
+ " 5 1 * ( # $ 4 * ������ ) * ! / : 2 ��
$
# . !
& #
% +
)
+ ' ) # & # " ��
* + 7 %
�� ! $ / - # #
$
% # $ $ % "
' 0 ��
' # �� !
+
% 4 . * ������
+ . )
+
#
+
*
1 G +
$ #
% % !
+
+ . & " #
)
����
+ . 8 8 / #
- '
�� �� ( , ������ ��
$ ������
+
+
���� !
+ ��
+
%
+ ����
+
+
�� # + ������ ����
" , ����
�� % 3 -
+
+ �������� ( + $
! #
�� ��������
$
"
��
+
����
+ & %
% 4 "
���� 2 -
���� + ' , ��
+
+ "
#
" ����
#
����
! # #
$
�� ������ ��* 4 4 , " # " " " " ��
����
$
+
+
��
+
+
+
+ ��
+
+
+
��
����
-
��������
��
+
+ ��
����
��
+
+
����
+
!
"
����
���� ��
��
+
+ $ *
+
�� ��
!
+ ��
+
+
+ !
% # ��
' ����
+
$
( + & $ $
$ # $ (
+ " ��
& # &
+
0
+ ��
' #
+ ' -
+ ! + )
# $ # ���� ��
! % ��
+ ���� )
+
+
#
! ! " �� ! ( &
, &
��
8 &
��
������
% )
* ) + !
+
! &
" %
* 0
* *
# ( ' "
) ,
% !
#
$ !
!
+
����
��
��
����
�� ��
�� ��
���� ����
+
��
+
+ ����
+ ��
����
+
+ ( ������
������
����
+ ��
+
�� ����
����������
+ ������������
+
+
+
���� �� ����
������
+
+
# )
+
+
$
+ ����
������ ���� ��
+
+
��
'
+
+
+
+
+
!
����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
���������������������������������������������������������������������������������������������������������������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ �������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ���������������� ������ �������������������������������� ������������������������ ���������������������������������������������������� �������������������� �������������������� �������������� ���������������������� ������������������������������������������������������������� [...]
��
���������� ���� �������� �� ����������
+
+ ���������������������������� ���������� ������������ ���������������������������������������������������������������� ������������������������������������������������������ ���������������������������������������������������������������� ������������������������������
�������������� ������������������ �������������������� ��������������
���������� ������������ �� ������ ��������
������ �� ���������������������� ���� �� ������
������ ������������ ���� �������������������������������������� ��������������
������������ ���� ������ ����
���������������� ��������
�������� ���������� ���������� ������ �������������� ������������������������������������������ ���������������������������� ��������
������ �� ������������
+ �� ��
+ ������������������������������ ������
+
+
+
����������
+ ���� ��������
������
�������������� ������ ���� �������� �������������������������������������������������������������� ���������� �� ������ ������
�������������������������������� �� ������������������������ �������� �� ���� ����
+ �� �������� ������ �������� ���� ���������� ������������
+
������
+ ����������
������
����
�� ����
+ �� �������� ��
��
������
+ ��
������ �������� ������ ���������� ����������
����������
������������
! ) 4 + , ���� % ��0 m s 3 �������� 1
< 6 $ 2 ��9 ��" ��������������������
+ ����( $
��������������# E ������������8 R >
G ��������
% t Z f F ������������� � E ������������E �� � Q
+ ��! J
�� ��B " ������I � � H D i � F 6 1
+ 6 m | � # ���� C D ������E ��
! ������ , w 5
�� H # �� ��������������3 ������0 X 2 ������ ����Z�
�]�F � @ �� ����������������p�c�z����������������� < ��������������s�e�_�B�E�a�a�}�������������
> S 9 �������� �� * ������ ! 6 5 0 $
�� ����
����������Z�q � � � I ���������� * �� : # �� s n | � � � � & J ��Z 2 , ��� � � � � � � z 0 2 \ � F ���� B � � � � � � k m � � � x j A ] � � � � � � � � ����) R L V e ] ; 5 P v = ~ ] * @ J L Z @ 6 W � p t ������������J �� # ��$ / u u
& \ ���� D # � � 8 H 1 ������9 � \ ( A R . ����
R 6 > ; # �������� . ) d f O 0 9 4 % ����������9 ' ����: J R P ! > " " ? 5 - # / &
* ��- ` t [...]
" H L * > o I �������� = 3 b ` T ^ @ ����A ( , ��������
+ �������� 8 O Q
' ������ < 1 �������� ) q � V } < ������������- 2 L J G 3 ��
. , ���������� 4 > ���� ��% < ? .
+ �� ����
& @ U E G H h q H C E - g y { � R ) ��
+ E = �������� ! - * / + B ��
+ 1 & �� ( ���������� �� * - ����
( \ . $ ���������� ���� % ����������������v�m�w��������������� , @ _ / ����������������x�r�T�T�l�u������������� 7 1 K R D ���� > ) + > ( ����
3 )
��������I [ B ����������L � ����P d : ���������� 0 S 3 4 L Y ������] �
+� ( ������| � [ ! Q W t o m � u E 0 I e J 5 9 = _ v � � w b N N m m p g M > V L n � � v � � � � n ���� 5 * . a s ' 8 J 0 ! ' . 1 . / 5 H R D 5 1 # ` q � � K ��! ������������' ; . > > V 3 c ; % ) * @ K z W D ��
[ _ A 6 i i V K ������
* 6 ������
: 6 - D H Q @ ? 1 & ' ���������� ���� 6 W W c K - ���� +
��
' & 1 = 0 B K ] , �������� # $ �� ����������������4 l T ��g�|����� 8 ����! - 5
����> ��
�������������������� �� 1 ������
����
' ��������
( : ; P 9 ���������� % > 0 /
������
+ & ������������ �� �� $ ���� �� C - % ��
���� ' 7 ' - @ X P 9 2 8 D _ s � 7 % ������
��������
+ - �������� ����
���� ��������������������
$ �������� ���������� ������ ����������������k�]�d���������������
% - F ���������������p�f�I�>�V�X�r��������������� 1 d ; ���������� ��������������D H " 8 8 4 ( $ ��������* *
��������������& W { g > ����������
0 0 7 @ 8 _ k � � D $ ��( $ * U Q L R Q } t C 4 G Z ) ) $ _ _ � ^ f L < T S K < & - : A e d r j ~ � � � T ����
��2 T " ? 5
< 5 =
# J a V Z
���������������� ( ��
! , 6 �� P �� " * E _ @ A ���� $ ; 7 ! G ? .
+ ���� 2
+ # , & ���� ) ' : - > 7 4 , % $ ����������)
��
) @ 8 M <
����
����
0 / K b # ������ ( / ( "
+
* ( 6 v s A # ���� - K C @ 5 0 A ) ��# ������ ���������� $ ! 5 E %
( # �� #
. : ����
> J I a N ���������� 3 = : 9
4 . �� ����
2 " ���� * O < 6 $ ��
< M ? A O o d K K T - 2 V d p � E 7 �� #
��
/ - # 0 " 9 �� ��
% *
+
���������� ������ ������
+ $ �� ��
+ * ��
% ! ������������������l�x������������� $ : I \ / ��������������������h�^�s�z������� �� ' 5 D W C
+ ��
.
������ > G 3 > E G ; * �� ��
< 8 & ���� ������ 0 _ � t I �������� - / 9 8 ; ! # ' A < h p � � L ) / , ��- '
- K H G H V { } M 7 F V -
1 0 _ h | ` e U C T R M 9 * < K N l o w r � � � � X ����
��4 V ( @ ; & : # ! ' ) : : & " % J e g ^ �������������� # 4 ��
+ , �� F �� - 2 I [ ; # I
9 5 % C ? $ 1 ���� + # , & ������ # " 5 2 = < 8 4 % " ����������+
��
4 K A Q B ��
% - ' ; W f 1 $ ������
������������������������������������������������������������������������������}�+����������������L�s����������������
�$�
�
�&�0�2�6�5�@�H�<�6�N�E�>�D�D�8�4�3�3�*��
���������������v�Z�T�E�4�!�
�������������v�V�D�)�������������������������������������������������������������������������������������������������������������������������� [...]
+ �� ������������ ��������
������������ ��
����������
���������� ' ! ��������������
��������
������������
+ �� ��
�� ������������ ���������� �������������������������� �� ����������������������������������
������ ���� ������ ����
+ ���������������� ���������������������������������������������������� ������ ���� ���������� ���� ������������ ������������������������������������ ��������������������������������������������
�� ������ ������ ��������
+ ��
���� ��
��������
��������
���� ������ �� ��
��
+
��
��
+ �������� ���� �������������� ����
���������� �� ��
+ �������� ������ ����
+ ����
����
���� ������
+ $ �� ��
+
%
+ ����
+
������
4 ) ��������
��
�� ����
+ ������������ ������ �� �������������������������� ���� ���������������������������� ��
��
+
+ ����
���������������� ����������������������������������������������������
����
������
�� ���������� ������������������������ ���������� �������������������������� ��������
�� ��������
+ �� �� �� ��
+
+ ������ ������
��
�� ����
+ ��
+
"
+
+ ��
������ ��
+ % ������
+ �������� ��
���� �� �� �� # &
!
����
������ ���� ����������
������
������ ��
. �������� ��
�� �� ������ �� �� / (
+ ��������
�� ���� ��
+ �� # ��������
���� ���� �������� ���� �� �������������������� ������ �� ���� ����
������ ������
+ ���������������� ������ ������������������ ���������� ��������
������ ��
������ ����
���������� �������������� �� ���������� �������� ���� ������ ��������
+
+ ��
+ ���� �� �������� ��
+
+ ��
������
�������� ��
��
������ �� ��
������ ���� �������������� ����
+
+
�� ���������� �� �������� ������ ����
��������
+ ������ ��
+ ���� ����������
������
����
+ ��
+
# ����
+ ������
+ ��
������ �� �������� + % ����������
�� �� ����������
�� ��
+
��
���������� ���������� ��������������������������
+ ���� ����������������������������������
���� ��
���� ��
���������������� �������������������������������������� ������������
������
+ ��
+ ������ ���� ������������ �� ���������������� �� ���������� �������������������������� ��������
+
�� ������ �������������������� ���������������� ������������ ���� ��������
��������
���� ������
�� �� ���� ���������� �� ����
��
���������� �������������������������� �������� ������������������ �� ���������� ��������������
+
+
�������������� ���������������������������������������� ������
�������� �������������������� ������ �������������������������� �� ��������������������
����������
+ �������������� ! �������������� ����������������
���������������� ���� ���� ��
������������������������
+ �������������������������� ����
������������������������������
������ ��
+ ������ ���� ����������������
������������������������������������������������������
������ ��
+ ������ �������������������� ������������������������������������ �������������������������� ��������
��
+ ���� ���� ������������ ���� ���� ��
����
��������
������
���� ��
+
+ ����
����������
����
+ �� �������� �� ���� ��
�� �� % " !
��������
������ ��
+ ���� ��������
������ ������ ��
�� ��
+
! ����
+ ����
+
+
+ ��
�������� �� ��
, # ������������
�� ����������
�� ��
��������
+ ���� ���������������������� ���� ������������������ ������ ���� ��
������ ������ ���������������� �������������������������� ���������� �� ������
+
������ ��
������
���� ���������� ���������������� �� �������� �������� ������ ������ ���������� �� ���������������������������������������������� ���������� ���� �� ���������� ��������
+ ���� ������ �� �� ����
+ �� ������ ��
��
+ �������� ���� ��������������������
+ ������
����������������
+ ��
+ ��������
+ ������������
+ ������������������������������������ ���������������� ��������
�������� �������������������� �� �� �������������������������� ��������������������
+
����������
���������� ���� !
+ �������������� �� ���������� �������������� ���� ����
+ ��
������������������������ �������������������������� ����
��������������������������������
+ ������������ �������������� ������������������
�������������������������������������������������������� �������������� �������������� �������������������� ������������������������������������ ��������������������������������������������
+ �� ���� ������������������ ���������������� ����������
��
��������
+
������ ���� �� ���� �� ����
+
��������
+ �� �������������������� ������
+ ����������
������ ���� �� �������� ���������� ���� ������ ��������
������ �������� �������������������� �� �������������� ���������� ��������������
����������
������������ �������������� �� ���������� ������������
���� ��
�������������������� ���� ������������������
���� ������������������������������
���������� ���� ��
+ ������������
������������������������������������������������������
������
+ �� �� ����������
�������������������� �� �� ���� �������� ������ ���� �������� �� ������ ������ �������������������� ���������������� ����������
�� �� ���������� �� ����������
+ �� ������ �� �� ����
�� ������
+
��������
+ ��
+ �������������������� ����
+
+ ������������ ��
+ ���� �������� ��
������������ ���������� ���� ����������������
����������
������
�� �������������� �� �������������������������� ����������������
�������� ����������
$
�������������� ���������� ��������������
+
���� ����
��
������������������������ �������������������������� ����
�������������������������������� �������������� ������������������������������������
+ �������������������������������������������������������� ���������������������������������������������������� ������������������������ ����������
�������������������������������������������� �� ���� ���������������������������������������������� ������������ ���� �������������� �� ����������
+ �� ������ �� �������� ����������������
�� ��
�� �������� ���� �������������������� �������� ���������������� ����
+ ��������
������������ ����������������������������������������������������
����������
������
+ �������������������� ������
�������������������������� ��������������������
����������
+ �������������� �������������� ����������������
+ �������������� ����������������
���� ������������������������ �������������������������������� �������������������������������������������������������������������������� ������������������ �������������������������������������������������������������� ������������������������������ �������������������� ������������������������ ����������
�������������������������������������������� �� ������ ������ �������������������������������������� ����������
�� ���������� �� ����������
�� �� �������� �� ������ ����
+
��������
�� �������������������� ��������
���������������� ���� ��������
������ �� ������������ ���������� ���� ����������������
������
������
�������������������� �� ������������ ������ �� ����������
+
��������
���������� &
������������
����
+
+ ������������
+ ������ ����
������������������ ���� ���������������� ����
�������������������������������� ����������������
+ �������������� ��������������
��������������������������������������������������������
+ ������ �� ������
����������������
������������������������ �� ���� �������� �� ���� �������� �� ���� ���������������� �������������� ��
+
+ ��������
������
+
����
#
+
+ ��������
+ ����
����
+
+
+ ! " ! " $ ��������
+ ��������
+ ������ �������� ������ ������ �� �� �� ���� ��
����
������
, $ ������������
+
����
����������
+ �������� �� ���� ���� �� �� ������
��������������������������
���������� ������������
+ ��������������
������������������������������������������ ����������
������������ ������ ������������������
������������ ������ �� ��
+
+ ������ �� �� ���������� ���������� ����������������������������������������������
+
�������� �� ���������� ��������
��
+ ������
�� ��
����������
+ ���� ������ ��
������
������
+ ��������
�� �� ��������
������ ����
���� �� ������
��������
+
�������� �� ��
)
������������
���� ������������
+
���������� ���� �� ��
����������������������������
+
����������
+ ���� ����
������������
��������������������������������������������������������
+
������ ���� �� ������ ������������������
+ ������������������������ �� ���� �������� �� ���� ��������������������������������������������������������������������������
+
+ ������ �� �������������� �� ��������
+
���� �� ������ ����
�� ��
����������
+ ���� ��������
������
������
������
���� ����������
����������
������
���� ������ ��
�� ��������
��������
����������
& �������������� �� ����������
�������������� ���� ��
+ ���������� �� �� ���� �� �� ������ ����
������������������������������ ������������
+ ��������������
����������������
+ ����������������������������������������������������
������ �� ������
+ ����������������
������ ��
+ ������������������������������������������������������������������������������������������������������������������������������������������������������ ���������������������������������������� ������������������ ���� ���������� ������������������ ���������������������������������������������������������������������������� �������������� �������������������������������������������������������������������������������� ���������� ������������������������������� [...]
�� �������������� �� ����������
+
�������� ������������
��
��
+ ��
����
+ �������������������� ����
������������������ ����
+ ������
������������
���������� ���������� ������������������������ ����������
������ �� �� ��
�������������� ���������� ������������������
���������� ��������
!
�������������� �� ������������ ����������������
+ ������ ��
+
���� ���������������������� �������������������������� ���� ���������������������������������� ������������������ ���������������� ������������������ �������������������������������������������������������� ������������������������������ ������������������ ������������������������ �� ������
���������������������������� ��������������
+ �� ������ ��������
������ ����
+
����������
+
+ ��������
�� ������ �� �� �� ��
���� ������
+ ��������
���� �� �� ������������ ���� �������������������� ������ �������������������������������������� ��������������
���������� �������������������������������������� ��������
���������� ����������������
������������������������ �������������� ���������� ��������������
#
+ �������������� ����������������
+ ������������
������ ���� �� ������������������������������ �������������������������������� ���������������������������������� ��������������
�������������� ������������������ ������������������������������������������������������
+ ������ ���� ������
�������������������� ���������������������������������������������������������������� ����������
�� ������ ���������������� ���������� ���� ���������� ������ �������������� ������������������ ������������ ���������� ����
�� �� ��������
���� �������������������������� �������������������� ������
+ ����������������
�� �������� ��������������
����������
+ ������ ���� ����������������
+ ��������
���������� �������������������� �� �� ������������ ���������� ������ ����
���������� ������������
+ %
+ �������������� ���������������� ������������ ���� ���� ��
���� ������������������������ �������������������������� ���� �������������������������������� ������������ ������ ��
����������������
������������������������������������������������������
����
+
�� ����������
������������������������������������ ������������������ ��
������ �� ������ �������������������������������������������������������������������������������������������������������������� �������������� ���������� ����
+ ������������������
���������������� ���������������������������������������������������������������������� ���������������������������������������������������������������� �������������� ������������ �������������������������� �� ������������ ������������������������������������������ ����������������������������������������������������������
+ ��������������������������������
���������������������������������� ������������������������������������ �������������������������������� �������������������������������� �������������������������������� ������������������
����������
����������������
�������������������������������������������������������� ������������ ������
�������������������� ����������������������������������������������������������������������������������
�� ���� ������������������ ���������� �� ������������ ������ ����������
+
��������
�� ������
+ �� �� ����
+ ���� ��
+ ��
+ ���������� ���� �������������������� ������
+ ������������ �� �� �������� ��������������
������
������ ���� ����������������
������
+
+ ������ ������������������ ������ ������
�� ��
+
��������
�������� ( �������������� �� ���������� ������������
�� ����
+ ������������������������ ������������������������ �� ������������������������������
+ ������ ��
+ ����
+ �������������� ���������������������������������������������������� ����
+
+ �� ���������� ������������������������������������ ������������������ ����
+
+ ��������
�� ������ �������������������������������������� ���������������������������������������� ������������������ ������������ ���������� ������ ������������������ ��������
+
���� �������������������������� ������������������������������ ������������������ ���� ������������������������������
+
�������������� �������������������������������������������� �������������� ������������������������������������������ ���������������������������������������������������������� �������������������������������� ���������������������������������� ���������������� ���������������� �������������������������������� �������������������������� ����
+ �������������������������������� ������������������ ���������������� ������������������ ������������������������������������������������������������������������������������������ ��������������������������������������������������������������������������������������������������������
��
+
+ ���� �� �������� ��������
+
+
�� ��������
�������������� ����
����������
+ ������
������������
+ ��
+
�� ��
������ ������ ����
����
+ ��
+
��������
��
- % ������������
����
������������
+
���� ����
�������� �� ���� �� ��������������������������
+ ������
+ ���������� ����������������������������������������������������
���� �������������������������������� ����������
����
�� ������������������ ���������������� ������������ ������ ��������
+ ��������
������ �� �� ���� �� ���� ��
+ �������� ���� ������������������������������ ������������ �� ��
+ �������� ��������������
������������ �������� ���� ����������������
+ ������
���������� ������������������ ������������ ���������� ������ ����
+
��������
��������
&
+ �������������� �� ���������� ������������
���� ����
������������������������
������������������������
���� ������������������������������
����������
����
��������������
������������������������������������������������������
+
������
+
�� ����������
������������������������ ���������� ���������������� ����
+
+
�������� �� ���� ���������� ���������������� ���������� ��������������������������������������������
��������
+
�� ����
+ �������� �� ���������������������������� ���� �������������� �� �������� ������������������ ��
+ �������� ���������������� ������
+
+ ����
������ ��������
+ ������ ���������� ������������������ ������ ������
+
+ �� ���������� ��
��������������������������
+ &
�������������� ���� ����������
���������������������������������� ������ ������������������������
+ ���� ����������������
+ �������������������������������� ��������������
+ ����
+
+ ���������� ��������������������������������������������������������
������
+
��������
������������������������������������ ������������������
������
�� ���� �������������� �� ���������������� ���������� ������ �������������� ���������� ���� ����
�� ���� ���� ��
+
���� �� ���������� ���� ������������������������������ ���������������� ��
+ �������� ��������������
+
������������ ���������� ���� ����������������
+ ������
�������������������������������� �� �������������������������� �� ���������� ���������� ����������
$
�������������� ���� ���������� ������������ ����������������
+ ������������������������
���� �������� ������
+ �������������������������������� ������������
+ ����
����������
��������������������������������������������������������
����
+
+
��������
�� �������������������������������� ����������
+ ������
+
+
��
+
+
��������
�� ��
+
#
+ ����
������
��
+ ������
�� ���� ��
+
+
+
������ ������
+
+
+
+
+ ������
5 ) ���������� ��
+
+ ������������
+ ����������
+
+
��������
+
+
+
����������������������������
������
"
+ ������ ������������������������������������������������������ # "
������ �� �������� ��������
+
+
��
+
+ �� ���� ������������������������������������ ���������� �� ����������
+ ��������
����
�� ����
��������
+
�������������������� ��������
���������� ��
��������
+ ������������
�������������� ���������� ���� ������ ��������
������
���������� �������������������� ������������������������
+ �� ����������
+
��������
����������
+ "
�������������� �������� ������������ ������������ ������������������������
���� �������� ������
�������������������������������� ������������ ������
+ ������������
��������������������������������������������������������
+ ������
�� ���������� ������������������������ ���������� ��������
+
�������� �� ������ ������������������������������������
+ ������
���� ������������ ��������
�� ����
+ ����
�� ��
��
+
��������
+ �������������������� �������� ���������������� ��
+ �������� ������������
������ ����
���� ��������
������
������������������������������ ������ �������� ����������
���������� ������������
&
�������������� ���������� ������������ ����������������
+
���� �������������������� ���� �� �� ������
��
������������������������������������������������ ����
+ ����������
�������������������������������������������������������� ������
�������� �������� ���������� ����������
��������
+
������ �� ������ �������������� �� ��������������
������
���� �������������� ����������
����
+ �� �� �� ��
+
+ ����
��������
+ ������������ �� ������
+ ���������������� ��
+ ��������
+ ������������
+
������
+
��
���� ��������
������
+
���������� �������� ���� �� ������ ������
+
��������
���������� ������������
) ��������������
+ �� ���������� ������������ ���������������� ������ ������������ ����
+
+ �� �� ������
������������������������������������������������
+ ��
+
���������� �������������������������������������������������������� ������ ��
+ �� �� ���� �������� ���������������������� ����������
+
������ �� ���� �������������� �������������� ��
+ ��������
+
+ ������
+
+
+
+
+ $
"
+
��������
�� ����
+
+ ������ ��
+ ������
����
+
������ �� ��
+
+ ���� ��
��
������ ��
+ ! ������������
��
������������
���� ��
���������� �� ���� ��
�������������������������������� ������������ ���� ����������
��������������������������������������������������������
+ ������
�� ����������
������������ ������ �� ���� ����
+
+
+
������ ���� ������ ��������������������������������������
+
������
+ ����������
+ ��������
����
��
��
���������� ���� ���������� ��
+ ��������
������ �� ������
+ ���� �� ��������
������
+
���������� ������ ��
���� ������
��
��������
��������
+ * ! ������������ ��������
������������ ������������
������������ �� �� ��
+ �� �� ������
+ ����
+ �������������������������������� �������������� ���� ����������
�������������������������������������������������������� ������ �� ������
���� ����������
���������� ���������� ���������� ��������
+
+ ���������� ���������� ������������������������ ��������������������
����
����������
+ ��������
+
+
����
+
+ �� �� ��
+ ��
+
+
����
���������� ����������
���������� ����
+ ��
��������
������ �� ������ ������ �� ������ ����������
������ ��������
��
+
�� ������ �� �������� �� �� ����
+
��������
����������
+
) "
�������������� �� ����������
������������
���������� ������������ ���������� ���� ���������������� ���� �������������������������������� ��������������
+ ������������ ����������������
+ �������������������������������������������������������� �������� ������������������ ������������������ ������������ �������� ���������� �������� �� ��
���������������� ���� ������ ������������������ ���������������� ������������ �� ���������������� ��������������������������������������������������������
+ !
"
! "
"
������
������ �������� ����������
+ �� ������������
+ �� �������� ��
+
����������
�� �� ���������� �� ���������� ���������� ���������� ������
��������
�������� ) ! ��������
+
+ ����
��
+ ���������� �� ��
+ ���� ��������������
+
�� ����
+ ��
��
+ ���� ��������
+ ����
��������
+ ��
��
+
+ �������� ������ ����
��
+ ����
+ ������ ���� ��
������
������ ����
������ �� ������������������ �������� �� �������������� ������������������
������ ������ ���������� ������ ������ �������� �� ������������ ������������ �������������������� �������� ��������������
+ �� �������� ������������ ������������������������ ����������
+
���������� �������������������� ������ �������������������������� �������������������� ���������� ������������������
�������������� ���������������� �� ������������ �������������� �� ������������������������������������������������������������ ����
���������������������������� �������������� ������������ �� ������������ ���������������� ������������������������������������
+ ������������ ������ ������������������
+ ������������������������������������ �������������������������������� ����������
��������������
���� �� ������
��
�������� �� ������������ ������������
+ �� �� ����������
+ ���� ���� ��
+
��
�� ����������
+ ��
������������
��������
�������� �������� ������
�� �� ��������
�� ������ ������ ������ �� ��
+ �������� ���������� �� �� ������ �������� ����������
+
+ ����������
���� ����
+
���� �������� ��
���� ���������� ����
���� ��
+ ��
+
+
��
" !
����������
+ ����
+
��������
�������� ������ �� ��
������ ������
+
������
�� ����
+
��������
��������
��������
+ �� ��������
+
+
+
��
�� ���������� ��
������������ ��
������
+
+ �������� �������� ����������
������������������
�������� ������ ������ �������������� �� ������������ ���������� �������������� ����
+
���������� ������������ "
������������ ��
���� ���������� ���� ����
���������� ����������
+ ������������������������
�������������� �������� ����������
�������������� ���������������� ������������������������������������������������������
+ ������������ ������
+ ������ ������������ ������������������������ ���������� �������������������������������������������� ���� �� ����������������
+ ���������� ����
+ �������� ��������������������������������������������������������������������������������
�������������� ���������������� ������ �������������������� ���� ���������������� �� �������� �������������������� ���� ���������� ������������������
������������ ����������
+ ������������������������ ��������
���������� ������������������ ���� �������������������������� ��������������������
������������������������������ % �������������� ���� ����������
�� ������������
����������������
������ ������������������������ �������������������������� ����
���������������������������� ������������ ���������� ���������������� ��������������������������������������������������� [...]
������������������������������������ �������������������������������� ����������
+
����
+
+
����
�� ��������
+ ������
+ ���� ��������
+ ��
+
����
������ ������
+
���� ��
������������������
����
+
+ ���������������� ��
+
��������
�������� ������������ ���������� �������� ������������ ��
��������
���������� ������ ������
+ ���� �������������������������������������� �� ������
��������
����������������
������������
������ ������ ����
+ ����������������
+ ������������������������ ���� ���� ���� �� ����
��
��������
���� ����
+
+
���������� ��������
�� ������
+ �� ����������
�������� �������� ������ �������������������� ������ ��������
+ �� ����
������������
��������
+ ������ ���� �������������� �� ������������ �������������� ������ �� ����
�� ���� ������������ �� �� ����
�� �� ����������
���������������������� ����
������������������ ���� �������� ��������������
+
���������� ������������ ���������������������� �� ��������
���������� ������ �������� ���� �������������������������� ����������������������������
������������ ������������������
�������������� ���� ���������� ���������������� ���������������� ������ ������������������������ ������������������������������ �������������������������������� ������������
���������� �� ���������� ��������������� [...]
+ ������������������ ������������������������ ���������� ������������������������������������������������ ����
���� ����
+ ����
����
+
�� �������� ����
+
�� ��
+
���� �� *
�� ����������
+ ���� ����
+ �������� ����
������
������ ���� �� ) ������ �� ������ ������ ���� ��������
+ ���� ������ �� ������
��
������ ����
+ ������������ �� ��
������������
�� �� �������� ���������� 5 $ ���������� ��
��
��������
+ ������
�� ���� ���� ��������
���� ������ ������
�� �� ��������
+
+ ��
�� �� ��
��
��
+
��
+ ������ ������
������������ ��
+ ���� ������
+
����
�� �� & ������
����
+
������ �� ����
+ ������������
+
��������������
+ ��������
+ ������������������������ �� �������������� ������������ ������ ���� ���� ������
+ ������������ �� ���� ������������������ ���� �������������� �� ������
�������������������������� �������� ����������������
���������� �������� ������������������������ ��������
���������� ������������������ ��
+ �������������������������� ���� ��������������������
���������� ���������������� #
+ �������������� ���� ���������� ������������ ����������������
������ ������������������������ ������������������������������
+ ������������������������������
+ ������������ ������ �� ���������� ���������������� ������������������������������������
+ ������ �� ������
+
���� ���������� ������������������������������������ ������������������������������ ������������
���������������� ���������������� ���������������� ������������
���������������������������� �������������������������������������������������� ���������������� ������������������������ ������ ���������������������������� ������������������������������
���������������������������������������������������������� ������������������������������ [...]
+ ����
+ ����
+ ����
+ ��������
��������
���� ���� ��
+ ��
+
+ ��������
���� �� �� �������� ������
�������������� �� ����
+ ������������������ ���� �������� �������������� �� ��
+ ���� ����������������
������
������ ������ ����
+
+ ���������� ������������
+ �� ������������������ ���������� ������������ %
������������
+ ����������
������������
�� ���� ���� ������������������������
������������������������������
���������������� ��������
������������ ����
�������������� ���������������� ������ ��������������������������
����
�� ���������� �� �������������������� ���������� �������������������������� ���������� ���� $
������ ���� /
$ % ���� '
$
+
+ ���� ������
�� ���� ! " " ���� &
+
! % "
����
+ ) ' %
���� ��
+
���� )
+
+
������ , '
+
+ $ # ( ������ �� & #
����
+ ������# * 2 )
������
��
����
������������
+ ���� ����
!
' &
�� ���� - T : $
�� ���� " .
+ ��
!
"
. �� " , # ( $ 1 " �� , 5
���� !
, 1 �� ����
���� !
��
������ & & % -
+
$ ����
+ & # '
����
# $ 4 0 �� ! $
&
������ ) ' $
4 $
+ ! / * ' &
! , + !
+ ���� - ;
# ���� $
�� $ /
��
+
+ ��������
���� ������
+ ������ ����������
+ �������� �� ������������ �� �� �� ����
+
��������
+
+ ���� �� �� ���������� ���� �������������������� ������
+ �������������������� ���� ���������� �������������� �������� ������ ��������������������������
+ ��������
+ ���������� ������ ������ ��������������������������
+ �� ���������������� ������������ ������������
+ ( ������������
+ �������� ������������ ���� ���� ���� ������������������������ �������������������������������� �������������������������������� ������������
�������������� ���������������� ������������������������������������������������������
+ ������ ���� ���� ������
������������������
+ ������������������������ ���������� ���������������������������� ����������
+
��������
+
+ ������ ���� ���������� ��������
���� ������ �� ��
+
+
������
���� �� �� ���������� ���� �������������� �� ������
���������������� �� �������� �������������� ������ ������ ���������������������� ������
�������� ������ ��������
+
+ ���������� ���������� �� �� �� ���������� ������������ ) ������������ ���������� ������������
+
���� ���� ���� ������������������������ �������������������������� ����
��������������������������������
�������� ��
����
+
���������� ��������������������������������������������������
����
+
�� ����������
�� �������������������������������� ������������������ ������ �������� �� ���� ��������������
+ �������� ��
��������
���� �� ����������
+ �������������� �������������� �� �� ��
+
+ ��
��������
+ ���� ���� �������� ���� �������������� ������
������������������ �� ���������� ������������ �� ���������� ���������������������������������������� �� �������� �������� ������ ����
+ ������������������������
+ �� ����������������
+ ����������
�������������� ( ! ������������ �������������� ������������ ���������� ��
������������������������������ �������������������������� ���� ���������������������������������� ������������
���������������� ���������������� ����������������������������������������������������
������ ���� ������
+ ���� ���������� �� �������������������������������� �������������������������� ���������� �� ���� ���������������� ����������
��������
����������
������������ �������� �� �� ����
+
�� ��
+
������
�� �� ���������� �� ����
������������������ �������� ���� ����
�������� ���������� �������������������������� ����������
�������� ���������� ������ �� ������������ �������� ������������ ��
+
+ ����������
������ �� " # ����������
���� ��
+ ������������
�� �� �� ������������ ���������� �������������������������� ����
������������������������������
�������������� ������������������ ����������������
����������������������������������������������������
+
�������������������������������������������������� ������������������������ ���������� �������������������������������������������� ���� ������ �������������� ������ �� ��
����
��������
�� ����
+
+
+
+
��
+
+ �������� ����
�������� ��
������
������
������
+
��
�� ������
������
+ �������� ��
���� ������
+ ����
��������
����������
( ! ������������ ����������
������������
+ ������������ ������������ ����
�� �� ������
+ �������������������������������� ��������������
��
+ ���������� �������������������������� ���������������������������� ������ ��
+ �� ���� ���� ������
���� ��
+
+
+ ������ ���� ������������������������ �������� �������� ���� ��
+ ��������
�� ��
+
��
��
+
+
��������
+ ����
���������� ��
����
�� ��
��
+
�� ��
���� ���� ��������
��������
������
+
���� ������
! ���� ��
+ 2 ( ������������
+ ����
������������
�������� �������� ����
��
���������������������������� ��������
���� �� ������������ ���������������� ������ ��������
�� ��
+
+ �� �� �� ����
����
+ ������������������������������������������������������������������������ ������������ ���� ������������������������������������ �������� �� ����
������ �� ������ ����
��
+ �������� �� ������
+
������������������ ��
��������
������������ �������������� �������� ���� ����������������
����������
����
+ �� ��
+ ���� ������ ������������ ������������ �������������� ����������
���������� "
+ �������������� ���� �������� ���������������� ���� ��
���� ��
��
�� ��
�������������� ����������
�������� �� �������������� ������������������
�������������������������������������������������������� ����������������������������������������������������������������������������������������������������������������������������������������
+ �� ���� �� ����������
������ �� ����
+
+ �� ����
+
��
�������� ��������
��
+
+
+ ���� ��
��
��������
+ ������
+ �������� �� ��
+ ��
! �� ��
���� ��
�� ���� ����������
������ ��������
�� �� ��
������ ��������
+
���� ��
���� ���������� + # ���������� �� ��������
������������ ������
���������� ���� ���� ����������
����
������������������������������ ������������ ���� ���� ����������������
�������������������������� ������������ ������ ���� ������������������ �� ������������ ���� ����������
������ �������� �� ��������
��
�� ������ ������ ���� ��
�������� ��������
" ��
+
��
+ ��
+
���� ��
+
����
��������
��
�������� ���� ���� �� ��
+
����
���� ��������
+ ����
+ ��������
+ ���� ��
+ �� ������ ��������
��
�� ��
��������
����������
������������ ���� ����������
������������
��������
���������� ���� �� ������������������
�� �������������������������������� �������������� �� ��
������������
�������������������������� ���������������������������� ������������������������ ������ ������������ ��
+ �������� ����
+ ������ �������� �� ��������
,
5 $ ��
% (
"
+ $ 1 ,
, ! �� $ ) !
) 3 $
/ B $
/ # % ' * ( ) " & 7 $
5 $ , * 1 + , * + 9 0 ) , $ !
0 * /
# ) ( # ) $ * &
0 , 1 / & # .
% # " # / / . ( * ,
+
��
, & $
) 2 + "
(
0
! * * - ( & ( 2 = ; , % ) 0 ( "
! �� !
3 C 4 &
& . "
$ 3 %
$ :
3 0 # ( , - $ !
+ $
$ 2 "
$
+ ��
= ' $
+
# & # %
0 !
(
+ ( !
����
& " ��
"
& (
��
# ) & % $ )
$
��
�� �� ����
�� ��
��
����������
����������
+
+ ��
+ ��
+
+
+
+ ����
������
+ ��
������ �� �� ��
��
+ ������
���� ��������
��
+
����
+ ������
������
���������� ' # ������������
+ ��������
+ ������������ ������ ��������
+ �� ��������
���������������������������� ������������
�� ��
���������� ���������������� �� ���������������������������� ������������ �� �� �� ���� ������
���� ��������
��
+ ��������
+ �� ������
����
+
+
+ ��
+ ��
������ ����
+ ��������
���� ! ��
��
+ ����
����
����
+
+
+ %
������
���� !
��
���� %
�� ��
+ # & ����
�� ��
��
����
+
���� ! ! ����
���� ��
����
+ ��������
�� ��
�� " ���� ����������
�� �� ��
������
������������
+ ������
���������� ��
�� ������������
+ �� ���� ��������
����
+ �� ������ ������
%
+ ������������
+ ��
������
+ �� �� ���� ���� �� ��
��
����
������
+ ��
+
�������� �� �� ����
+ ���� ���� ����
+ �� �� �� ' ������������
���������� !
����
����
����
+
����
+
������
+
����
������ �� ���� �� ��
�� ���� �� �������� ��
������ ������ # ��
�� ��
+ ������
+
����
��������
'
��
��������
+ ����������
& )
������������
��������
�� �������� ����
����
+ ���� �� �� ������
���������� ���� ���������� ������������
! " ���� ��
���������� �������� ����
+
+ ���������������� �� ������ �������������� ���� ��
���� ���� ������ �� ������
�������� ���� ������������
���������������������������� ��������������
������
���� ��������������
+ ��������
����
��
�� ������
+
+ ������ ����
������ ��
+
�������������� ��
�������� ������
�� �������� ������
+ ������
+ �������� �������� ������������������������������������ ���������� ������������
���� ��������
������ ������������ �������� ����
+ ���� ����
+
$ $ ������ ����������������
+
( -
���������������������������� ��������������
������
+ �� ��������������������
�������� ������ ���� ������������������������������
+
+ ���� �������� ������������
+ ������ ����������
����������������������
������������������������������ ���� ������������������ ������������ �������� ������������ ���� ���� ������ ���������������������������� ������������
+ ��
����
+
��
+ ����
��
������������ ��������
+ ���� ��
�� ����
������
+
+
����
+ ����
+ ������
+
������
�� ������ ��
+
+
��
+
����
�� ��������
+
������
��������
��
������
��
+ ����
��������
+ ����������
* # ������������
�������� ������������ ������ ��
�������� ��
+ �� �� ����
����������������������������
����������
�� �� �� ����������
��������������
+
������������ ������������
+ �������������� ������ ������ ���� �������� ������
������
������������������ ������ ������������
��
+ ��������������
+
���� ������ ���� ��������
+ ����
+
����
+ ����
# ������
����
��
���� "
!
����
�� ������������
�� ��
����
+ ��
+ ������
��������
������
+ ����
��
��������
! ��������
+ ��
������ ����
+
������
���� ����������������
�������������� ������ ����
���� ������ ��
+
+
������������ �������������� ���������� ����
+
���� �� ���������� ���� ��
��������
������������
+ ���� ������������ ����
������������
����
+ ����
+
����
��������
�������� ��������
+ ����
�� ��
+
+
������
������
�� ��
�� ��
��
������
������
+ ��������
+
+
��
����
����
+
+ ������
+
�������� ������
+
����
������
����
+ �������� �� �� ������
+
+
+
�� ���� ��
������������ �� ������
+
�������������� ��
+ ��������
��������������
�������� ��������
���������� �������� �������� ������
��
������
���������� �� ������ ���������������� ������������������������������������������������������ ������������
������������������������
+ �� ����������
+
���������� ���� ���������� ���������� ����
���� ����
+ ����
+
+
��������
+ ����
��������������
�������� �������������� �������������������������������������������������������� �������������� ���������� ���������������������������� ���������������������������� ������������������ ����
+ ���������� ���������������� �������������� ���� ������������ �������������� ���������� ��
��
+ ��������������������
+ �� ������ ���������� ������������ �� ������
����������
+ ���� �� �������������� ���������������� ���� �������� ��������
+ ���������� ������ ������ �������������� �������������������� ������
������������������������������������������
+
+
&
"
$
+
$ +
& ' ) ( % ( '
! ) $ " # +
+
"
* & ( &
* -
+
+
" # &
+
+
+ %
��
'
+
+
+
: 2
����
+
$ $ !
!
��
����
���������� ������ ����
��
+ ��������
�� ��
+
��
+
+
�� ��������
+ ��
+
����
+ ��
������
+ ��
+
+
!
+
����
+
#
��
+
+
������
������
+
+
+ ������ ��
����
+
+ ����
+ ��
��������
������
+ # ��������
+ ��
+
+ ��������
������
+
+
���������� ����
�� ��
+ ������ ������������ �������������� �� �������� �������� ���������� �� �� ������
������������ �������� ����
���� �������� ������ �������� ���������� ���� ����
+ ��
+ ����������
������ �� ����������
�������������������������������������������� ������������ ������������������
����������������
������������������ ������������������������������ ���� �������������� �� ������
+
+ ������������������ �� �������� ���������������� �� ������ �� ����
������ ��������
������
������
������ ����
+ ������ ����
+
+
���������� ����������
&
�������������� ���� �������� ������������ ���������������� ������ �������������������� ���� ������������ �� ���������������� ������
+
+
����������
+
���� ���������� ���������������� ������ ����������������������������
+ ������������������ ������
+ �� ���������� ������������������������ ����������
+ ���������������������������� ���������� ���� ����
��������������
+
���� �� ��������
���� ���������������� ��������������������������������������������������������
��������������
������������ �� ���������������������������� ���� �������������� �� �������� ��������������������������
+ �������� ������������������
+
�� �������� ��������
����������������������
������ ����������
��������������
+ ���� ���������� ���������� �� ���������������� ���������� ���������������� ( �������������� ���� ���������� ������������ ����������������
+ ������ ������������������������
���� ������������������ ��������������������������
+ ���������� ������ �� ������������ ���������������� ������������������������������������
���������������� ������
+ ������ ����������
������������������������������������ �������������������������������� ���������������� ��
����
+
���� �� ���������� ���������������������������������������������� ������������ ���������� ���� �������������� �������������������� ������������������������������ �� �������������� ����
+ ������������������ ��
�������� ����������������
�� ������ ����
������ ������
+
+ ������
+ ������
������ ����
������ ��
���������� ��������
+
(
�������������� ���� ���������� ������������ ����������������
+ ������ ������������ ����
+ �� ��������
���������������� ������
��������
+ ��
+
+ �������� �������������� ������ ���������������������������� ������������ ������
�� ����������
���������������������� ���������� �������������������������� ���������� ����
����������
+
���� ��
��������
�������������������������������������������� ������������ ���������� ���� �������������� ������������ �� ���� ������ ���������� ���� �������������� ����
+ ������������������ ��
+ �������� ����������������
+ �� ������ ����
�� ������ ��������
������
+
������
������ ����
������ ������
�� ���������� ������������ '
�������������� ���� �������� ������������ ����������������
������ �������������������� ���� ���������� ��
+ ������������ �� ������
+
��������
+
+ ����
�������� ������ ������ ������ ��������������������������
���������� ���� �� ����������
+ ������������������������ ���������� ���������������������������� ���������� �� ��
����
+
+ ���� �� �������� ���������������������������������������������� ������������ �� �� �� ������
+ ������������ �� �� ������������������������������ ��
�������������� ����
+ ������������������ ��
�������� ����������������
+ ������
+
+ ��
������ ������
+
+ ������
+ ����������
+ ������ ����
������ ��
+
+ ���������� ����������
* ������������ ���� �������� ������������ ����������������
������ ���������������� �� ���� �� �� ���������������� ������
��������
��
�������� �������������� ������ ����������������������������
������ �� �� ����������
�������������������� ���������� �������������������������� ������ ����
+
����������
+
���� �� ��
������
���������������������� �� �������������� ������������ �� �� �� ���� ������
������������ �� ���� ������ ����������
�������������� �� ������
+ ������������������ ��
�������� ��������������
������ ����
�� ���������������� ������
+
�������� ������ ����
+
������ ������
�� �� ������������ ���������� ������������
+ )
+ �������������� ���� �������� ������������ ������������
+ ������ ������������������������
���� ������������������ ������������������ ������ ����������
+ ����
+
��������
������ �������� ������������������������������������
������ �� ������ �� ����������
+ ������������������������������������ ���������������������������� �������� ��
+ ����
���� ��
+ ���������� ���������������������������������������������� ������������
��
+
+ ����
���������������������������������������������������� ��
+ ������������
+
����
���������������� ��
�������� ����������������
+ ����
���� ������
����
+ ���������� ������ ������
����
+
+
+
+ ���������� ����������
+ " ������������ �� ��������
������������ ����������������
������ ������������ ��
�� ��
�������������������������� �� ����
+ ��
+
+ ������
������ ������ ������ ��������������������������
������ ��
+
�������� �������������������������������� �������������������� ����
������ ����
+
��������
������������ ���������� ���������������������������������������������� �������������� �� �� �� ������
���������������������������������������������������� ��
+ �������������� ����
������������������ ���� �������� ������������������
�� ������ ����
�� ����������������
������
���������� ������������������ ������ ������
+ �� ��������
���������� ������������
+ (
�������������� ���� �������� ������������ ����������������
������ ������������ ������ ���� ������������������ �������������������������� �� ����
��
������
������ ������ ������������������������������������
+
������ �� �� ����������
���������������������������������������������������������������� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
������
���������������� ���������� ���������������������������������������������� ������������ �� ��
+ ������
+
������������������������������������������������������������ �������������� ����
������������������ ���� �������� ������������������
�� ������ ����
�� ����������������
��������
���������� ������������������ ������ ������
+ �� �� ��
���������� ��������������
'
�������������� �� ���������� ������������ ���������������� ������ �������������������� ���� ��������������
+ ����������������������������
������������
+
��
+
+
�������� ������������������������������������������������������
+
������ ��������
���������������������������������������������������������������� ������ �� ��
+ ��������
������������ ���������� ���������������������������������������������� ������������ �� �� ��
+ ���� ������
+ ������������������������������ ���������������������� ���� �������������� �� ������
+
������������������������ �������� ����������������
+
�� ������ ���� ����������������������
��������
���������� ������������������ ��
���������� �� ���������� �� ���������������� ���������� ������������ &
�������������� ���� ���������� ������������ ���������������� ������ ������������������������
+ ������������������������ ����
+ ����������������������������
+ ������������
+ ����
������
���������������� ������������������������������������
+
������ �� ���������� ������������������������������������ �������������������������� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+ �������������������� ���������������������������������������������������������������������������������� �� ��
��������
�������������� ���������� ���������������������������������������������� ������������ ��
+ ����
+
������������������ �������������������������������� ������ �������������� �� ������
������������������ ���� �������� ������������������
�� ������ ����
+ ��������������������
+
��������
+ ���������� ������������������ �������� ������ �� �� �� ���������� ������������
) �������������� �� �������� ������������ ����������������
+ ������ ����������������������
���� ������������������ ��
����������������������������
������������
��
������
������������������������������������������������������
+
����
��������
���������������������������������������������������������������� ������ ���� ���� �������������� �������������� ������������ ������������������������ ���� �������������� ������������ ������ �� ���� ����
���������� �� ���� ������ ���������� ���� �������������� �� ������
���������������� ��
+ ��������
��������������
������ ���� ���� ���������������� ������
+ �������� ������ ��������
������ ������
+ �� �� �� �� ���������� ������������ '
+ ������������ �� ��������
+ ������������
+
����������
���� ���������������������� ���� ������������������ ��
������������������ �������� ���� �� ��
+ ����
+
������ ���� ������ ����������������������������������
+ ����
��������
�������������������������������� ������������������ ����
+ ������
��������
�������������� ���������� ������������������������ ����������������
+ ����������
+
+
����
+ �������� �� ������������������������������ ������ �������������� �� ������
������������������ ���� �������� ����������������
������ ���� �� ������ ��������
������
���������� ������������������ ������ ������
+ �� ���� ���������� ������������
) ������������ ��������
+ ������������ ����������������
+ ���� �������������������� ���� �������� ������
������������������������������
+ ������������
��
+ �������� ����������������������������������������������������
��
+
+
��������
����������������������������������������������������
������
��
����
+ ����������
�������������� ���������� �������������������������� �� ������������ ������������ �� �� �� �� ����
���������� �� ������������������������������ ���� �������������������� ������
+ ������������������ ���� �������� ����������������
+ �� ������ ���� ��������������������
��������
���������� ������������������ ������������ �������� �� �� ���� ���������� ������������
'
�������������� �� ���������� ������������ ������������ ��
������ ������������������������
������������������������ ����
+ ������������������������������
������������
����
+
���������� ����������������������������������������������������
+ ����
+
+
����������
+ �� ���������������������������������������������������� ���� ������ �� ���� ���� ������������������ ���������������� ������������ ������������������������������������������
����������
����
������ ����
+ ���������� �� ������������������������������ ���� ���������������� ������������ ������������������ ���� �������� ��������������
+ ���������� ���������� ���������������������� �������� �������������������������������� ���������������������� �� ���������������� ����������������������������
+ #
+ �������������� ���� ���������� ���������������������������������� ������ ������������������������
���� ������������������ ���� ������������������������������������������������ ����
+ ����������
�������������������������������������������������������� �������� ��
�� ���� ���������������������������������� ������������������ ��
������ ���� ������ ������������������ ��������������
���� ���� �������������� �������� �� ����
+ ���� ������
���� ��������
���������� ������
���������������� ��
�������� ������������ ������
+ ����
+ �� ��������
+ ������
���������� ������ �� ������ ��������
+ �� ������
���������� ������������
& �������������� ���� ����������
+ �������������� ����������������
+ ������ ������������������ ���� ����������������
��
������������������������������������������������ ���� ����������
�������������������������������������������������������� �� ������������ �� �� ���� �������� ���������� ���������� ����������������
+ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ��
�������� ������ �� ������
������������������������ �� ��������
+ ��
��
������ ���� �� ��������
+ ��������
����
����������������
+
��������
+ ������������
+
�� ��������
������
+ ���������� ������
+ ������ ����
����
���������� ������������
+ ) " �������������� ����������
������������ ���������������� �� ������������ ����
���������� ��
������������������������������������������������
+ ��
+ ���������� �������������������������������������������������������� �������� ��
�� �������� ���������� ���������� ������������������ ��
+
+ ��������
+
+ ���� ��
������������ �������� ����
���� ������������ �� ������
& ��
����
+ ���� ��������
+
+
+
+ ����
+ ����
# # ������ ����
+
��
������������ ������
+
����
�������� ���� ������ ������
+
������ ������
��
(
+
7 2 "
����
�� ������������ ������������
+
������
+ �������� ������
�������������������������������� ������������ ��
+ "
+ �������������� ���������������� ������������������������������������
+ �� ������ �� �� ��
�� �� ��
����������
����������
����������
���������� ������ ������ �� ������������ �� ���������������� ���������������������������������������������������������� ������������
+ �� ��
��������������
���������������������������������������������������� ������ �������������� ������
+
������������������ ���� �������� ������������������
�� ������ ���� ����������������������
+ ��������
+ ������������ ������������������
���������� �������� �� ���������������� ������������������������������ $ �������������� ������������������ �������������� ������������������ �������� ������������������������
���� ������������������ ���� ������������������������������������������������
����
���������������� ���������������������������������������������������������������������������������� ������
+
�� ����������
���������������������������������������������������������������� ��������
+ ��
������ ������ �� ���� ������������ ��������
+ ��
+
+
+
+
������
����
+ ����
������
���� �������� ��
+ ������
�� ��
����
+
����
��������
+
����
+
����
��������
+
+ ����������
) # ������������
+ ���������� ������������
���������� ��
����������
+ �� ���� �������������������������������� ��������������
+
+
���������� ���������������� ������ ���������������������������� ������������
+ ��
+ ������ ������ �������������� ��
+
������ �� ��
+
+
���� ��
���������� ������������������������������������������
��������
+
+ ����
������������������ �������������������������������� ��
�� ��������
���� �������� ��
�������� ��������������
+
+
+
�� ������
����
��������
������ ��
+
+ ����
+
+ ���������� ������������
+ # ������������ �� ���������� ������������ ����������������
+ ������ ������������ ��
��
���������������������������� ����������
+
+ �������� �������������� ������ ����������������������������
+ ������ ��
��
+ �� �� �������� ���������������������� ������������������ ������
+
+ �������� ��
����
+ ������ ��
����������
������ ���������������� ��������������
��������
+
+ ����
������������ �� ���� �� ������ ���������� ������
+ ���� �������� ����
�������� ������������
��
������
����
��������
������
+ ��
+ ����
+
+ ����
+
+ ���������� ����������
( # ������������ �� ���������� ������������
����������������
�� �� ������������ ��
�� ������ ����
�������������������������������� ��������������
+
+
��
+ ���������� ���������������� ������ ���������������������������� ������������������ ����
���� �������� �������� ����������
+ �������������������������� ������ �� ��
����
+ ���� �� ������������ ���������������������������������������������� ������������
��
+ ������ ����
���������������������������������������������������� ��
+ ������������
+
����
���������� ����
�������� ����������������
����
��
���� ������
����
+
������
������ ��
+ ����
+
���������� ��������
+ + # ������������ �� �������� ������������ ����������������
������ ������������ �� ��
�������������������������� ��������
��
��������
������ ������ ������ ����������������������������
������ �� ��
+ �������� �������� ���������� ���������� �������������������������� �������� ��
����
����
+ ���������� ����������������������������������������
+ ������������
+ ����
+ �� �������� ���� ������������������ ���������� �� ������������
+ ����
�������� ��
+
�������� ��������������
+
����
+
��������
����
������ ������ ��
������ ��
+
+
+ �� ���������� ����������
# �������������� �� �������� ������������ ���������������� ������ ���������� ���� �� ���� �� �������������������������������� ������������
��
�������� ���������������� ���� ���������������������������� �� �������������� ������
���� �� �������� ���������� ���������� �������������������������� ������ ��
+
����
��
���� �� ������������ ��������
+ ��
+
��
������
+
+
���� ����
+ ������
+ ��
������ ���� ������ ��
+
������
����
������
��
+
+ ����
+
����
+
+
+
+
��������
��������
* $ ������������
������ ������������ ���������� ��
�������� �� �� ��
���������������������������� ����������
��
���������� ��������������
+ �� ���������������������������� ������������ ����
�� ���� ������
������ ���������������� ���� ����������
��
��
��������
������������������������ ��������������
���������� �� �� ������ ����
���������������� ������������������ ���������� �� �� ��������
+
����
�������� ��
+
�������� ��������������
������
+
+
������
��
������ ����
+ ��
+
+
+ ��
+
+
+
+
+
��������
������
, " ������������
+ �� ������
+
������������
������������ ��
�� ���������� ��
+ ��
������������������������
+ �� ��
��
+
�������� �������������� �� ����������������������������
+ ������������ ���� ���������� �������� �������� ����������
�������������������������� �������� ��
+ ����
+
����
�������� �� ���������������� ��������������
+
����������
�� ���� ����
+ �������� �� �������� ������ ���������� ��
+ �� ������
�� ��������
�������� ��������������
+
+
����
+ ��
�� ������
����
������
��
+
����
+ ��������
+ ��������
+ & ������������
������
+ ������������
+ ������������ ��
���������� �� �� ��
��������������������������
��������
��
�������� �������������� �� ���������������������������� �������������� �� ������
�� ������ �������� ������ ������
�������������������������� �������� �� ����
+
+ ����
+ ��������
���� ������������������ ��������������
+ ���������� ������ �� ����
�������������� ������������ �� ������������������ ���������� �� �� �������� ����
�������� ����
�������� ��������������
������ ���� �� ������
+ ����
������ ������ ��
����
+
+ ��
+
+
+ �������� ��������
+ % ������������ �� ������
������������
+
������������ ��
�� �� ������������ ��
�� �� ��
������������������������
+ �� ����
�� �������� �������������� ���� ���������������������������� �������������������� ������
�� ����������
������������������ ����������
������������������������������ ��������
+
+ ��
+
����
�������������� ��������
������
+ �� ���� ���� ������ ��
+ ���� �� ��
������
������
������
������������
����
+
���� �� ������
������
������
��
��
��
��
��������
+ ����
* ( ������������
������
+ ������������ ���� ����
����������
�� ��
�������������� ������
������
+ �� ����������
������������
+ ������������ �� ������ ���������������� ���� ���� �� �� �������� ��������
������ ���������������������������� ����������������������������������������������������
��������������
������������ ���� ������������������ �� �������������� ������������ �������������������� ������������������
���������������� �������� ������ ������������ �� ����������������������������������������������������������������� [...]
+ ���������������� ���������� ���������������������� ���������������������������������������������������������� ����������������
+ �������������� �� ������������ �������������������������� �������������������������������� ���������������������� ��������
����������������
+
+ ����������
+ ������������ ������ ����������������
+ ������������ �� ���������� �������������������� ������
���������������������������� ����������������������
+ ��������������������������������"
��������������������������������
������������ ������������
������ ���������������������� ��������������������������
������������������������������
����������
������������
�������������� ���������������� ��������������������������������������
������������ �������� ���� ������������ ������������ ���������� ����������
���������������������������� ��������
+ ��
+
+
������������
��������
���� ������
����
������ ���� ���� ��
+
���� ���� �� ���� ������
������
�������� �� ��������
+ ��������
������ ��
�������� ������ ��
������ ����������
+ ��������
�������� ������ ���� ���������������� ���� ����
+
���������� ������
�������������� �������������������������������� ���� �������������� ���������� ���� ���������������� ���������� �� ������ ������ ���������������� ���� ������ ���� ������������ ���������� ����
�������� ��
���������� ���������� �������� ��������������
�������� ������
+ ����������������
+
�� �������������� �� ����
+ ������������ �� ��
������������ ����
+ ���� ���������������� ������ �� ����������
���� ���������������� ������������������ �������������������������������� ������������������ ������������������������������������������������������ ������ ���������������� �� �������� ������������������ �� �������� ����������������
�� �������� ����������
��������������������
+ ������
���������� ������������������ ���� ���������� �������� �� ����������������
���������� ������������ " �������������� ���������������� ������������ ���������������� ������ ������������������������
���� ������������������ �������������������������� ����������
������ �� �������������� ���������������� ������ ����������������������������
������������������ ������
������ ����������
+ ������������������������ ����������
�������������������������������������������� ���� ��������������
���� �������� ���� ��������������
�� �������� ��
���������� ������������������
�������������� �� ������������ �������� �� �� ���� �� ��
+ ��������������
������
���������� ����
��������
��������������
������ �������� �� ����
+ ������ ������ ������ ������
+ ������
����
�� ������
���������� �������������� $ ! �������������������� ��������
������������ ������������ ������ ���������������� �� ���������� ������
������������������ ������
������������
�������� ������������ ����������������
�� ���������������������������� ���������������� ������
���������� ���������������������� ��������
�������������������������� �������������������� ���� ���������������� ���������������� ������������ ���������������������������������������������� ������������ ������������������ ������������������ ������������������������������������������������������ ���� ���������������� ������������ ������������������ ���� ���������������������������� ������������ ��������
+ ��������������������
������
+
��������
������ ���� �� ���� ���������� ������
+ ��������
���������� ������������ #
�������������� ���� ��������
������������ ���������������� ������ ������������������������
���� ������������������
+ ��������������������������
+ ����������
����������
���������������� ������������������ ������������������������������������ ������������������ ������
������ ����������
������������������������������������ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ [...]
+ �� ����������
������ ���� ������������ �������������������������������������������� ������������ ����������������
+
����������������
���������������������������������������������������� ���� �������������� �� ������
+ ������������������ ��
+ �������� ������������������
���������� �� ����
�� ������ ������
+
+ ������
������ ������ ����
������ ��
���������� ��������
+
( ������������ �� �������� ������������ ����������������
+ ������ ��������������������
+ ���� ������������
+ ������������������������
��������
����
+ ������������ ������������������ ������ ���������������������������� �������������������� ������
�� ����������
+ �������������������� ����������
���������������������������� ���������������� ��
+ ���� ��������������
+ ������������ ������������
������������������������ ������������������ ������������ ������������������ ������������������ ������������������������������ �������������������� ���� ���������������� ���������� ������������������ ����
+ �������� ��������������
+ ������������ ����������
+ ���������� ��������
+
������
������ ������ ������ ��
�������� ����
�� ��������
���������� ��������
+
&
������������ ���� ������
+ ������������
+ ������������ ��
������ ��������������������
+ ���� ������������������
������������������ ������
+ ����������
��������
���������������� ���������������� ������ ��������������������������
+ ����������������������������
���������������� ������������������������ ����������
���������������������������������������������������� ��
+ �� ���������������� �������������� ������������
+ ������������������������������������������ ������������ ������������������
+ ������������������
+ ���������������������������������������������������� ���� �������������� �� ������
������������������ ��
����������������������������
+ ������������ ��������
+ ������������������
������
+
������ ������ ����
������ ������
�� �� ��
���������� ����������
+
( ������������ �� ������ ������������ ����������������
+ ������ ��������������������
+ ���� ���������������� �������������������������� ���������� ���� �� �������������� ������������������ ������������������������������������ ����������������������������
���� ���������� ������������������������ ���������� ���������������������������������������������������������� ������ ���������������� �� �������������������������������� ���������������������������������������������� ���������������������������������� ���������������������� ������������������������������������������������������ �������������������������������������� ���������������������������� ���������������������������������������������������������������� [...]
+ ������ ������������ ������ �������������������������� �������������������������� ���������� ������������ �������������� ���������������� �������������� ���������������� ����������������������������������
������������������������ ��
�������������������������������� ������������ ���� ���������������� ������������������ �������������������������������������������������������� �������������������������������� �������������������� � [...]
+ ��
��
������������
�� ������������������ ��������
+
���������� �� �� �� ����
+ �������� ����
+ ������ �� ������ �������� ������ �� �� �������� ����
�������� ������ ������������
+ �� ������ ����
�� ���� ������
������
�� ����
��
+
+
+ ��������
+ �� �� ) % ����������
����
������������
����������
�� �������� ��
+ �� ������
�������������� ������
��
���� ������ �������������� ���� ������������ ����������
�������������������� ������
���� ���������� �� �������� ��������
�� ������ �������������������������� ���� ��������
��
+
+ ��!
�������� �� & % ����
+
��
��
��
�� ��
+
+ ������ ��
+
��
+
" ��
����
+ ������
+ ' &
+ ����
#
�� ( ��
��
�� ��
" / �� ����
+
+ ����������
����
+ ��������
&
+ �� ��
+ ������ �� �� ��
����
+
+
+
�� $ ������ �� ��
��������
��������
+ ��
�� �� $ �� ��
���� �� ������ �� �� ������ " %
+
��
������
+
+ �� ����
+
+
��
��
+ !
+
��
+
+
+ ����
#
���� ����
+ ��
+
+ ��
����
����
+
��
+ ��
��
, % ��������
����������
+ ��
+ ����
���������� �� ��
+
����
+
+ ��
�� ����
������ ��
+ ������ ������ ��
����
+ ��
+
+ ���� ���� ���� ������ �������������� ������ )
+
����
��
���� ������
��
+ ������
�� �� ��
+
�� ����
+
+ �� ��
+ ����������
����
&
���� �� �� ��
����������
����������
+ ����
���� ���� ��
������
��
�� ��
������
���������� �� (
������
+ ���� �� ������ ���� ������ ���� ����
�� ������������ "
���������� �� �� ������ ������
+ ���� ������
+ �������� ��
+
�������� ��������
������ ���������� ������
����
+ ���� ������������
�� ��������
���� ���������� �������� ��
+
+
���� ��
+
+ ��������
+ ��
������
����
+
+
������ ����
+ ���� �� �� ��
������
+ ����
�� ����������
������
+
������
�� ��
������
��������
+
+ ������
+
�������� ����������
����������
������ ������������
�� ��
+ �������� �� �� ���� �� ������������ ����
�� ������ ����
+ ���������� �������� ����
������
�� ����
�������� ���������� ������
�� ������ ��������
���� �������� �� ������ ���������������� ���������������������������������� ���������������� �������������� ����������������������������������������������������������������������������������������������������������
+ ������������������ �� �������� �������� ���������� ���� ������������������������������ ���������������������������� ���������� ����������������
+ ������������������������������������������������������������������������������ ��������������������������������������������������������������������������������������������������������������������������������������������
�������������������������������������� �������������� �������������������������������������������������������������������������������������������������������������������������� ������������������ ������������������������������������
����������������������� [...]
+ �� ������ �������� ���������� �� ����������
+ ���������������� �� ������������ ���������� ������������������ �� ��������������
+
���� ��������
�������� ���� ������������ ����
������ ��������
+ ������
���� ��
������������������
������ ���������� ������
+ ���� ���������������� �� �� �������������� ������
������������ ����������������
+ ������������ �������������������� ������������
���������������� ���������������� ���������� ������������������������������
������������������������������ �������������� ����������������������������������
������������������������������������������������������ ���������������������� ������
������������������ ������������ ������������������������������������������ ����
+ ����
��
���� �� ���� ������ ������
����
������
+ �� ����
������
�� ���� ���� ����
���� �������� ������ ���� ����������
+
����
������ ����
��
���� �������� ������������ ���� ����
+ ������ ������
+ �� ������
+ ���� ���� �������� ����������
�� �� ������ ����
+ �� ���������� ��
��������
���������� ������ ����������
+ �� ������������������������ ���������������� ���� ����������
������ �������� �������� ���� ���������� ��������������
���������� ���� ������ ���� ������������ ������
������ �� �������������������� �������� ���������������� ���� �������������� �������� ��������
+ ������
+ ������ ������
+ ����
+ ��
+
+
+
+
+
+
+
+
+
# ������
+
+
"
��
"
����
�� ��
+ ����
������ ����
����
+ ��������
������
+
+
���������������� ���������� ������������ ������
+ ��������
���� ���� �� ���� ����������
+ ������
+ ��������
+ ���� ��
��������
+ ����
������
+ �� ���������� �� ��������
��������
+
����
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ���������������������������� ���������������������������������������������������������������������������������������������������� ���������������������������������� [...]
+
$
+
* ! # !
��
"
( ��
!
��
+
��
����
# (
"
��
����
��
������ ����
��������
��
�� ����
+ ����
+ ����
+
+
+ ��
% ��������
+ ��
+
+
��������
+
�� ���� ������
����
�� ��
����
����
��
+
��
����
����
+
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
+ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
+
+
+
+
+
+
+
+
+
+
+
����
+
+
+
+
����
��
��
+
+
����
+
# ��������
+ ������
+
+
+
+
+
+
��
+
+
+
+
����
+
+
+ % ��
��
�� ����
������ �� ����������
�������� �� ������ �������������������� ����
+ �������� �������������� ���������������� �� ������ �������� �� ������������������ ���������������������������������������������� ���������� ������������������ ��
+ ������ �������������������� �� ������ ���������������� ������ ���� ����������
������ ���� �� �������� �������� ���� ������ ������ ������������ ���� ��������������
+
�������������� ���������� �� �� ������ ���� ������������������ ������
������������������������ �� �������� �������� ���������������� ������ ���������� ��������
������������������ ���� �� ������ ���������� ���������������� ���� ���������������������������� ������������������ ������������ �� ���������� ���������������������������������� ����������������������������������������
��
+ #
" & �� % (
'
+
# #
$ &
/ + !
+
+ ��
+ + , ����
+
+ ! ������
+
����
����
������ ���� ����
�� ����
����
��������
+ ��������
$
������
+
+ ������ ����
����
�� # ��
������
��������������
(
���� ������
����
�� ����
��������
���� ����
������ ������ ��������
. ��������
+ �������� "
�� ' + '
+ * ��
������
��
���� ���� $
$
+ ������ ���� %
+
���� ��
&
�� ����
#
+ ������
) (
����
+
+
+
+ ����
,
+ ����
+ ���� ! ) ��
+
����
����* ,
+
+
+ �������� ��������
�� " !
+ ��
���� ! �������� %
������
��������
���� ! % + 2 ����
��
+ ����
$
+ ���� ����
��
+
����
����
+ ����
��
+
��
��
��
����
+
��
��
������
+
������
��
+
����
����
��������
��
������
+ ����������
�������� ��
����
�� ������
+ ������ ����
�� ����������
+ ���������� �������� #
+ ������������ �� �� ��
���������� ������ �� ��
+ ������ ��
+ ������
+
+ ����������
����
��������������
��
���������������� �������� �� �� ������������ �� �������������� �� ������
+
+ �������� ��������������������
���������� �� ��
��
$ % #
+ #
��
��
+ ��
+ "
+ ! "
!
���� ����
!
* , $
��
" )
+ ��
+
" ��
��
���� �� !
+ ����
+ ������
��
+ ���� ����%
" ��
+ ������
���� ���� %
��
��
+
+
���� ��
����
����
+ �������� ������������ ����
����
+ �� �� ����
+ ������
������ ��
+
���� ��
+ ��
+
�� ��
+
+
��
+
+ ����
+
��
��
+
+
+
������
+
+
����
+
��
+
������ ������
+
����
����
+ ��
��
�������� ��������
+
- # ����
+ ��������
+ ��
+ ��
+
+
����
�� ��
��
������������ �������� ����
��������
+ ��
������ �� ������
+ �� �������� ����
��
��
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������� ���������������� ������������������������������������������������������ �������������������������� ���������������������������������������������������������������������������������������������������������������������������������� [...]
+ �� ������������
����������
����
��������
+ ������������������������������
+ ������������������ ��
+ �������� ��������
+ ������������ �������������������������������������� ����������������
+ ��������
������ �������������������������������������������������������������������������������� ���������� ���������� &
������������ ���� ��������
������������
+ ���� ���� ��
�� ���������������������������������������������������� ���� �������������������������������� ���������������� ������������������������������������ �������������������������������������������������������� �������������������������������������������������������������������������������������������� ���������������������������������������������� �� ������ ���� ������������������ ����������������
��������
����������
��������
�� �� ����
+
������ �� ������ ����
��
+
��
�������� ��
���������� ���� ��������
�� ��������
������
+ �������� ���� ���������������� ������������
+ ���� ������ �� �� �� �������������� �������� �������� �� ��
+ ��������
���� ���� *
������������ ����������
������������ ��
���������� ������ ������ ������ ������ ����
+
������������������������������ ���������� �� ���������������� ������������������
+ ������������������������������������������ ������������ �������������� ������������ ������������������
������������������������ �� ������
+ ���������������������������������������������� ����" �� A �� ��; 5
������U [ ������X ��
+ e ��r�����@ . ����N V
��>�w��������� � ; , ! ����E C 6 ��������z�v���O ����������� u ��k�v�@ � e " \ � d _ ����������� � t ���� ' . j 9 ������ 6 ��������. C " �� !
��������% ����W � r W ��������z�����A �� = 9 * ���� - ( ��d��� J�z�] [ ��������p�n�������5 ��K ������x���\ ����|�������~�c�Q�o�r���Q . ������l o ����2 y * 1 ? - ������/ p ` # ����r ����������K b i f ` Y a ^ m H
������
+ ( 1 C G ; 3 k m " $ ����( G Z , )
Z U = ' ! N W $ . p T # n U ����2 U 7 , > = + ��^ O T 9 ? L ���� 3 T J \ ^ 3 E ������8 x 6 m ^ 5 ����������0 j 1 < ��1 ������, � � ; ������ S ����$ ������A � = ����& ��
& f M ����& #
$ �� = @ O D ��g���P � � v C 0
+ ����z { ������� 2 3 : ����> Q " X f 7 Y , ��������9 � � F ����p Y I M > �� 4
1 5 5 ��+ �� � � / " ��� C M O 3 f � � R ����������= @ �� �
f a P C H ����������& ' N � � v t N ������
( ; 1 ' ������������������ K U ) �� & U e ��������2 ��B _ � ' �� ����- ��H U ) �� 5 ����H , ' T � � %S ����o L w�N� ��X � � c ����f A ) c 9 ����Y � � � � d ��( � �
� K 8 � � � � � z m i � � � � � ~ s d c � � � � k < ( n { l ` @ N � � S 6 n � � � U _ k � ^ 1 ( M � � � � � ��< e V A 7 ] k = M _ ^ [ u 1 2 ����9 P ����- E C �� ��������
m n v l �� (
����������������w�G�A�������` j T ) : G : 5 . ? \ o 4 N 5 U 4 % ������) ^ z s G A � 9 ����# % � W [...]
����
' ��+ /
��������������
�� % 2 5 T W < % , 7 S �� ' # F D *
, ? N @ ����
+ ' �� % ��
9 O ! ����������3 B U : & �������� & ���� ���� �� �� # �������������� ����������b�q����� & + ������������������f�s�w�3�Q�L�M�i�����" ! �������� ����
1 ���������� 0 > $ ! R
���� ��
! * 0 9 Q i o E ������
+ ��
% $ < G 2 B G / & ��
< : 4 8 / # L Q # # 7 ( ) N k I i T ��/ _ < 9 h s g R > H , Q D 2 " U Z 2 * Q e i ~ Y $
���� ! j � n C 2 ������ & D 9 / ' ) ) 9 V \ & ����
% ������
# 5 N Y 5
�������������� ���� ��) C
���� + ' / = U J Z ! ���������������� $
$ 7 C 9 ����������% 4 # ��
+ 1 ����
����
+
�� ����. ; ��
$ ���������� L { g ����������
+ �� 1 ����/ $ $ # 5 ���������� ��2 _ g ] F ��������
��
+ & ���������� �������� ! - , �� ��
) 0 ���� ��������
% , #
" ������
�� ��# /
4 = ������������ $ / , 5 D L c c E 8 ; L c
1 / I G 0 / = O F " ����
$ % �� &
+ ��
& @ G
+ ����������7 @ S ; $ �������� ! ���� ����
�� & ��������������
����������p�}�����! $ , 1 �������� ��������o�u�w�>�a�c�\�w�����, - $ ! �� �� 0 & & ������ ? G 3 - W ) ����(
! 3 9 @ E \ r z S # ����
" 9 = M T D $ + O X ? 3 C $ O Q T M ? 3 ` m F . C 0 $ \ Z > P q } T r ` # : j P 3 F h s j _ N J 3 S Q A 1 ` e ( D : \ v t � l : : ���� ; , s � p R ; 2 T E ? 7 8 9 $ % = Z ] 5 �� , 4 ( & ! * ' $ ����
( A Z [ 9
� [...]
+ ���� ����
! ( 1 I , S A
����
�� 0 A 1 < ���� $
+ !
! I O + % 4
��
+ 5 4 W z i ����������)
C 2 2 : 1 F ������
B l { r W ������
+ #
( 2 $ �� ���� ������
����������������������������������������������������������������������������������l� �����,���W�8�3�J�g�z�������� ���
��
�
�$�(� � ���
����
��� �������������������������_�L�B�%����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [...]
\ No newline at end of file
diff --git a/mne/fiff/edf/tests/data/test_bdf_eeglab.mat b/mne/fiff/edf/tests/data/test_bdf_eeglab.mat
new file mode 100644
index 0000000..f04bc84
Binary files /dev/null and b/mne/fiff/edf/tests/data/test_bdf_eeglab.mat differ
diff --git a/mne/fiff/edf/tests/data/test_edf_eeglab.mat b/mne/fiff/edf/tests/data/test_edf_eeglab.mat
new file mode 100644
index 0000000..6a492ce
Binary files /dev/null and b/mne/fiff/edf/tests/data/test_edf_eeglab.mat differ
diff --git a/mne/fiff/edf/tests/data/test_eeglab.mat b/mne/fiff/edf/tests/data/test_eeglab.mat
new file mode 100644
index 0000000..f04bc84
Binary files /dev/null and b/mne/fiff/edf/tests/data/test_eeglab.mat differ
diff --git a/mne/fiff/edf/tests/test_edf.py b/mne/fiff/edf/tests/test_edf.py
new file mode 100644
index 0000000..1d7216b
--- /dev/null
+++ b/mne/fiff/edf/tests/test_edf.py
@@ -0,0 +1,87 @@
+"""Data Equivalence Tests"""
+
+# Author: Teon Brooks <teon at nyu.edu>
+#
+# License: BSD (3-clause)
+
+import os.path as op
+import inspect
+
+from nose.tools import assert_equal
+from numpy.testing import assert_array_almost_equal, assert_array_equal
+from scipy import io
+
+from mne.utils import _TempDir
+from mne.fiff import Raw, pick_types
+from mne.fiff.edf import read_raw_edf
+
+FILE = inspect.getfile(inspect.currentframe())
+data_dir = op.join(op.dirname(op.abspath(FILE)), 'data')
+hpts_path = op.join(data_dir, 'biosemi.hpts')
+bdf_path = op.join(data_dir, 'test.bdf')
+edf_path = op.join(data_dir, 'test.edf')
+bdf_eeglab_path = op.join(data_dir, 'test_bdf_eeglab.mat')
+edf_eeglab_path = op.join(data_dir, 'test_edf_eeglab.mat')
+
+tempdir = _TempDir()
+
+
+def test_bdf_data():
+ """Test reading raw bdf files
+ """
+ raw_py = read_raw_edf(bdf_path, hpts=hpts_path, preload=True)
+ picks = pick_types(raw_py.info, meg=False, eeg=True, exclude='bads')
+ data_py, _ = raw_py[picks]
+
+ print raw_py # to test repr
+ print raw_py.info # to test Info repr
+
+ # this .mat was generated using the EEG Lab Biosemi Reader
+ raw_eeglab = io.loadmat(bdf_eeglab_path)
+ raw_eeglab = raw_eeglab['data'] * 1e-6 # data are stored in microvolts
+ data_eeglab = raw_eeglab[picks]
+
+ assert_array_almost_equal(data_py, data_eeglab)
+
+
+def test_edf_data():
+ """Test reading raw edf files
+ """
+ raw_py = read_raw_edf(edf_path, preload=True)
+ picks = pick_types(raw_py.info, meg=False, eeg=True, exclude='bads')
+ data_py, _ = raw_py[picks]
+
+ print raw_py # to test repr
+ print raw_py.info # to test Info repr
+
+ # this .mat was generated using the EEG Lab Biosemi Reader
+ raw_eeglab = io.loadmat(edf_eeglab_path)
+ raw_eeglab = raw_eeglab['data'] * 1e-6 # data are stored in microvolts
+ data_eeglab = raw_eeglab[picks]
+
+ assert_array_almost_equal(data_py, data_eeglab)
+
+
+def test_read_segment():
+ """Test writing raw edf files when preload is False
+ """
+ raw1 = read_raw_edf(bdf_path, hpts=hpts_path, preload=False)
+ raw1_file = op.join(tempdir, 'raw1.fif')
+ raw1.save(raw1_file, overwrite=True)
+ raw11 = Raw(raw1_file, preload=True)
+ data1, times1 = raw1[:, :]
+ data11, times11 = raw11[:, :]
+ assert_array_almost_equal(data1, data11, 8)
+ assert_array_almost_equal(times1, times11)
+ assert_equal(sorted(raw1.info.keys()), sorted(raw11.info.keys()))
+
+ raw2 = read_raw_edf(bdf_path, hpts=hpts_path, preload=True)
+ raw2_file = op.join(tempdir, 'raw2.fif')
+ raw2.save(raw2_file, overwrite=True)
+ data2, times2 = raw2[:, :]
+ assert_array_equal(data1, data2)
+ assert_array_equal(times1, times2)
+
+ raw1 = Raw(raw1_file, preload=True)
+ raw2 = Raw(raw2_file, preload=True)
+ assert_array_equal(raw1._data, raw2._data)
diff --git a/mne/fiff/evoked.py b/mne/fiff/evoked.py
index 35eb578..d56a394 100644
--- a/mne/fiff/evoked.py
+++ b/mne/fiff/evoked.py
@@ -8,9 +8,6 @@ from copy import deepcopy
import numpy as np
import warnings
-import logging
-logger = logging.getLogger('mne')
-
from .constants import FIFF
from .open import fiff_open
from .tag import read_tag
@@ -21,14 +18,12 @@ from .proj import ProjMixin
from ..baseline import rescale
from ..filter import resample, detrend
from ..fixes import in1d
-from ..utils import _check_pandas_installed
-
-from .write import start_file, start_block, end_file, end_block, \
- write_int, write_string, write_float_matrix, \
- write_id
+from ..utils import _check_pandas_installed, logger, verbose
+from .write import (start_file, start_block, end_file, end_block,
+ write_int, write_string, write_float_matrix,
+ write_id)
from ..viz import plot_evoked, plot_evoked_topomap, _mutable_defaults
-from .. import verbose
aspect_dict = {'average': FIFF.FIFFV_ASPECT_AVERAGE,
'standard_error': FIFF.FIFFV_ASPECT_STD_ERR}
@@ -67,7 +62,7 @@ class Evoked(ProjMixin):
----------
info : dict
Measurement info.
- `ch_names` : list of string
+ ch_names : list of string
List of channels' names.
nave : int
Number of averaged epochs.
@@ -213,7 +208,7 @@ class Evoked(ProjMixin):
1000 * last / info['sfreq'], comment))
if info['comps'] is not None:
logger.info(' %d CTF compensation matrices available'
- % len(info['comps']))
+ % len(info['comps']))
# Read the data in the aspect block
nave = 1
@@ -241,7 +236,8 @@ class Evoked(ProjMixin):
if nepoch != 1 and nepoch != info['nchan']:
fid.close()
raise ValueError('Number of epoch tags is unreasonable '
- '(nepoch = %d nchan = %d)' % (nepoch, info['nchan']))
+ '(nepoch = %d nchan = %d)'
+ % (nepoch, info['nchan']))
if nepoch == 1:
# Only one epoch
@@ -256,7 +252,7 @@ class Evoked(ProjMixin):
if all_data.shape[1] != nsamp:
fid.close()
raise ValueError('Incorrect number of samples (%d instead of %d)'
- % (all_data.shape[1], nsamp))
+ % (all_data.shape[1], nsamp))
# Calibrate
cals = np.array([info['chs'][k]['cal']
@@ -280,7 +276,7 @@ class Evoked(ProjMixin):
# bind info, proj, data to self so apply_proj can be used
self.data = all_data
self.proj = False
- if proj == True:
+ if proj:
self.apply_proj()
# Run baseline correction
self.data = rescale(self.data, times, baseline, 'mean', copy=False)
@@ -367,16 +363,16 @@ class Evoked(ProjMixin):
unit : bool
Scale plot with channel (SI) unit.
show : bool
- Call pylab.show() at the end or not.
+ Call pyplot.show() at the end or not.
ylim : dict
ylim for plots. e.g. ylim = dict(eeg=[-200e-6, 200e6])
Valid keys are eeg, mag, grad
xlim : 'tight' | tuple | None
xlim for plots.
proj : bool | 'interactive'
- If true SSP projections are applied before display. If 'interactive',
- a check box for reversible selection of SSP projection vectors will
- be shown.
+ If true SSP projections are applied before display. If
+ 'interactive', a check box for reversible selection of SSP
+ projection vectors will be shown.
hline : list of floats | None
The values at which show an horizontal line.
units : dict | None
@@ -439,11 +435,11 @@ class Evoked(ProjMixin):
format : str
String format for colorbar values.
proj : bool | 'interactive'
- If true SSP projections are applied before display. If 'interactive',
- a check box for reversible selection of SSP projection vectors will
- be shown.
+ If true SSP projections are applied before display. If
+ 'interactive', a check box for reversible selection of SSP
+ projection vectors will be shown.
show : bool
- Call pylab.show() at the end.
+ Call pyplot.show() at the end.
"""
plot_evoked_topomap(self, times=times, ch_type=ch_type, layout=layout,
vmax=vmax, cmap=cmap, sensors=sensors,
@@ -539,9 +535,10 @@ class Evoked(ProjMixin):
df.insert(0, 'time', times * scale_time)
if use_time_index is True:
+ if 'time' in df:
+ df['time'] = df['time'].astype(np.int64)
with warnings.catch_warnings(True):
df.set_index('time', inplace=True)
- df.index = df.index.astype(int)
return df
@@ -582,8 +579,9 @@ class Evoked(ProjMixin):
If None only MEG and EEG channels are detrended.
"""
if picks is None:
- picks = pick_types(self.info, meg=True, eeg=True, stim=False,
- eog=False, ecg=False, emg=False, exclude='bads')
+ picks = pick_types(self.info, meg=True, eeg=True, ref_meg=False,
+ stim=False, eog=False, ecg=False, emg=False,
+ exclude='bads')
self.data[picks] = detrend(self.data[picks], order, axis=-1)
def copy(self):
@@ -636,7 +634,7 @@ def _get_entries(fid, evoked_node):
raise ValueError('Dataset names in FIF file '
'could not be found.')
t = [aspect_rev.get(str(a), 'Unknown') for a in aspect_kinds]
- t = ['"' + c + '" (' + t + ')' for t, c in zip(t, comments)]
+ t = ['"' + c + '" (' + tt + ')' for tt, c in zip(t, comments)]
t = ' ' + '\n '.join(t)
return comments, aspect_kinds, t
@@ -661,10 +659,11 @@ def merge_evoked(all_evoked):
ch_names = evoked.ch_names
for e in all_evoked[1:]:
assert e.ch_names == ch_names, ValueError("%s and %s do not contain "
- "the same channels" % (evoked, e))
+ "the same channels"
+ % (evoked, e))
assert np.max(np.abs(e.times - evoked.times)) < 1e-7, \
- ValueError("%s and %s do not "
- "contain the same time instants" % (evoked, e))
+ ValueError("%s and %s do not contain the same time "
+ "instants" % (evoked, e))
# use union of bad channels
bads = list(set(evoked.info['bads']).union(*(ev.info['bads']
diff --git a/mne/fiff/kit/__init__.py b/mne/fiff/kit/__init__.py
index b17c036..32c546b 100644
--- a/mne/fiff/kit/__init__.py
+++ b/mne/fiff/kit/__init__.py
@@ -5,6 +5,7 @@
# License: BSD (3-clause)
from .kit import read_raw_kit
+from .coreg import read_elp, read_hsp, read_mrk, write_hsp, write_mrk
from . import kit
from . import coreg
from . import constants
diff --git a/mne/fiff/kit/constants.py b/mne/fiff/kit/constants.py
index d7c287d..b4d3eae 100644
--- a/mne/fiff/kit/constants.py
+++ b/mne/fiff/kit/constants.py
@@ -22,6 +22,7 @@ KIT.CHAN_SENS = 80
KIT.DATA_OFFSET = 144
KIT.SAMPLE_INFO = 128
KIT.MRK_INFO = 192
+KIT.CHAN_LOC_OFFSET = 64
# parameters
KIT.VOLTAGE_RANGE = 5.
@@ -42,11 +43,11 @@ KIT_NY = Bunch(**KIT)
KIT_AD = Bunch(**KIT)
# NYU-system channel information
-KIT_NY.nchan = 192
-KIT_NY.nmegchan = 157
-KIT_NY.nrefchan = 3
-KIT_NY.nmiscchan = 32
-KIT_NY.n_sens = KIT_NY.nmegchan + KIT_NY.nrefchan
+KIT_NY.NCHAN = 192
+KIT_NY.NMEGCHAN = 157
+KIT_NY.NREFCHAN = 3
+KIT_NY.NMISCCHAN = 32
+KIT_NY.N_SENS = KIT_NY.NMEGCHAN + KIT_NY.NREFCHAN
# 12-bit A-to-D converter, one bit for signed integer. range +/- 2048
KIT_NY.DYNAMIC_RANGE = 2 ** 12 / 2
# amplifier information
@@ -70,12 +71,11 @@ KIT_NY.LPFS = [10, 20, 50, 100, 200, 500, 1000, 2000]
# AD-system channel information
-KIT_AD.nchan = 256
-KIT_AD.nmegchan = 208
-KIT_AD.nrefchan = 16
-KIT_AD.ntrigchan = 8
-KIT_AD.nmiscchan = 24
-KIT_AD.n_sens = KIT_AD.nmegchan + KIT_AD.nrefchan
+KIT_AD.NCHAN = 256
+KIT_AD.NMEGCHAN = 208
+KIT_AD.NREFCHAN = 16
+KIT_AD.NMISCCHAN = 32
+KIT_AD.N_SENS = KIT_AD.NMEGCHAN + KIT_AD.NREFCHAN
# 16-bit A-to-D converter, one bit for signed integer. range +/- 32768
KIT_AD.DYNAMIC_RANGE = 2 ** 16 / 2
# amplifier information
diff --git a/mne/fiff/kit/coreg.py b/mne/fiff/kit/coreg.py
index 84e7c4c..cddba6e 100644
--- a/mne/fiff/kit/coreg.py
+++ b/mne/fiff/kit/coreg.py
@@ -4,117 +4,38 @@
#
# License: BSD (3-clause)
-from struct import unpack
-from os import SEEK_CUR, path
-import re
+from datetime import datetime
import cPickle as pickle
-import numpy as np
-from scipy import linalg
-from ..constants import FIFF
-from ...transforms.transforms import apply_trans, rotation, translation
-from .constants import KIT
-
-
-def get_points(mrk_fname, elp_fname, hsp_fname):
- """Extracts dig points, elp, and mrk points from files needed for coreg
-
- Parameters
- ----------
- mrk_fname : str
- Path to marker file (saved as text from MEG160).
- elp_fname : str
- Path to elp digitizer file.
- hsp_fname : str
- Path to hsp headshape file.
-
- Returns
- -------
- mrk_points : numpy.array, shape = (n_points, 3)
- Array of 5 points by coordinate (x,y,z) from marker measurement.
- elp_points : numpy.array, shape = (n_points, 3)
- Array of 5 points by coordinate (x,y,z) from digitizer laser point.
- dig : dict
- A dictionary containing the mrk_points, elp_points, and hsp_points in
- a format used for raw.info['dig'].
- """
-
- mrk_points = read_mrk(mrk_fname=mrk_fname)
- mrk_points = transform_pts(mrk_points, unit='m')
-
- elp_points = read_elp(elp_fname=elp_fname)
- elp_points = transform_pts(elp_points)
- nasion = elp_points[0, :]
- lpa = elp_points[1, :]
- rpa = elp_points[2, :]
-
- trans = get_neuromag_transform(lpa, rpa, nasion)
- elp_points = np.dot(elp_points, trans.T)
- nasion = elp_points[0]
- lpa = elp_points[1]
- rpa = elp_points[2]
- elp_points = elp_points[3:]
-
- hsp_points = read_hsp(hsp_fname=hsp_fname)
- hsp_points = transform_pts(hsp_points)
- hsp_points = np.dot(hsp_points, trans.T)
- dig = []
-
- point_dict = {}
- point_dict['coord_frame'] = FIFF.FIFFV_COORD_HEAD
- point_dict['ident'] = FIFF.FIFFV_POINT_NASION
- point_dict['kind'] = FIFF.FIFFV_POINT_CARDINAL
- point_dict['r'] = nasion
- dig.append(point_dict)
-
- point_dict = {}
- point_dict['coord_frame'] = FIFF.FIFFV_COORD_HEAD
- point_dict['ident'] = FIFF.FIFFV_POINT_LPA
- point_dict['kind'] = FIFF.FIFFV_POINT_CARDINAL
- point_dict['r'] = lpa
- dig.append(point_dict)
-
- point_dict = {}
- point_dict['coord_frame'] = FIFF.FIFFV_COORD_HEAD
- point_dict['ident'] = FIFF.FIFFV_POINT_RPA
- point_dict['kind'] = FIFF.FIFFV_POINT_CARDINAL
- point_dict['r'] = rpa
- dig.append(point_dict)
+import os
+from os import SEEK_CUR
+import re
+from struct import unpack
- for idx, point in enumerate(elp_points):
- point_dict = {}
- point_dict['coord_frame'] = FIFF.FIFFV_COORD_HEAD
- point_dict['ident'] = idx
- point_dict['kind'] = FIFF.FIFFV_POINT_HPI
- point_dict['r'] = point
- dig.append(point_dict)
+import numpy as np
+from scipy.linalg import norm
- for idx, point in enumerate(hsp_points):
- point_dict = {}
- point_dict['coord_frame'] = FIFF.FIFFV_COORD_HEAD
- point_dict['ident'] = idx
- point_dict['kind'] = FIFF.FIFFV_POINT_EXTRA
- point_dict['r'] = point
- dig.append(point_dict)
- return mrk_points, elp_points, dig
+from ... import __version__
+from ...transforms import translation
+from .constants import KIT
-def read_mrk(mrk_fname):
+def read_mrk(fname):
"""Marker Point Extraction in MEG space directly from sqd
Parameters
----------
- mrk_fname : str
+ fname : str
Absolute path to Marker file.
- File formats allowed: *.sqd, *.txt, *.pickled
+ File formats allowed: *.sqd, *.mrk, *.txt, *.pickled
Returns
-------
mrk_points : numpy.array, shape = (n_points, 3)
Marker points in MEG space [m].
"""
- ext = path.splitext(mrk_fname)[-1]
- if ext == '.sqd':
- with open(mrk_fname, 'r') as fid:
+ ext = os.path.splitext(fname)[-1]
+ if ext in ('.sqd', '.mrk'):
+ with open(fname, 'r') as fid:
fid.seek(KIT.MRK_INFO)
mrk_offset = unpack('i', fid.read(KIT.INT))[0]
fid.seek(mrk_offset)
@@ -127,22 +48,65 @@ def read_mrk(mrk_fname):
fid.seek(KIT.INT * 4 + (KIT.DOUBLE * 3), SEEK_CUR)
pts.append(np.fromfile(fid, dtype='d', count=3))
mrk_points = np.array(pts)
- elif ext == '.hpi':
- mrk_points = np.loadtxt(mrk_fname)
+ elif ext == '.txt':
+ mrk_points = np.loadtxt(fname)
elif ext == '.pickled':
- mrk = pickle.load(open(mrk_fname))
- mrk_points = mrk['points']
+ with open(fname) as fid:
+ food = pickle.load(fid)
+ try:
+ mrk_points = food['mrk']
+ except:
+ err = ("%r does not contain marker points." % fname)
+ raise ValueError(err)
else:
- raise TypeError('File must be *.sqd, *.hpi or *.pickled.')
+ err = ('KIT marker file must be *.sqd, *.txt or *.pickled, '
+ 'not *%s.' % ext)
+ raise ValueError(err)
+
+ # check output
+ mrk_points = np.asarray(mrk_points)
+ if mrk_points.shape != (5, 3):
+ err = ("%r is no marker file, shape is "
+ "%s" % (fname, mrk_points.shape))
+ raise ValueError(err)
return mrk_points
-def read_elp(elp_fname):
+def write_mrk(fname, points):
+ """Save KIT marker coordinates
+
+ Parameters
+ ----------
+ fname : str
+ Path to the file to write. The kind of file to write is determined
+ based on the extension: '.txt' for tab separated text file, '.pickled'
+ for pickled file.
+ points : array_like, shape = (5, 3)
+ The marker point coordinates.
+ """
+ mrk = np.asarray(points)
+ _, ext = os.path.splitext(fname)
+ if mrk.shape != (5, 3):
+ err = ("KIT marker points array needs to have shape (5, 3), got "
+ "%s." % str(mrk.shape))
+ raise ValueError(err)
+
+ if ext == '.pickled':
+ with open(fname, 'w') as fid:
+ pickle.dump({'mrk': mrk}, fid, pickle.HIGHEST_PROTOCOL)
+ elif ext == '.txt':
+ np.savetxt(fname, mrk, fmt='%.18e', delimiter='\t', newline='\n')
+ else:
+ err = "Unrecognized extension: %r. Need '.txt' or '.pickled'." % ext
+ raise ValueError(err)
+
+
+def read_elp(fname):
"""ELP point extraction in Polhemus head space
Parameters
----------
- elp_fname : str
+ fname : str
Absolute path to laser point file acquired from Polhemus system.
File formats allowed: *.txt
@@ -151,19 +115,28 @@ def read_elp(elp_fname):
elp_points : numpy.array, shape = (n_points, 3)
Fiducial and marker points in Polhemus head space.
"""
- p = re.compile(r'(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)')
- elp_points = p.findall(open(elp_fname).read())
+ pattern = re.compile(r'(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)')
+ elp_points = pattern.findall(open(fname).read())
elp_points = np.array(elp_points, dtype=float)
+ if elp_points.shape[1] != 3:
+ err = ("File %r does not contain 3 columns as required; got shape "
+ "%s." % (fname, elp_points.shape))
+ raise ValueError(err)
+ elif len(elp_points) < 8:
+ err = ("File %r contains fewer than 8 points; got shape "
+ "%s." % (fname, elp_points.shape))
+ raise ValueError(err)
return elp_points
-def read_hsp(hsp_fname):
- """HSP point extraction in Polhemus head space
+def read_hsp(fname):
+ """Read a Polhemus ascii head shape file
Parameters
----------
- hsp_fname : str
- Absolute path to headshape file acquired from Polhemus system.
+ fname : str
+ Path to head shape file acquired from Polhemus system and saved in
+ ascii format.
Returns
-------
@@ -171,30 +144,43 @@ def read_hsp(hsp_fname):
Headshape points in Polhemus head space.
File formats allowed: *.txt, *.pickled
"""
- ext = path.splitext(hsp_fname)[-1]
- if ext == '.txt':
- p = re.compile(r'(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)')
- hsp_points = p.findall(open(hsp_fname).read())
- hsp_points = np.array(hsp_points, dtype=float)
- # downsample the digitizer points
- n_pts = len(hsp_points)
- if n_pts > KIT.DIG_POINTS:
- space = int(n_pts / KIT.DIG_POINTS)
- hsp_points = np.copy(hsp_points[::space])
- elif ext == '.pickled':
- hsp = pickle.load(open(hsp_fname))
- hsp_points = hsp['points']
- else:
- raise TypeError('File must be either *.txt or *.pickled.')
+ pattern = re.compile(r'(\-?\d+\.\d+)\s+(\-?\d+\.\d+)\s+(\-?\d+\.\d+)')
+ with open(fname) as fid:
+ hsp_points = pattern.findall(fid.read())
+ hsp_points = np.array(hsp_points, dtype=float)
return hsp_points
-def read_sns(sns_fname):
+def write_hsp(fname, pts):
+ """Write a headshape hsp file
+
+ Parameters
+ ----------
+ fname : str
+ Target file.
+ pts : array, shape = (n_pts, 3)
+ Points comprising the headshape.
+ """
+ pts = np.asarray(pts)
+ if (pts.ndim != 2) or (pts.shape[1] != 3):
+ err = "pts must be of shape (n_pts, 3), not %r" % str(pts.shape)
+ raise ValueError(err)
+
+ with open(fname, 'w') as fid:
+ version = __version__
+ now = datetime.now().strftime("%I:%M%p on %B %d, %Y")
+ fid.write("% Ascii 3D points file created by mne-python version "
+ "{version} at {now}\n".format(version=version, now=now))
+ fid.write("% {N} 3D points, x y z per line\n".format(N=len(pts)))
+ np.savetxt(fid, pts, '%8.2f', ' ')
+
+
+def read_sns(fname):
"""Sensor coordinate extraction in MEG space
Parameters
----------
- sns_fname : str
+ fname : str
Absolute path to sensor definition file.
Returns
@@ -202,75 +188,9 @@ def read_sns(sns_fname):
locs : numpy.array, shape = (n_points, 3)
Sensor coil location.
"""
-
p = re.compile(r'\d,[A-Za-z]*,([\.\-0-9]+),' +
r'([\.\-0-9]+),([\.\-0-9]+),' +
r'([\.\-0-9]+),([\.\-0-9]+)')
- locs = np.array(p.findall(open(sns_fname).read()), dtype=float)
+ with open(fname) as fid:
+ locs = np.array(p.findall(fid.read()), dtype=float)
return locs
-
-
-def get_neuromag_transform(lpa, rpa, nasion):
- """Creates a transformation matrix from RAS to Neuromag-like space
-
- Resets the origin to mid-distance of peri-auricular points with nasion
- passing through y-axis.
- (mne manual, pg. 97)
-
- Parameters
- ----------
- lpa : numpy.array, shape = (1, 3)
- Left peri-auricular point coordinate.
- rpa : numpy.array, shape = (1, 3)
- Right peri-auricular point coordinate.
- nasion : numpy.array, shape = (1, 3)
- Nasion point coordinate.
-
- Returns
- -------
- trans : numpy.array, shape = (3, 3)
- Transformation matrix to Neuromag-like space.
- """
- origin = (lpa + rpa) / 2
- nasion = nasion - origin
- lpa = lpa - origin
- rpa = rpa - origin
- axes = np.empty((3, 3))
- axes[1] = nasion / linalg.norm(nasion)
- axes[2] = np.cross(axes[1], lpa - rpa)
- axes[2] /= linalg.norm(axes[2])
- axes[0] = np.cross(axes[1], axes[2])
-
- trans = linalg.inv(axes)
- return trans
-
-
-def transform_pts(pts, unit='mm'):
- """Transform KIT and Polhemus points to RAS coordinate system
-
- This is used to orient points in Neuromag coordinates.
- KIT sensors are (x,y,z) in [mm].
- KIT markers are (x,y,z) in [m].
- Polhemus points are (x,y,z) in [mm].
- The transformation to RAS space is -y,x,z in [m].
-
- Parameters
- ----------
- pts : numpy.array, shape = (n_points, 3)
- Points to be transformed.
- unit : 'mm' | 'm'
- Unit of source points to be converted.
-
- Returns
- -------
- pts : numpy.array, shape = (n_points, 3)
- Points transformed to Neuromag-like head space (RAS).
- """
- if unit == 'mm':
- pts = pts / 1e3
- elif unit != 'm':
- raise ValueError('The unit must be either "m" or "mm".')
- pts = np.array(pts, ndmin=2)
- pts = pts[:, [1, 0, 2]]
- pts[:, 0] = pts[:, 0] * -1
- return pts
diff --git a/mne/fiff/kit/kit.py b/mne/fiff/kit/kit.py
index 447a224..b3ba1ad 100644
--- a/mne/fiff/kit/kit.py
+++ b/mne/fiff/kit/kit.py
@@ -8,21 +8,25 @@ RawKIT class is adapted from Denis Engemann et al.'s mne_bti2fiff.py
#
# License: BSD (3-clause)
-import time
-import logging
-from struct import unpack
+import os
from os import SEEK_CUR
+from struct import unpack
+import time
+
import numpy as np
-from scipy.linalg import norm
+from scipy import linalg
+
from ...fiff import pick_types
-from ...transforms.coreg import fit_matched_pts
-from ...utils import verbose
+from ...coreg import fit_matched_points, _decimate_points
+from ...coreg import get_ras_to_neuromag_trans
+from ...utils import verbose, logger
+from ...transforms import apply_trans, als_ras_trans, als_ras_trans_mm
from ..raw import Raw
from ..constants import FIFF
+from ..meas_info import Info
+from ..tag import _loc_to_trans
from .constants import KIT, KIT_NY, KIT_AD
-from . import coreg
-
-logger = logging.getLogger('mne')
+from .coreg import read_elp, read_hsp, read_mrk
class RawKIT(Raw):
@@ -31,25 +35,31 @@ class RawKIT(Raw):
Parameters
----------
input_fname : str
- Absolute path to the sqd file.
- mrk_fname : str
- Absolute path to marker coils file.
- elp_fname : str
- Absolute path to elp digitizer laser points file.
- hsp_fname : str
- Absolute path to elp digitizer head shape points file.
- sns_fname : str
- Absolute path to sensor information file.
+ Path to the sqd file.
+ mrk : None | str | array_like, shape = (5, 3)
+ Marker points representing the location of the marker coils with
+ respect to the MEG Sensors, or path to a marker file.
+ elp : None | str | array_like, shape = (8, 3)
+ Digitizer points representing the location of the fiducials and the
+ marker coils with respect to the digitized head shape, or path to a
+ file containing these points.
+ hsp : None | str | array, shape = (n_points, 3)
+ Digitizer head shape points, or path to head shape file. If more than
+ 10`000 points are in the head shape, they are automatically decimated.
stim : list of int | '<' | '>'
- Can be submitted as list of trigger channels.
- If a list is not specified, the default triggers extracted from
- misc channels will be used with specified directionality.
- '<' means that largest values assigned to the first channel
- in sequence.
- '>' means the largest trigger assigned to the last channel
- in sequence.
+ Channel-value correspondence when converting KIT trigger channels to a
+ Neuromag-style stim channel. For '<', the largest values are assigned
+ to the first channel (default). For '>', the largest values are
+ assigned to the last channel. Can also be specified as a list of
+ trigger channel indexes.
+ slope : '+' | '-'
+ How to interpret values on KIT trigger channels when synthesizing a
+ Neuromag-style stim channel. With '+', a positive slope (low-to-high)
+ is interpreted as an event. With '-', a negative slope (high-to-low)
+ is interpreted as an event.
stimthresh : float
- The threshold level for accepting voltage change as a trigger event.
+ The threshold level for accepting voltage changes in KIT trigger
+ channels as a trigger event.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
preload : bool
@@ -61,10 +71,10 @@ class RawKIT(Raw):
mne.fiff.Raw : Documentation of attribute and methods.
"""
@verbose
- def __init__(self, input_fname, mrk_fname, elp_fname, hsp_fname, sns_fname,
- stim='<', stimthresh=1, verbose=None, preload=False):
-
+ def __init__(self, input_fname, mrk=None, elp=None, hsp=None, stim='>',
+ slope='-', stimthresh=1, preload=False, verbose=None):
logger.info('Extracting SQD Parameters from %s...' % input_fname)
+ input_fname = os.path.abspath(input_fname)
self._sqd_params = get_sqd_params(input_fname)
self._sqd_params['stimthresh'] = stimthresh
self._sqd_params['fname'] = input_fname
@@ -72,15 +82,16 @@ class RawKIT(Raw):
# Raw attributes
self.verbose = verbose
- self._preloaded = preload
+ self._preloaded = False
self.fids = list()
self._projector = None
self.first_samp = 0
self.last_samp = self._sqd_params['nsamples'] - 1
self.comp = None # no compensation for KIT
+ self.proj = False
# Create raw.info dict for raw fif object with SQD data
- self.info = {}
+ self.info = Info()
self.info['meas_id'] = None
self.info['file_id'] = None
self.info['meas_date'] = int(time.time())
@@ -97,27 +108,26 @@ class RawKIT(Raw):
self.info['ctf_head_t'] = None
self.info['dev_ctf_t'] = []
self.info['filenames'] = []
- self.info['dev_head_t'] = {}
- self.info['dev_head_t']['from'] = FIFF.FIFFV_COORD_DEVICE
- self.info['dev_head_t']['to'] = FIFF.FIFFV_COORD_HEAD
+ self.info['dig'] = None
+ self.info['dev_head_t'] = None
- mrk, elp, self.info['dig'] = coreg.get_points(mrk_fname=mrk_fname,
- elp_fname=elp_fname,
- hsp_fname=hsp_fname)
- self.info['dev_head_t']['trans'] = fit_matched_pts(tgt_pts=mrk,
- src_pts=elp)
+ if (mrk and elp and hsp):
+ self._set_dig_kit(mrk, elp, hsp)
+ elif (mrk or elp or hsp):
+ err = ("mrk, elp and hsp need to be provided as a group (all or "
+ "none)")
+ raise ValueError(err)
# Creates a list of dicts of meg channels for raw.info
logger.info('Setting channel info structure...')
ch_names = {}
ch_names['MEG'] = ['MEG %03d' % ch for ch
- in range(1, self._sqd_params['n_sens'] + 1)]
+ in range(1, self._sqd_params['n_sens'] + 1)]
ch_names['MISC'] = ['MISC %03d' % ch for ch
- in range(1, self._sqd_params['nmiscchan']
- + 1)]
+ in range(1, self._sqd_params['nmiscchan'] + 1)]
ch_names['STIM'] = ['STI 014']
- locs = coreg.read_sns(sns_fname=sns_fname)
- chan_locs = coreg.transform_pts(locs[:, :3])
+ locs = self._sqd_params['sensor_locs']
+ chan_locs = apply_trans(als_ras_trans, locs[:, :3])
chan_angles = locs[:, 3:]
self.info['chs'] = []
for idx, ch_info in enumerate(zip(ch_names['MEG'], chan_locs,
@@ -136,8 +146,9 @@ class RawKIT(Raw):
chan_info['coil_type'] = FIFF.FIFFV_COIL_KIT_GRAD
chan_info['kind'] = FIFF.FIFFV_MEG_CH
else:
- chan_info['coil_type'] = FIFF.FIFFV_COIL_NONE
+ chan_info['coil_type'] = FIFF.FIFFV_COIL_KIT_REF_MAG
chan_info['kind'] = FIFF.FIFFV_REF_MEG_CH
+ chan_info['eeg_loc'] = None
# create three orthogonal vector
# ch_angles[0]: theta, ch_angles[1]: phi
@@ -146,7 +157,7 @@ class RawKIT(Raw):
y = np.sin(ch_angles[0]) * np.sin(ch_angles[1])
z = np.cos(ch_angles[0])
vec_z = np.array([x, y, z])
- length = norm(vec_z)
+ length = linalg.norm(vec_z)
vec_z /= length
vec_x = np.zeros(vec_z.size, dtype=np.float)
if vec_z[1] < vec_z[2]:
@@ -159,13 +170,14 @@ class RawKIT(Raw):
else:
vec_x[2] = 1.0
vec_x -= np.sum(vec_x * vec_z) * vec_z
- length = norm(vec_x)
+ length = linalg.norm(vec_x)
vec_x /= length
vec_y = np.cross(vec_z, vec_x)
# transform to Neuromag like coordinate space
vecs = np.vstack((vec_x, vec_y, vec_z))
- vecs = coreg.transform_pts(vecs, unit='m')
+ vecs = apply_trans(als_ras_trans, vecs)
chan_info['loc'] = np.vstack((ch_loc, vecs)).ravel()
+ chan_info['coil_trans'] = _loc_to_trans(chan_info['loc'])
self.info['chs'].append(chan_info)
# label trigger and misc channels
@@ -190,27 +202,22 @@ class RawKIT(Raw):
self.info['ch_names'] = (ch_names['MEG'] + ch_names['MISC'] +
ch_names['STIM'])
- # Acquire stim channels
- if isinstance(stim, str):
- picks = pick_types(self.info, meg=False, misc=True,
- exclude=[])[:8]
- if stim == '<':
- stim = picks[::-1]
- elif stim == '>':
- stim = picks
- else:
- raise ValueError("stim needs to be list of int, '>' or '<', "
- "not %r" % stim)
- self._sqd_params['stim'] = stim
-
- if self._preloaded:
+ self._set_stimchannels(stim, slope)
+ if preload:
+ self._preloaded = preload
logger.info('Reading raw data from %s...' % input_fname)
self._data, _ = self._read_segment()
assert len(self._data) == self.info['nchan']
# Create a synthetic channel
+ stim = self._sqd_params['stim']
trig_chs = self._data[stim, :]
- trig_chs = trig_chs > stimthresh
+ if slope == '+':
+ trig_chs = trig_chs > stimthresh
+ elif slope == '-':
+ trig_chs = trig_chs < stimthresh
+ else:
+ raise ValueError("slope needs to be '+' or '-'")
trig_vals = np.array(2 ** np.arange(len(stim)), ndmin=2).T
trig_chs = trig_chs * trig_vals
stim_ch = trig_chs.sum(axis=0)
@@ -227,6 +234,12 @@ class RawKIT(Raw):
float(self.last_samp) / self.info['sfreq']))
logger.info('Ready.')
+ def __repr__(self):
+ s = ('%r' % os.path.basename(self._sqd_params['fname']),
+ "n_channels x n_times : %s x %s" % (len(self.info['ch_names']),
+ self.last_samp - self.first_samp + 1))
+ return "<RawKIT | %s>" % ', '.join(s)
+
def read_stim_ch(self, buffer_size=1e5):
"""Read events from data
@@ -244,7 +257,8 @@ class RawKIT(Raw):
start = int(self.first_samp)
stop = int(self.last_samp + 1)
- pick = pick_types(self.info, meg=False, stim=True, exclude=[])
+ pick = pick_types(self.info, meg=False, ref_meg=False,
+ stim=True, exclude=[])
stim_ch = np.empty((1, stop), dtype=np.int)
for b_start in range(start, stop, buffer_size):
b_stop = b_start + buffer_size
@@ -301,7 +315,7 @@ class RawKIT(Raw):
(start, stop - 1, start / float(self.info['sfreq']),
(stop - 1) / float(self.info['sfreq'])))
- with open(self._sqd_params['fname'], 'r') as fid:
+ with open(self._sqd_params['fname'], 'rb') as fid:
# extract data
fid.seek(KIT.DATA_OFFSET)
# data offset info
@@ -325,7 +339,12 @@ class RawKIT(Raw):
data = data.T
# Create a synthetic channel
trig_chs = data[self._sqd_params['stim'], :]
- trig_chs = trig_chs > self._sqd_params['stimthresh']
+ if self._sqd_params['slope'] == '+':
+ trig_chs = trig_chs > self._sqd_params['stimthresh']
+ elif self._sqd_params['slope'] == '-':
+ trig_chs = trig_chs < self._sqd_params['stimthresh']
+ else:
+ raise ValueError("slope needs to be '+' or '-'")
trig_vals = np.array(2 ** np.arange(len(self._sqd_params['stim'])),
ndmin=2).T
trig_chs = trig_chs * trig_vals
@@ -338,6 +357,150 @@ class RawKIT(Raw):
return data, times
+ def _set_dig_kit(self, mrk, elp, hsp, auto_decimate=True):
+ """Add landmark points and head shape data to the RawKIT instance
+
+ Digitizer data (elp and hsp) are represented in [mm] in the Polhemus
+ ALS coordinate system.
+
+ Parameters
+ ----------
+ mrk : None | str | array_like, shape = (5, 3)
+ Marker points representing the location of the marker coils with
+ respect to the MEG Sensors, or path to a marker file.
+ elp : None | str | array_like, shape = (8, 3)
+ Digitizer points representing the location of the fiducials and the
+ marker coils with respect to the digitized head shape, or path to a
+ file containing these points.
+ hsp : None | str | array, shape = (n_points, 3)
+ Digitizer head shape points, or path to head shape file. If more
+ than 10`000 points are in the head shape, they are automatically
+ decimated.
+ auto_decimate : bool
+ Decimate hsp points for head shape files with more than 10'000
+ points.
+ """
+ if isinstance(hsp, basestring):
+ hsp = read_hsp(hsp)
+
+ n_pts = len(hsp)
+ if n_pts > KIT.DIG_POINTS:
+ hsp = _decimate_points(hsp, 5)
+ n_new = len(hsp)
+ msg = ("The selected head shape contained {n_in} points, which is "
+ "more than recommended ({n_rec}), and was automatically "
+ "downsampled to {n_new} points. The preferred way to "
+ "downsample is using FastScan.")
+ msg = msg.format(n_in=n_pts, n_rec=KIT.DIG_POINTS, n_new=n_new)
+ logger.warning(msg)
+
+ if isinstance(elp, basestring):
+ elp = read_elp(elp)[:8]
+
+ if isinstance(mrk, basestring):
+ mrk = read_mrk(mrk)
+
+ hsp = apply_trans(als_ras_trans_mm, hsp)
+ elp = apply_trans(als_ras_trans_mm, elp)
+ mrk = apply_trans(als_ras_trans, mrk)
+
+ nasion, lpa, rpa = elp[:3]
+ nmtrans = get_ras_to_neuromag_trans(nasion, lpa, rpa)
+ elp = apply_trans(nmtrans, elp)
+ hsp = apply_trans(nmtrans, hsp)
+
+ # device head transform
+ trans = fit_matched_points(tgt_pts=elp[3:], src_pts=mrk, out='trans')
+
+ self._set_dig_neuromag(elp[:3], elp[3:], hsp, trans)
+
+ def _set_dig_neuromag(self, fid, elp, hsp, trans):
+ """Fill in the digitizer data using points in neuromag space
+
+ Parameters
+ ----------
+ fid : array, shape = (3, 3)
+ Digitizer fiducials.
+ elp : array, shape = (5, 3)
+ Digitizer ELP points.
+ hsp : array, shape = (n_points, 3)
+ Head shape points.
+ trans : None | array, shape = (4, 4)
+ Device head transformation.
+ """
+ trans = np.asarray(trans)
+ if not trans.shape == (4, 4):
+ raise ValueError("trans needs to be 4 by 4 array")
+
+ nasion, lpa, rpa = fid
+ dig = [{'r': nasion, 'ident': FIFF.FIFFV_POINT_NASION,
+ 'kind': FIFF.FIFFV_POINT_CARDINAL,
+ 'coord_frame': FIFF.FIFFV_COORD_HEAD},
+ {'r': lpa, 'ident': FIFF.FIFFV_POINT_LPA,
+ 'kind': FIFF.FIFFV_POINT_CARDINAL,
+ 'coord_frame': FIFF.FIFFV_COORD_HEAD},
+ {'r': rpa, 'ident': FIFF.FIFFV_POINT_RPA,
+ 'kind': FIFF.FIFFV_POINT_CARDINAL,
+ 'coord_frame': FIFF.FIFFV_COORD_HEAD}]
+
+ for idx, point in enumerate(elp):
+ dig.append({'r': point, 'ident': idx, 'kind': FIFF.FIFFV_POINT_HPI,
+ 'coord_frame': FIFF.FIFFV_COORD_HEAD})
+
+ for idx, point in enumerate(hsp):
+ dig.append({'r': point, 'ident': idx,
+ 'kind': FIFF.FIFFV_POINT_EXTRA,
+ 'coord_frame': FIFF.FIFFV_COORD_HEAD})
+
+ dev_head_t = {'from': FIFF.FIFFV_COORD_DEVICE,
+ 'to': FIFF.FIFFV_COORD_HEAD, 'trans': trans}
+
+ self.info['dig'] = dig
+ self.info['dev_head_t'] = dev_head_t
+
+ def _set_stimchannels(self, stim='<', slope='-'):
+ """Specify how the trigger channel is synthesized form analog channels.
+
+ Has to be done before loading data. For a RawKIT instance that has been
+ created with preload=True, this method will raise a
+ NotImplementedError.
+
+ Parameters
+ ----------
+ stim : list of int | '<' | '>'
+ Can be submitted as list of trigger channels.
+ If a list is not specified, the default triggers extracted from
+ misc channels will be used with specified directionality.
+ '<' means that largest values assigned to the first channel
+ in sequence.
+ '>' means the largest trigger assigned to the last channel
+ in sequence.
+ slope : '+' | '-'
+ '+' means a positive slope (low-to-high) on the event channel(s)
+ is used to trigger an event.
+ '-' means a negative slope (high-to-low) on the event channel(s)
+ is used to trigger an event.
+ """
+ if self._preloaded:
+ err = "Can't change stim channel after preloading data"
+ raise NotImplementedError(err)
+
+ self._sqd_params['slope'] = slope
+
+ if isinstance(stim, str):
+ picks = pick_types(self.info, meg=False, ref_meg=False,
+ misc=True, exclude=[])[:8]
+ if stim == '<':
+ stim = picks[::-1]
+ elif stim == '>':
+ stim = picks
+ else:
+ raise ValueError("stim needs to be list of int, '>' or "
+ "'<', not %r" % str(stim))
+
+ self._sqd_params['stim'] = stim
+
+
def get_sqd_params(rawfile):
"""Extracts all the information from the sqd file.
@@ -354,7 +517,7 @@ def get_sqd_params(rawfile):
"""
sqd = dict()
sqd['rawfile'] = rawfile
- with open(rawfile, 'r') as fid:
+ with open(rawfile, 'rb') as fid:
fid.seek(KIT.BASIC_INFO)
basic_offset = unpack('i', fid.read(KIT.INT))[0]
fid.seek(basic_offset)
@@ -373,6 +536,34 @@ def get_sqd_params(rawfile):
else:
raise NotImplementedError
+ # channel locations
+ fid.seek(KIT_SYS.CHAN_LOC_OFFSET)
+ chan_offset = unpack('i', fid.read(KIT.INT))[0]
+ chan_size = unpack('i', fid.read(KIT.INT))[0]
+
+ fid.seek(chan_offset)
+ sensors = []
+ for i in xrange(KIT_SYS.N_SENS):
+ fid.seek(chan_offset + chan_size * i)
+ sens_type = unpack('i', fid.read(KIT.INT))[0]
+ if sens_type == 1:
+ # magnetometer
+ # x,y,z,theta,phi,coilsize
+ sensors.append(np.fromfile(fid, dtype='d', count=6))
+ elif sens_type == 2:
+ # axialgradiometer
+ # x,y,z,theta,phi,baseline,coilsize
+ sensors.append(np.fromfile(fid, dtype='d', count=7))
+ elif sens_type == 3:
+ # planargradiometer
+ # x,y,z,theta,phi,btheta,bphi,baseline,coilsize
+ sensors.append(np.fromfile(fid, dtype='d', count=9))
+ elif sens_type == 257:
+ # reference channels
+ sensors.append(np.zeros(7))
+ sqd['i'] = sens_type
+ sqd['sensor_locs'] = np.array(sensors)
+
# amplifier gain
fid.seek(KIT_SYS.AMPLIFIER_INFO)
amp_offset = unpack('i', fid.read(KIT_SYS.INT))[0]
@@ -407,9 +598,9 @@ def get_sqd_params(rawfile):
fid.seek(sens_offset)
sens = np.fromfile(fid, dtype='d', count=sqd['nchan'] * 2)
sensitivities = (np.reshape(sens, (sqd['nchan'], 2))
- [:KIT_SYS.n_sens, 1])
- sqd['sensor_gain'] = np.ones(KIT_SYS.nchan)
- sqd['sensor_gain'][:KIT_SYS.n_sens] = sensitivities
+ [:KIT_SYS.N_SENS, 1])
+ sqd['sensor_gain'] = np.ones(KIT_SYS.NCHAN)
+ sqd['sensor_gain'][:KIT_SYS.N_SENS] = sensitivities
fid.seek(KIT_SYS.SAMPLE_INFO)
acqcond_offset = unpack('i', fid.read(KIT_SYS.INT))[0]
@@ -420,47 +611,54 @@ def get_sqd_params(rawfile):
_ = fid.read(KIT_SYS.INT) # initialized estimate of samples
sqd['nsamples'] = unpack('i', fid.read(KIT_SYS.INT))[0]
else:
- raise NotImplementedError
- sqd['n_sens'] = KIT_SYS.n_sens
- sqd['nmegchan'] = KIT_SYS.nmegchan
- sqd['nmiscchan'] = KIT_SYS.nmiscchan
+ err = ("You are probably trying to load a file that is not a "
+ "continuous recording sqd file.")
+ raise ValueError(err)
+ sqd['n_sens'] = KIT_SYS.N_SENS
+ sqd['nmegchan'] = KIT_SYS.NMEGCHAN
+ sqd['nmiscchan'] = KIT_SYS.NMISCCHAN
sqd['DYNAMIC_RANGE'] = KIT_SYS.DYNAMIC_RANGE
return sqd
-def read_raw_kit(input_fname, mrk_fname, elp_fname, hsp_fname, sns_fname,
- stim='<', stimthresh=1, verbose=None, preload=False):
+def read_raw_kit(input_fname, mrk=None, elp=None, hsp=None, stim='>',
+ slope='-', stimthresh=1, preload=False, verbose=None):
"""Reader function for KIT conversion to FIF
Parameters
----------
input_fname : str
- Absolute path to the sqd file.
- mrk_fname : str
- Absolute path to marker coils file.
- elp_fname : str
- Absolute path to elp digitizer laser points file.
- hsp_fname : str
- Absolute path to elp digitizer head shape points file.
- sns_fname : str
- Absolute path to sensor information file.
+ Path to the sqd file.
+ mrk : None | str | array_like, shape = (5, 3)
+ Marker points representing the location of the marker coils with
+ respect to the MEG Sensors, or path to a marker file.
+ elp : None | str | array_like, shape = (8, 3)
+ Digitizer points representing the location of the fiducials and the
+ marker coils with respect to the digitized head shape, or path to a
+ file containing these points.
+ hsp : None | str | array, shape = (n_points, 3)
+ Digitizer head shape points, or path to head shape file. If more than
+ 10`000 points are in the head shape, they are automatically decimated.
stim : list of int | '<' | '>'
- Can be submitted as list of trigger channels.
- If a list is not specified, the default triggers extracted from
- misc channels, will be used with specified directionality.
- '<' means that largest values assigned to the first channel
- in sequence.
- '>' means the largest trigger assigned to the last channel
- in sequence.
+ Channel-value correspondence when converting KIT trigger channels to a
+ Neuromag-style stim channel. For '<', the largest values are assigned
+ to the first channel (default). For '>', the largest values are
+ assigned to the last channel. Can also be specified as a list of
+ trigger channel indexes.
+ slope : '+' | '-'
+ How to interpret values on KIT trigger channels when synthesizing a
+ Neuromag-style stim channel. With '+', a positive slope (low-to-high)
+ is interpreted as an event. With '-', a negative slope (high-to-low)
+ is interpreted as an event.
stimthresh : float
- The threshold level for accepting voltage change as a trigger event.
+ The threshold level for accepting voltage changes in KIT trigger
+ channels as a trigger event.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
preload : bool
If True, all data are loaded at initialization.
If False, data are not read until save.
"""
- return RawKIT(input_fname=input_fname, mrk_fname=mrk_fname,
- elp_fname=elp_fname, hsp_fname=hsp_fname,
- sns_fname=sns_fname, stim=stim, stimthresh=stimthresh,
+ return RawKIT(input_fname=input_fname, mrk=mrk, elp=elp, hsp=hsp,
+ stim=stim, slope=slope, stimthresh=stimthresh,
verbose=verbose, preload=preload)
diff --git a/mne/fiff/kit/tests/data/trans-sample.fif b/mne/fiff/kit/tests/data/trans-sample.fif
new file mode 100644
index 0000000..56e894b
Binary files /dev/null and b/mne/fiff/kit/tests/data/trans-sample.fif differ
diff --git a/mne/fiff/kit/tests/test_coreg.py b/mne/fiff/kit/tests/test_coreg.py
new file mode 100644
index 0000000..3a140d5
--- /dev/null
+++ b/mne/fiff/kit/tests/test_coreg.py
@@ -0,0 +1,75 @@
+# Authors: Christian Brodbeck <christianbrodbeck at nyu.edu>
+#
+# License: BSD (3-clause)
+
+import inspect
+import os
+
+import numpy as np
+from numpy.testing import assert_array_almost_equal, assert_array_equal
+
+from mne.fiff.kit import read_hsp, write_hsp, read_mrk, write_mrk
+from mne.coreg import get_ras_to_neuromag_trans
+from mne.transforms import apply_trans, rotation, translation
+from mne.utils import _TempDir
+
+
+FILE = inspect.getfile(inspect.currentframe())
+parent_dir = os.path.dirname(os.path.abspath(FILE))
+data_dir = os.path.join(parent_dir, 'data')
+hsp_fname = os.path.join(data_dir, 'test_hsp.txt')
+mrk_fname = os.path.join(data_dir, 'test_mrk.sqd')
+
+tempdir = _TempDir()
+
+
+def test_io_hsp():
+ """Test IO for hsp files"""
+ pts = read_hsp(hsp_fname)
+
+ dest = os.path.join(tempdir, 'test.txt')
+ write_hsp(dest, pts)
+ pts1 = read_hsp(dest)
+
+ assert_array_equal(pts, pts1)
+
+
+def test_io_mrk():
+ """Test IO for mrk files"""
+ pts = read_mrk(mrk_fname)
+
+ # pickle
+ path = os.path.join(tempdir, 'mrk.pickled')
+ write_mrk(path, pts)
+ pts_2 = read_mrk(path)
+ assert_array_equal(pts, pts_2, "read/write with pickle")
+
+ # txt
+ path = os.path.join(tempdir, 'mrk.txt')
+ write_mrk(path, pts)
+ pts_2 = read_mrk(path)
+ assert_array_equal(pts, pts_2, "read/write mrk to text")
+
+
+def test_hsp_trans():
+ """Test the coordinate transformation for hsp files"""
+ # create model points in neuromag-like space
+ anterior = [0, 1, 0]
+ left = [-1, 0, 0]
+ right = [.8, 0, 0]
+ up = [0, 0, 1]
+ rand_pts = np.random.uniform(-1, 1, (3, 3))
+ pts = np.vstack((anterior, left, right, up, rand_pts))
+
+ # change coord system
+ rx, ry, rz, tx, ty, tz = np.random.uniform(-2 * np.pi, 2 * np.pi, 6)
+ trans = np.dot(translation(tx, ty, tz), rotation(rx, ry, rz))
+ pts_changed = apply_trans(trans, pts)
+
+ # transform back into original space
+ nas, lpa, rpa = pts_changed[:3]
+ hsp_trans = get_ras_to_neuromag_trans(nas, lpa, rpa)
+ pts_restored = apply_trans(hsp_trans, pts_changed)
+
+ assert_array_almost_equal(pts_restored, pts, 6, "Neuromag transformation "
+ "failed")
diff --git a/mne/fiff/kit/tests/test_kit.py b/mne/fiff/kit/tests/test_kit.py
index 3bca73b..b82e9be 100644
--- a/mne/fiff/kit/tests/test_kit.py
+++ b/mne/fiff/kit/tests/test_kit.py
@@ -10,24 +10,29 @@ import numpy as np
from numpy.testing import assert_array_almost_equal, assert_array_equal
import scipy.io
from mne.utils import _TempDir
-from mne.fiff import Raw, pick_types, kit
+from mne.fiff import Raw, pick_types
+from mne.fiff.kit import read_raw_kit, read_hsp, write_hsp
+from mne.fiff.kit.coreg import read_sns
FILE = inspect.getfile(inspect.currentframe())
parent_dir = op.dirname(op.abspath(FILE))
data_dir = op.join(parent_dir, 'data')
+sqd_path = op.join(data_dir, 'test.sqd')
+mrk_path = op.join(data_dir, 'test_mrk.sqd')
+elp_path = op.join(data_dir, 'test_elp.txt')
+hsp_path = op.join(data_dir, 'test_hsp.txt')
+
tempdir = _TempDir()
def test_data():
"""Test reading raw kit files
"""
- raw_py = kit.read_raw_kit(input_fname=op.join(data_dir, 'test.sqd'),
- mrk_fname=op.join(data_dir, 'test_mrk.sqd'),
- elp_fname=op.join(data_dir, 'test_elp.txt'),
- hsp_fname=op.join(data_dir, 'test_hsp.txt'),
- sns_fname=op.join(data_dir, 'sns.txt'),
- stim=range(167, 159, -1), stimthresh=1,
- preload=True)
+ raw_py = read_raw_kit(sqd_path, mrk_path, elp_path, hsp_path,
+ stim=range(167, 159, -1), slope='+', stimthresh=1,
+ preload=True)
+ print repr(raw_py)
+
# Binary file only stores the sensor channels
py_picks = pick_types(raw_py.info, exclude='bads')
raw_bin = op.join(data_dir, 'test_bin.fif')
@@ -43,7 +48,8 @@ def test_data():
assert_array_almost_equal(data_py, data_Ykgw)
- py_picks = pick_types(raw_py.info, stim=True, exclude='bads')
+ py_picks = pick_types(raw_py.info, stim=True, ref_meg=False,
+ exclude='bads')
data_py, _ = raw_py[py_picks]
assert_array_almost_equal(data_py, data_bin)
@@ -51,59 +57,60 @@ def test_data():
def test_read_segment():
"""Test writing raw kit files when preload is False
"""
- raw1 = kit.read_raw_kit(input_fname=op.join(data_dir, 'test.sqd'),
- mrk_fname=op.join(data_dir, 'test_mrk.sqd'),
- elp_fname=op.join(data_dir, 'test_elp.txt'),
- hsp_fname=op.join(data_dir, 'test_hsp.txt'),
- sns_fname=op.join(data_dir, 'sns.txt'),
- stim=range(167, 159, -1), preload=False)
+ raw1 = read_raw_kit(sqd_path, mrk_path, elp_path, hsp_path, stim='<',
+ preload=False)
raw1_file = op.join(tempdir, 'raw1.fif')
raw1.save(raw1_file, buffer_size_sec=.1, overwrite=True)
- raw2 = kit.read_raw_kit(input_fname=op.join(data_dir, 'test.sqd'),
- mrk_fname=op.join(data_dir, 'test_mrk.sqd'),
- elp_fname=op.join(data_dir, 'test_elp.txt'),
- hsp_fname=op.join(data_dir, 'test_hsp.txt'),
- sns_fname=op.join(data_dir, 'sns.txt'),
- stim=range(167, 159, -1), preload=True)
+ raw2 = read_raw_kit(sqd_path, mrk_path, elp_path, hsp_path, stim='<',
+ preload=True)
raw2_file = op.join(tempdir, 'raw2.fif')
raw2.save(raw2_file, buffer_size_sec=.1, overwrite=True)
raw1 = Raw(raw1_file, preload=True)
raw2 = Raw(raw2_file, preload=True)
assert_array_equal(raw1._data, raw2._data)
- raw3 = kit.read_raw_kit(input_fname=op.join(data_dir, 'test.sqd'),
- mrk_fname=op.join(data_dir, 'test_mrk.sqd'),
- elp_fname=op.join(data_dir, 'test_elp.txt'),
- hsp_fname=op.join(data_dir, 'test_hsp.txt'),
- sns_fname=op.join(data_dir, 'sns.txt'),
- stim=range(167, 159, -1), preload=True)
+ raw3 = read_raw_kit(sqd_path, mrk_path, elp_path, hsp_path, stim='<',
+ preload=True)
assert_array_almost_equal(raw1._data, raw3._data)
+
def test_ch_loc():
"""Test raw kit loc
"""
- raw_py = kit.read_raw_kit(input_fname=op.join(data_dir, 'test.sqd'),
- mrk_fname=op.join(data_dir, 'test_mrk.sqd'),
- elp_fname=op.join(data_dir, 'test_elp.txt'),
- hsp_fname=op.join(data_dir, 'test_hsp.txt'),
- sns_fname=op.join(data_dir, 'sns.txt'),
- stim=range(167, 159, -1))
+ raw_py = read_raw_kit(sqd_path, mrk_path, elp_path, hsp_path, stim='<')
raw_bin = Raw(op.join(data_dir, 'test_bin.fif'))
+ ch_py = raw_py._sqd_params['sensor_locs'][:, :5]
+ # ch locs stored as m, not mm
+ ch_py[:, :3] *= 1e3
+ ch_sns = read_sns(op.join(data_dir, 'sns.txt'))
+ assert_array_almost_equal(ch_py, ch_sns, 2)
+
for py_ch, bin_ch in zip(raw_py.info['chs'], raw_bin.info['chs']):
if bin_ch['ch_name'].startswith('MEG'):
- # the mne_kit2fiff_bin has a different representation of pi.
- assert_array_almost_equal(py_ch['loc'], bin_ch['loc'], decimal=5)
+ # the stored ch locs have more precision than the sns.txt
+ assert_array_almost_equal(py_ch['loc'], bin_ch['loc'], decimal=2)
+ assert_array_almost_equal(py_ch['coil_trans'],
+ bin_ch['coil_trans'],
+ decimal=2)
+
def test_stim_ch():
"""Test raw kit stim ch
"""
- raw = kit.read_raw_kit(input_fname=op.join(data_dir, 'test.sqd'),
- mrk_fname=op.join(data_dir, 'test_mrk.sqd'),
- elp_fname=op.join(data_dir, 'test_elp.txt'),
- hsp_fname=op.join(data_dir, 'test_hsp.txt'),
- sns_fname=op.join(data_dir, 'sns.txt'),
- stim=range(167, 159, -1), preload=True)
- stim_pick = pick_types(raw.info, meg=False, stim=True, exclude='bads')
+ raw = read_raw_kit(sqd_path, mrk_path, elp_path, hsp_path, stim='<',
+ slope='+', preload=True)
+ stim_pick = pick_types(raw.info, meg=False, ref_meg=False,
+ stim=True, exclude='bads')
stim1, _ = raw[stim_pick]
stim2 = np.array(raw.read_stim_ch(), ndmin=2)
assert_array_equal(stim1, stim2)
+
+
+def test_hsp_io():
+ """Test reading and writing hsp files"""
+ pts = read_hsp(hsp_path)
+ temp_fname = op.join(tempdir, 'temp_hsp.txt')
+ write_hsp(temp_fname, pts)
+ pts2 = read_hsp(temp_fname)
+ assert_array_equal(pts, pts2, "Hsp points diverged after writing and "
+ "reading.")
diff --git a/mne/fiff/matrix.py b/mne/fiff/matrix.py
index f8f472f..3f89acd 100644
--- a/mne/fiff/matrix.py
+++ b/mne/fiff/matrix.py
@@ -3,14 +3,11 @@
#
# License: BSD (3-clause)
-import logging
-logger = logging.getLogger('mne')
-
from .constants import FIFF
from .tag import find_tag, has_tag
-from .write import write_int, start_block, end_block, write_float_matrix, \
- write_name_list
-from .. import verbose
+from .write import (write_int, start_block, end_block, write_float_matrix,
+ write_name_list)
+from ..utils import logger, verbose
def _transpose_named_matrix(mat, copy=True):
diff --git a/mne/fiff/meas_info.py b/mne/fiff/meas_info.py
index 6fb899a..b192e96 100644
--- a/mne/fiff/meas_info.py
+++ b/mne/fiff/meas_info.py
@@ -5,12 +5,11 @@
from warnings import warn
from copy import deepcopy
+import os.path as op
import numpy as np
from scipy import linalg
from StringIO import StringIO
-
-import logging
-logger = logging.getLogger('mne')
+from datetime import datetime as dt
from .open import fiff_open
from .tree import dir_tree_find, copy_tree
@@ -19,11 +18,150 @@ from .tag import read_tag
from .proj import read_proj, write_proj
from .ctf import read_ctf_comp, write_ctf_comp
from .channels import read_bad_channels
+from .write import (start_file, end_file, start_block, end_block,
+ write_string, write_dig_point, write_float, write_int,
+ write_coord_trans, write_ch_info, write_name_list)
+from ..utils import logger, verbose
+
+
+def _summarize_str(st):
+ """Aux function"""
+ return st[:56][::-1].split(',', 1)[-1][::-1] + ', ...'
+
+
+class Info(dict):
+ """ Info class to nicely represent info dicts
+ """
+
+ def __repr__(self):
+ """Summarize info instead of printing all"""
+ strs = ['<Info | %s non-empty fields']
+ non_empty = 0
+ for k, v in self.items():
+ if k in ['bads', 'ch_names']:
+ entr = (', '.join(b for ii, b in enumerate(v) if ii < 10)
+ if v else '0 items')
+ if len(entr) >= 56:
+ # get rid of of half printed ch names
+ entr = _summarize_str(entr)
+ elif k == 'filename' and v:
+ path, fname = op.split(v)
+ entr = path[:10] + '.../' + fname
+ elif k == 'projs' and v:
+ entr = ', '.join(p['desc'] + ': o%s' %
+ {0: 'ff', 1: 'n'}[p['active']] for p in v)
+ if len(entr) >= 56:
+ entr = _summarize_str(entr)
+ elif k == 'meas_date' and np.iterable(v):
+ # first entire in meas_date is meaningful
+ entr = dt.fromtimestamp(v[0]).strftime('%Y-%m-%d %H:%M:%S')
+ else:
+ this_len = (len(v) if hasattr(v, '__len__') else
+ ('%s' % v if v is not None else None))
+ entr = (('%d items' % this_len) if isinstance(this_len, int)
+ else ('%s' % this_len if this_len else ''))
+ if entr:
+ non_empty += 1
+ entr = ' | ' + entr
+ strs.append('%s : %s%s' % (k, str(type(v))[7:-2], entr))
+ strs_non_empty = sorted(s for s in strs if '|' in s)
+ strs_empty = sorted(s for s in strs if '|' not in s)
+ st = '\n '.join(strs_non_empty + strs_empty)
+ st += '\n>'
+ st %= non_empty
+ return st
+
+
+def read_fiducials(fname):
+ """Read fiducials from a fiff file
+
+ Returns
+ -------
+ pts : list of dicts
+ List of digitizer points (each point in a dict).
+ coord_frame : int
+ The coordinate frame of the points (one of
+ mne.fiff.FIFF.FIFFV_COORD_...)
+ """
+ fid, tree, _ = fiff_open(fname)
+ with fid:
+ isotrak = dir_tree_find(tree, FIFF.FIFFB_ISOTRAK)
+ isotrak = isotrak[0]
+ pts = []
+ coord_frame = FIFF.FIFFV_COORD_UNKNOWN
+ for k in range(isotrak['nent']):
+ kind = isotrak['directory'][k].kind
+ pos = isotrak['directory'][k].pos
+ if kind == FIFF.FIFF_DIG_POINT:
+ tag = read_tag(fid, pos)
+ pts.append(tag.data)
+ elif kind == FIFF.FIFF_MNE_COORD_FRAME:
+ tag = read_tag(fid, pos)
+ coord_frame = tag.data[0]
+
+ if coord_frame == FIFF.FIFFV_COORD_UNKNOWN:
+ err = ("No coordinate frame was found in the file %r, it is probably "
+ "not a valid fiducials file." % fname)
+ raise ValueError(err)
+
+ # coord_frame is not stored in the tag
+ for pt in pts:
+ pt['coord_frame'] = coord_frame
-from .write import start_block, end_block, write_string, write_dig_point, \
- write_float, write_int, write_coord_trans, write_ch_info, \
- write_name_list, start_file
-from .. import verbose
+ return pts, coord_frame
+
+
+def write_fiducials(fname, pts, coord_frame=0):
+ """Write fiducials to a fiff file
+
+ Parameters
+ ----------
+ fname : str
+ Destination file name.
+ pts : iterator of dict
+ Iterator through digitizer points. Each point is a dictionary with
+ the keys 'kind', 'ident' and 'r'.
+ coord_frame : int
+ The coordinate frame of the points (one of
+ mne.fiff.FIFF.FIFFV_COORD_...)
+ """
+ pts_frames = set((pt.get('coord_frame', coord_frame) for pt in pts))
+ bad_frames = pts_frames - set((coord_frame,))
+ if len(bad_frames) > 0:
+ err = ("Points have coord_frame entries that are incompatible with "
+ "coord_frame=%i: %s." % (coord_frame, str(tuple(bad_frames))))
+ raise ValueError(err)
+
+ fid = start_file(fname)
+ start_block(fid, FIFF.FIFFB_ISOTRAK)
+ write_int(fid, FIFF.FIFF_MNE_COORD_FRAME, coord_frame)
+ for pt in pts:
+ write_dig_point(fid, pt)
+
+ end_block(fid, FIFF.FIFFB_ISOTRAK)
+ end_file(fid)
+
+
+ at verbose
+def read_info(fname, verbose=None):
+ """Read measurement info from a file
+
+ Parameters
+ ----------
+ fname : str
+ File name.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ info : instance of mne.fiff.meas_info.Info
+ Info on dataset.
+ """
+ f, tree, _ = fiff_open(fname)
+ with f as fid:
+ info = read_meas_info(fid, tree)[0]
+ return info
@verbose
@@ -41,7 +179,7 @@ def read_meas_info(fid, tree, verbose=None):
Returns
-------
- info : dict
+ info : instance of mne.fiff.meas_info.Info
Info on dataset.
meas : dict
Node in tree that contains the info.
@@ -196,9 +334,9 @@ def read_meas_info(fid, tree, verbose=None):
# Put the data together
#
if tree['id'] is not None:
- info = dict(file_id=tree['id'])
+ info = Info(file_id=tree['id'])
else:
- info = dict(file_id=None)
+ info = Info(file_id=None)
# Load extra information blocks
read_extra_meas_info(fid, tree, info)
@@ -286,7 +424,7 @@ def read_extra_meas_info(fid, tree, info):
def write_extra_meas_info(fid, info):
"""Write otherwise left out blocks of data"""
# uses cStringIO fake file to read the appropriate blocks
- if 'orig_blocks' in info:
+ if 'orig_blocks' in info and info['orig_blocks'] is not None:
# Blocks from the original
blocks = info['orig_blocks']
fid_str, tree, _ = fiff_open(info['orig_fid_str'])
@@ -302,7 +440,7 @@ def write_meas_info(fid, info, data_type=None, reset_range=True):
----------
fid : file
Open file descriptor
- info : dict
+ info : instance of mne.fiff.meas_info.Info
The measurement info structure
data_type : int
The data_type in case it is necessary. Should be 4 (FIFFT_FLOAT),
diff --git a/mne/fiff/open.py b/mne/fiff/open.py
index 8c7aabf..d5b1b2b 100644
--- a/mne/fiff/open.py
+++ b/mne/fiff/open.py
@@ -7,13 +7,11 @@ import numpy as np
import os.path as op
import gzip
import cStringIO
-import logging
-logger = logging.getLogger('mne')
from .tag import read_tag_info, read_tag, read_big, Tag
from .tree import make_dir_tree
from .constants import FIFF
-from .. import verbose
+from ..utils import logger, verbose
@verbose
diff --git a/mne/fiff/pick.py b/mne/fiff/pick.py
index c54e037..5e8f45e 100644
--- a/mne/fiff/pick.py
+++ b/mne/fiff/pick.py
@@ -8,12 +8,9 @@ from copy import deepcopy
import re
from warnings import warn
-import logging
-logger = logging.getLogger('mne')
-
import numpy as np
from .constants import FIFF
-from .. import verbose
+from ..utils import logger, verbose
def channel_type(info, idx):
@@ -29,7 +26,7 @@ def channel_type(info, idx):
Returns
-------
type : 'grad' | 'mag' | 'eeg' | 'stim' | 'eog' | 'emg' | 'ecg'
- 'ref_meg' | 'resp'
+ 'ref_meg' | 'resp' | 'exci' | 'ias' | 'syst'
Type of channel
"""
kind = info['chs'][idx]['kind']
@@ -54,6 +51,12 @@ def channel_type(info, idx):
return 'resp'
elif kind == FIFF.FIFFV_MISC_CH:
return 'misc'
+ elif kind == FIFF.FIFFV_EXCI_CH:
+ return 'exci'
+ elif kind == FIFF.FIFFV_IAS_CH:
+ return 'ias'
+ elif kind == FIFF.FIFFV_SYST_CH:
+ return 'syst'
elif kind in [FIFF.FIFFV_QUAT_0, FIFF.FIFFV_QUAT_1, FIFF.FIFFV_QUAT_2,
FIFF.FIFFV_QUAT_3, FIFF.FIFFV_QUAT_4, FIFF.FIFFV_QUAT_5,
FIFF.FIFFV_QUAT_6, FIFF.FIFFV_HPI_G, FIFF.FIFFV_HPI_ERR,
@@ -121,8 +124,9 @@ def pick_channels_regexp(ch_names, regexp):
def pick_types(info, meg=True, eeg=False, stim=False, eog=False, ecg=False,
- emg=False, ref_meg=False, misc=False, resp=False, chpi=False,
- include=[], exclude=None, selection=None):
+ emg=False, ref_meg='auto', misc=False, resp=False, chpi=False,
+ exci=False, ias=False, syst=False,
+ include=[], exclude='bads', selection=None):
"""Pick channels by type and names
Parameters
@@ -131,8 +135,9 @@ def pick_types(info, meg=True, eeg=False, stim=False, eog=False, ecg=False,
The measurement info.
meg : bool or string
If True include all MEG channels. If False include None
- If string it can be 'mag', 'grad', 'planar1' or 'planar2' to select only
- magnetometers, all gradiometers, or a specific type of gradiometer.
+ If string it can be 'mag', 'grad', 'planar1' or 'planar2' to select
+ only magnetometers, all gradiometers, or a specific type of
+ gradiometer.
eeg : bool
If True include EEG channels.
eog : bool
@@ -143,8 +148,9 @@ def pick_types(info, meg=True, eeg=False, stim=False, eog=False, ecg=False,
If True include EMG channels.
stim : bool
If True include stimulus channels.
- ref_meg: bool
- If True include CTF / 4D reference channels.
+ ref_meg: bool | str
+ If True include CTF / 4D reference channels. If 'auto', the reference
+ channels are only included if compensations are present.
misc : bool
If True include miscellaneous analog channels.
resp : bool
@@ -152,6 +158,12 @@ def pick_types(info, meg=True, eeg=False, stim=False, eog=False, ecg=False,
is separate from the stim channel.
chpi : bool
If True include continuous HPI coil channels.
+ exci : bool
+ Flux excitation channel used to be a stimulus channel.
+ ias : bool
+ Internal Active Shielding data (maybe on Triux only).
+ syst : bool
+ System status channel information (on Triux systems only).
include : list of string
List of additional channels to include. If empty do not include any.
exclude : list of string | str
@@ -169,12 +181,7 @@ def pick_types(info, meg=True, eeg=False, stim=False, eog=False, ecg=False,
pick = np.zeros(nchan, dtype=np.bool)
if exclude is None:
- msg = ('In pick_types, the parameter "exclude" must be specified as '
- 'either "bads" or a list of channels to exclude. In 0.7, the '
- 'default will be changed from [] (current behavior) to "bads".')
- warn(msg, category=DeprecationWarning)
- logger.warn(msg)
- exclude = []
+ raise ValueError('exclude must be a list of strings or "bads"')
elif exclude == 'bads':
exclude = info.get('bads', [])
elif not isinstance(exclude, list):
@@ -182,6 +189,11 @@ def pick_types(info, meg=True, eeg=False, stim=False, eog=False, ecg=False,
' If only one channel is to be excluded, use '
'[ch_name] instead of passing ch_name.')
+ if isinstance(ref_meg, basestring):
+ if ref_meg != 'auto':
+ raise ValueError('ref_meg has to be either a bool or \'auto\'')
+ ref_meg = info['comps'] is not None and len(info['comps']) > 0
+
for k in range(nchan):
kind = info['chs'][k]['kind']
if kind == FIFF.FIFFV_MEG_CH:
@@ -190,9 +202,9 @@ def pick_types(info, meg=True, eeg=False, stim=False, eog=False, ecg=False,
elif info['chs'][k]['unit'] == FIFF.FIFF_UNIT_T_M:
if meg == 'grad':
pick[k] = True
- elif meg == 'planar1' and info['ch_names'][k].endswith('2'):
+ elif meg == 'planar1' and info['ch_names'][k].endswith('2'):
pick[k] = True
- elif meg == 'planar2' and info['ch_names'][k].endswith('3'):
+ elif meg == 'planar2' and info['ch_names'][k].endswith('3'):
pick[k] = True
elif (meg == 'mag'
and info['chs'][k]['unit'] == FIFF.FIFF_UNIT_T):
@@ -213,6 +225,12 @@ def pick_types(info, meg=True, eeg=False, stim=False, eog=False, ecg=False,
pick[k] = True
elif kind == FIFF.FIFFV_RESP_CH and resp:
pick[k] = True
+ elif kind == FIFF.FIFFV_SYST_CH and syst:
+ pick[k] = True
+ elif kind == FIFF.FIFFV_IAS_CH and ias:
+ pick[k] = True
+ elif kind == FIFF.FIFFV_EXCI_CH and exci:
+ pick[k] = True
elif kind in [FIFF.FIFFV_QUAT_0, FIFF.FIFFV_QUAT_1, FIFF.FIFFV_QUAT_2,
FIFF.FIFFV_QUAT_3, FIFF.FIFFV_QUAT_4, FIFF.FIFFV_QUAT_5,
FIFF.FIFFV_QUAT_6, FIFF.FIFFV_HPI_G, FIFF.FIFFV_HPI_ERR,
@@ -266,7 +284,19 @@ def pick_info(info, sel=[]):
return res
-def pick_channels_evoked(orig, include=[], exclude=[]):
+def _has_kit_refs(info, picks):
+ """Helper to determine if KIT ref channels are chosen
+
+ This is currently only used by make_forward_solution, which cannot
+ run when KIT reference channels are included.
+ """
+ for p in picks:
+ if info['chs'][p]['coil_type'] == FIFF.FIFFV_COIL_KIT_REF_MAG:
+ return True
+ return False
+
+
+def pick_channels_evoked(orig, include=[], exclude='bads'):
"""Pick channels from evoked data
Parameters
@@ -309,7 +339,8 @@ def pick_channels_evoked(orig, include=[], exclude=[]):
def pick_types_evoked(orig, meg=True, eeg=False, stim=False, eog=False,
ecg=False, emg=False, ref_meg=False, misc=False,
- resp=False, chpi=False, include=[], exclude=None):
+ resp=False, chpi=False, exci=False, ias=False,
+ syst=False, include=[], exclude='bads'):
"""Pick by channel type and names from evoked data
Parameters
@@ -339,6 +370,12 @@ def pick_types_evoked(orig, meg=True, eeg=False, stim=False, eog=False,
is separate from the stim channel.
chpi : bool
If True include continuous HPI coil channels.
+ exci : bool
+ Flux excitation channel used to be a stimulus channel.
+ ias : bool
+ Internal Active Shielding data (maybe on Triux only).
+ syst : bool
+ System status channel information (on Triux systems only).
include : list of string
List of additional channels to include. If empty do not include any.
exclude : list of string | str
@@ -353,13 +390,14 @@ def pick_types_evoked(orig, meg=True, eeg=False, stim=False, eog=False,
"""
sel = pick_types(info=orig.info, meg=meg, eeg=eeg, stim=stim, eog=eog,
ecg=ecg, emg=emg, ref_meg=ref_meg, misc=misc,
- resp=resp, chpi=chpi, include=include, exclude=exclude)
+ resp=resp, chpi=chpi, exci=exci, ias=ias, syst=syst,
+ include=include, exclude=exclude)
include_ch_names = [orig.ch_names[k] for k in sel]
return pick_channels_evoked(orig, include_ch_names)
@verbose
-def pick_channels_forward(orig, include=[], exclude=[], verbose=None):
+def pick_channels_forward(orig, include=[], exclude='bads', verbose=None):
"""Pick channels from forward operator
Parameters
@@ -398,6 +436,7 @@ def pick_channels_forward(orig, include=[], exclude=[], verbose=None):
# Pick the correct rows of the forward operator
fwd['sol']['data'] = fwd['sol']['data'][sel, :]
+ fwd['_orig_sol'] = fwd['_orig_sol'][sel, :]
fwd['sol']['nrow'] = nuse
ch_names = [fwd['sol']['row_names'][k] for k in sel]
@@ -411,6 +450,7 @@ def pick_channels_forward(orig, include=[], exclude=[], verbose=None):
if fwd['sol_grad'] is not None:
fwd['sol_grad']['data'] = fwd['sol_grad']['data'][sel, :]
+ fwd['_orig_sol_grad'] = fwd['_orig_sol_grad'][sel, :]
fwd['sol_grad']['nrow'] = nuse
fwd['sol_grad']['row_names'] = [fwd['sol_grad']['row_names'][k]
for k in sel]
@@ -466,7 +506,7 @@ def channel_indices_by_type(info):
return idx
-def pick_channels_cov(orig, include=[], exclude=[]):
+def pick_channels_cov(orig, include=[], exclude='bads'):
"""Pick channels from covariance matrix
Parameters
diff --git a/mne/fiff/proj.py b/mne/fiff/proj.py
index 98a1ef4..754d2a8 100644
--- a/mne/fiff/proj.py
+++ b/mne/fiff/proj.py
@@ -9,15 +9,11 @@ from math import sqrt
import numpy as np
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
from .tree import dir_tree_find
from .constants import FIFF
from .tag import find_tag
from .pick import pick_types
-from .. import verbose
-from ..utils import deprecated
+from ..utils import logger, verbose
class Projection(dict):
@@ -71,38 +67,6 @@ class ProjMixin(object):
return self
- @deprecated(r"'apply_projector' is deprecated and will be removed in "
- "version 0.7. Please use apply_proj instead")
- def apply_projector(self):
- """Apply the signal space projection (SSP) operators to the data.
-
- Notes
- -----
- Once the projectors have been applied, they can no longer be
- removed. It is usually not recommended to apply the projectors at
- too early stages, as they are applied automatically later on
- (e.g. when computing inverse solutions).
- Hint: using the copy method individual projection vectors
- can be tested without affecting the original data.
- With evoked data, consider the following example::
-
- projs_a = mne.read_proj('proj_a.fif')
- projs_b = mne.read_proj('proj_b.fif')
- # add the first, copy, apply and see ...
- evoked.add_proj(a).copy().apply_proj().plot()
- # add the second, copy, apply and see ...
- evoked.add_proj(b).copy().apply_proj().plot()
- # drop the first and see again
- evoked.copy().del_proj(0).apply_proj().plot()
- evoked.apply_proj() # finally keep both
-
- Returns
- -------
- self : instance of Raw | Epochs | Evoked
- The instance.
- """
- return self.apply_proj()
-
def apply_proj(self):
"""Apply the signal space projection (SSP) operators to the data.
@@ -302,14 +266,18 @@ def read_proj(fid, node, verbose=None):
else:
active = False
+ # handle the case when data is transposed for some reason
+ if data.shape[0] == len(names) and data.shape[1] == nvec:
+ data = data.T
+
if data.shape[1] != len(names):
raise ValueError('Number of channel names does not match the '
'size of data matrix')
# Use exactly the same fields in data as in a named matrix
one = Projection(kind=kind, active=active, desc=desc,
- data=dict(nrow=nvec, ncol=nchan, row_names=None,
- col_names=names, data=data))
+ data=dict(nrow=nvec, ncol=nchan, row_names=None,
+ col_names=names, data=data))
projs.append(one)
@@ -329,8 +297,8 @@ def read_proj(fid, node, verbose=None):
###############################################################################
# Write
-from .write import write_int, write_float, write_string, write_name_list, \
- write_float_matrix, end_block, start_block
+from .write import (write_int, write_float, write_string, write_name_list,
+ write_float_matrix, end_block, start_block)
def write_proj(fid, projs):
@@ -571,7 +539,8 @@ def make_eeg_average_ref_proj(info, activate=True, verbose=None):
The SSP/PCA projector.
"""
logger.info("Adding average EEG reference projection.")
- eeg_sel = pick_types(info, meg=False, eeg=True, exclude='bads')
+ eeg_sel = pick_types(info, meg=False, eeg=True, ref_meg=False,
+ exclude='bads')
ch_names = info['ch_names']
eeg_names = [ch_names[k] for k in eeg_sel]
n_eeg = len(eeg_sel)
@@ -621,7 +590,8 @@ def setup_proj(info, add_eeg_ref=True, activate=True,
The modified measurement info (Warning: info is modified inplace).
"""
# Add EEG ref reference proj if necessary
- eeg_sel = pick_types(info, meg=False, eeg=True, exclude='bads')
+ eeg_sel = pick_types(info, meg=False, eeg=True, ref_meg=False,
+ exclude='bads')
if len(eeg_sel) > 0 and not _has_eeg_average_ref_proj(info['projs']) \
and add_eeg_ref is True:
eeg_proj = make_eeg_average_ref_proj(info, activate=activate)
diff --git a/mne/fiff/raw.py b/mne/fiff/raw.py
index e42bcb6..c0a7957 100644
--- a/mne/fiff/raw.py
+++ b/mne/fiff/raw.py
@@ -16,25 +16,22 @@ import numpy as np
from scipy.signal import hilbert
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
from .constants import FIFF
from .open import fiff_open
from .meas_info import read_meas_info, write_meas_info
from .tree import dir_tree_find
from .tag import read_tag
from .pick import pick_types, channel_type
-from .proj import setup_proj, activate_proj, proj_equal, ProjMixin
+from .proj import (setup_proj, activate_proj, proj_equal, ProjMixin,
+ _has_eeg_average_ref_proj, make_eeg_average_ref_proj)
from .compensator import get_current_comp, make_compensator
-from ..filter import low_pass_filter, high_pass_filter, band_pass_filter, \
- notch_filter, band_stop_filter, resample
+from ..filter import (low_pass_filter, high_pass_filter, band_pass_filter,
+ notch_filter, band_stop_filter, resample)
from ..parallel import parallel_func
-from ..utils import deprecated, _check_fname, estimate_rank, \
- _check_pandas_installed
-from ..viz import plot_raw, _mutable_defaults
-from .. import verbose
+from ..utils import (_check_fname, estimate_rank, _check_pandas_installed,
+ logger, verbose)
+from ..viz import plot_raw, plot_raw_psds, _mutable_defaults
class Raw(ProjMixin):
@@ -66,6 +63,9 @@ class Raw(ProjMixin):
If None the compensation in the data is not modified.
If set to n, e.g. 3, apply gradient compensation of grade n as
for CTF systems.
+ add_eeg_ref : bool
+ If True, add average EEG reference projector (if it's not already
+ present).
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
@@ -73,23 +73,18 @@ class Raw(ProjMixin):
----------
info : dict
Measurement info.
- `ch_names` : list of string
+ ch_names : list of string
List of channels' names.
- `n_times` : int
+ n_times : int
Total number of time points in the raw file.
verbose : bool, str, int, or None
See above.
"""
@verbose
def __init__(self, fnames, allow_maxshield=False, preload=False,
- proj=False, proj_active=None, compensation=None,
+ proj=False, compensation=None, add_eeg_ref=True,
verbose=None):
- if proj_active is not None:
- warnings.warn('proj_active param in Raw is deprecated and will be'
- ' removed in version 0.7. Please use proj instead.')
- proj = proj_active
-
if not isinstance(fnames, list):
fnames = [op.abspath(fnames)] if not op.isabs(fnames) else [fnames]
else:
@@ -97,7 +92,6 @@ class Raw(ProjMixin):
raws = [self._read_raw_file(fname, allow_maxshield, preload,
compensation) for fname in fnames]
-
_check_raw_compatibility(raws)
# combine information from each raw file to construct self
@@ -115,6 +109,7 @@ class Raw(ProjMixin):
self.info['filenames'] = fnames
self.orig_format = raws[0].orig_format
self.proj = False
+ self._add_eeg_ref(add_eeg_ref)
if preload:
self._preload_data(preload)
@@ -147,6 +142,15 @@ class Raw(ProjMixin):
except:
return exception_type, exception_val, trace
+ def _add_eeg_ref(self, add_eeg_ref):
+ """Helper to add an average EEG reference"""
+ if add_eeg_ref:
+ eegs = pick_types(self.info, meg=False, eeg=True, ref_meg=False)
+ projs = self.info['projs']
+ if len(eegs) > 0 and not _has_eeg_average_ref_proj(projs):
+ eeg_ref = make_eeg_average_ref_proj(self.info, activate=False)
+ projs.append(eeg_ref)
+
def _preload_data(self, preload):
"""This function actually preloads the data"""
if isinstance(preload, basestring):
@@ -347,8 +351,8 @@ class Raw(ProjMixin):
if isinstance(item[1], slice):
time_slice = item[1]
- start, stop, step = time_slice.start, time_slice.stop, \
- time_slice.step
+ start, stop, step = (time_slice.start, time_slice.stop,
+ time_slice.step)
elif isinstance(item[1], int):
start, stop, step = item[1], item[1] + 1, 1
else:
@@ -374,8 +378,8 @@ class Raw(ProjMixin):
data, times = self._data[sel, start:stop], self._times[start:stop]
else:
data, times = self._read_segment(start=start, stop=stop, sel=sel,
- projector=self._projector,
- verbose=self.verbose)
+ projector=self._projector,
+ verbose=self.verbose)
return data, times
def __setitem__(self, item, value):
@@ -576,11 +580,25 @@ class Raw(ProjMixin):
l_freq = None
if h_freq > (fs / 2.):
h_freq = None
+ if l_freq is not None and not isinstance(l_freq, float):
+ l_freq = float(l_freq)
+ if h_freq is not None and not isinstance(h_freq, float):
+ h_freq = float(h_freq)
+
if not self._preloaded:
raise RuntimeError('Raw data needs to be preloaded to filter. Use '
'preload=True (or string) in the constructor.')
if picks is None:
- picks = pick_types(self.info, meg=True, eeg=True, exclude=[])
+ if 'ICA ' in ','.join(self.ch_names):
+ pick_parameters = dict(misc=True, ref_meg=False)
+ else:
+ pick_parameters = dict(meg=True, eeg=True, ref_meg=False)
+ picks = pick_types(self.info, exclude=[], **pick_parameters)
+ # let's be safe.
+ if len(picks) < 1:
+ raise RuntimeError('Could not find any valid channels for '
+ 'your Raw object. Please contact the '
+ 'MNE-Python developers.')
# update info if filter is applied to all data channels,
# and it's not a band-stop filter
@@ -691,7 +709,16 @@ class Raw(ProjMixin):
verbose = self.verbose
fs = float(self.info['sfreq'])
if picks is None:
- picks = pick_types(self.info, meg=True, eeg=True, exclude=[])
+ if 'ICA ' in ','.join(self.ch_names):
+ pick_parameters = dict(misc=True)
+ else:
+ pick_parameters = dict(meg=True, eeg=True)
+ picks = pick_types(self.info, exclude=[], **pick_parameters)
+ # let's be safe.
+ if len(picks) < 1:
+ raise RuntimeError('Could not find any valid channels for '
+ 'your Raw object. Please contact the '
+ 'MNE-Python developers.')
if not self._preloaded:
raise RuntimeError('Raw data needs to be preloaded to filter. Use '
'preload=True (or string) in the constructor.')
@@ -748,16 +775,17 @@ class Raw(ProjMixin):
"""
if not self._preloaded:
raise RuntimeError('Can only resample preloaded data')
+ sfreq = float(sfreq)
+ o_sfreq = float(self.info['sfreq'])
- o_sfreq = self.info['sfreq']
offsets = np.concatenate(([0], np.cumsum(self._raw_lengths)))
new_data = list()
# set up stim channel processing
if stim_picks is None:
- stim_picks = pick_types(self.info, meg=False, stim=True,
- exclude=[])
+ stim_picks = pick_types(self.info, meg=False, ref_meg=False,
+ stim=True, exclude=[])
stim_picks = np.asanyarray(stim_picks)
- ratio = sfreq / float(o_sfreq)
+ ratio = sfreq / o_sfreq
for ri in range(len(self._raw_lengths)):
data_chunk = self._data[:, offsets[ri]:offsets[ri + 1]]
new_data.append(resample(data_chunk, sfreq, o_sfreq, npad,
@@ -770,9 +798,13 @@ class Raw(ProjMixin):
# of channels and then use np.insert() to restore the stims
# figure out which points in old data to subsample
- stim_inds = np.floor(np.arange(new_ntimes) / ratio).astype(int)
+ # protect against out-of-bounds, which can happen (having
+ # one sample more than expected) due to padding
+ stim_inds = np.minimum(np.floor(np.arange(new_ntimes)
+ / ratio).astype(int),
+ data_chunk.shape[1] - 1)
for sp in stim_picks:
- new_data[ri][sp] = data_chunk[sp][:, stim_inds]
+ new_data[ri][sp] = data_chunk[[sp]][:, stim_inds]
self._first_samps[ri] = int(self._first_samps[ri] * ratio)
self._last_samps[ri] = self._first_samps[ri] + new_ntimes - 1
@@ -783,6 +815,8 @@ class Raw(ProjMixin):
self.first_samp = self._first_samps[0]
self.last_samp = self.first_samp + self._data.shape[1] - 1
self.info['sfreq'] = sfreq
+ self._times = (np.arange(self.n_times, dtype=np.float64)
+ / self.info['sfreq'])
def crop(self, tmin=0.0, tmax=None, copy=True):
"""Crop raw data file.
@@ -837,16 +871,17 @@ class Raw(ProjMixin):
raw.fids = [f for fi, f in enumerate(raw.fids) if fi in keepers]
raw.rawdirs = [r for ri, r in enumerate(raw.rawdirs)
if ri in keepers]
- if raw._preloaded:
- raw._data = raw._data[:, smin:smax + 1]
raw.first_samp = raw._first_samps[0]
raw.last_samp = raw.first_samp + (smax - smin)
+ if raw._preloaded:
+ raw._data = raw._data[:, smin:smax + 1]
+ raw._times = np.arange(raw.n_times) / raw.info['sfreq']
return raw
@verbose
def save(self, fname, picks=None, tmin=0, tmax=None, buffer_size_sec=10,
drop_small_buffer=False, proj=False, format='single',
- overwrite=False, verbose=None, proj_active=None):
+ overwrite=False, verbose=None):
"""Save raw data to file
Parameters
@@ -896,11 +931,6 @@ class Raw(ProjMixin):
or all forms of SSS). It is recommended not to concatenate and
then save raw files for this reason.
"""
- if proj_active is not None:
- warnings.warn('proj_active param in Raw is deprecated and will be'
- ' removed in version 0.7. Please use proj instead.')
- proj = proj_active
-
fname = op.abspath(fname)
if not self._preloaded and fname in self.info['filenames']:
raise ValueError('You cannot save data to the same file.'
@@ -966,7 +996,8 @@ class Raw(ProjMixin):
if self.comp is not None:
inv_comp = linalg.inv(self.comp)
- write_int(outfid, FIFF.FIFF_FIRST_SAMPLE, first_samp)
+ if first_samp != 0:
+ write_int(outfid, FIFF.FIFF_FIRST_SAMPLE, first_samp)
for first in range(start, stop, buffer_size):
last = first + buffer_size
if last >= stop:
@@ -994,7 +1025,7 @@ class Raw(ProjMixin):
def plot(raw, events=None, duration=10.0, start=0.0, n_channels=20,
bgcolor='w', color=None, bad_color=(0.8, 0.8, 0.8),
event_color='cyan', scalings=None, remove_dc=True, order='type',
- show_options=False, title=None, show=True):
+ show_options=False, title=None, show=True, block=False):
"""Plot raw data
Parameters
@@ -1037,6 +1068,9 @@ class Raw(ProjMixin):
raw object or '<unknown>' will be displayed as title.
show : bool
Show figures if True
+ block : bool
+ Whether to halt program execution until the figure is closed.
+ Useful for setting bad channels on the fly (click on line).
Returns
-------
@@ -1048,20 +1082,56 @@ class Raw(ProjMixin):
The arrow keys (up/down/left/right) can typically be used to navigate
between channels and time ranges, but this depends on the backend
matplotlib is configured to use (e.g., mpl.use('TkAgg') should work).
+ To mark or un-mark a channel as bad, click on the rather flat segments
+ of a channel's time series. The changes will be reflected immediately
+ in the raw object's ``raw.info['bads']`` entry.
"""
return plot_raw(raw, events, duration, start, n_channels, bgcolor,
color, bad_color, event_color, scalings, remove_dc,
- order, show_options, title, show)
-
- @deprecated('time_to_index is deprecated please use time_as_index instead.'
- ' Will be removed in v0.7.')
- def time_to_index(self, *args):
- """Convert time to indices"""
- indices = []
- for time in args:
- ind = int(time * self.info['sfreq'])
- indices.append(ind)
- return indices
+ order, show_options, title, show, block)
+
+ @verbose
+ def plot_psds(self, tmin=0.0, tmax=60.0, fmin=0, fmax=np.inf,
+ proj=False, n_fft=2048, picks=None, ax=None, color='black',
+ area_mode='std', area_alpha=0.33, n_jobs=1, verbose=None):
+ """Plot the power spectral density across channels
+
+ Parameters
+ ----------
+ tmin : float
+ Start time for calculations.
+ tmax : float
+ End time for calculations.
+ fmin : float
+ Start frequency to consider.
+ fmax : float
+ End frequency to consider.
+ proj : bool
+ Apply projection.
+ n_fft : int
+ Number of points to use in Welch FFT calculations.
+ picks : list | None
+ List of channels to use. Cannot be None if `ax` is supplied. If
+ both `picks` and `ax` are None, separate subplots will be created
+ for each standard channel type (`mag`, `grad`, and `eeg`).
+ ax : instance of matplotlib Axes | None
+ Axes to plot into. If None, axes will be created.
+ color : str | tuple
+ A matplotlib-compatible color to use.
+ area_mode : str | None
+ How to plot area. If 'std', the mean +/- 1 STD (across channels)
+ will be plotted. If 'range', the min and max (across channels)
+ will be plotted. Bad channels will be excluded from these
+ calculations. If None, no area will be plotted.
+ area_alpha : float
+ Alpha for the area.
+ n_jobs : int
+ Number of jobs to run in parallel.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+ return plot_raw_psds(self, tmin, tmax, fmin, fmax, proj, n_fft, picks,
+ ax, color, area_mode, area_alpha, n_jobs)
def time_as_index(self, times, use_first_samp=False):
"""Convert time to indices
@@ -1150,7 +1220,8 @@ class Raw(ProjMixin):
else:
stop = min(self.n_times - 1, self.time_as_index(tstop)[0])
tslice = slice(start, stop + 1)
- picks = pick_types(self.info, meg=True, eeg=True, exclude='bads')
+ picks = pick_types(self.info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
# ensure we don't get a view of data
if len(picks) == 1:
return 1.0, 1.0
@@ -1381,9 +1452,10 @@ class Raw(ProjMixin):
df.insert(0, 'time', times * scale_time)
if use_time_index is True:
+ if 'time' in df:
+ df['time'] = df['time'].astype(np.int64)
with warnings.catch_warnings(True):
df.set_index('time', inplace=True)
- df.index = df.index.astype(int)
return df
@@ -1621,6 +1693,60 @@ class Raw(ProjMixin):
return "<Raw | %s>" % s
+def set_eeg_reference(raw, ref_channels, copy=True):
+ """Rereference eeg channels to new reference channel(s).
+
+ If multiple reference channels are specified, they will be averaged.
+
+ Parameters
+ ----------
+ raw : instance of Raw
+ Instance of Raw with eeg channels and reference channel(s).
+
+ ref_channels : list of str
+ The name(s) of the reference channel(s).
+
+ copy : bool
+ Specifies whether instance of Raw will be copied or modified in place.
+
+ Returns
+ -------
+ raw : instance of Raw
+ Instance of Raw with eeg channels rereferenced.
+
+ ref_data : array
+ Array of reference data subtracted from eeg channels.
+ """
+ # Check to see that raw data is preloaded
+ if not raw._preloaded:
+ raise RuntimeError('Raw data needs to be preloaded. Use '
+ 'preload=True (or string) in the constructor.')
+ # Make sure that reference channels are loaded as list of string
+ if not isinstance(ref_channels, list):
+ raise IOError('Reference channel(s) must be a list of string. '
+ 'If using a single reference channel, enter as '
+ 'a list with one element.')
+ # Find the indices to the reference electrodes
+ ref_idx = [raw.ch_names.index(c) for c in ref_channels]
+
+ # Get the reference array
+ ref_data = raw._data[ref_idx].mean(0)
+
+ # Get the indices to the eeg channels using the pick_types function
+ eeg_idx = pick_types(raw.info, exclude="bads", eeg=True, meg=False,
+ ref_meg=False)
+
+ # Copy raw data or modify raw data in place
+ if copy: # copy data
+ raw = raw.copy()
+
+ # Rereference the eeg channels
+ raw._data[eeg_idx] -= ref_data
+
+ # Return rereferenced data and reference array
+ return raw, ref_data
+
+
def _allocate_data(data, data_buffer, data_shape, dtype):
if data is None:
# if not already done, allocate array with right type
@@ -1691,9 +1817,9 @@ class _RawShell():
###############################################################################
# Writing
-from .write import start_file, end_file, start_block, end_block, \
- write_dau_pack16, write_float, write_double, \
- write_complex64, write_complex128, write_int, write_id
+from .write import (start_file, end_file, start_block, end_block,
+ write_dau_pack16, write_float, write_double,
+ write_complex64, write_complex128, write_int, write_id)
def start_writing_raw(name, info, sel=None, data_type=FIFF.FIFFT_FLOAT,
@@ -1743,7 +1869,7 @@ def start_writing_raw(name, info, sel=None, data_type=FIFF.FIFFT_FLOAT,
comps = copy.deepcopy(info['comps'])
for c in comps:
row_idx = [k for k, n in enumerate(c['data']['row_names'])
- if n in ch_names]
+ if n in ch_names]
row_names = [c['data']['row_names'][i] for i in row_idx]
rowcals = c['rowcals'][row_idx]
c['rowcals'] = rowcals
@@ -1888,3 +2014,89 @@ def concatenate_raws(raws, preload=None):
"""
raws[0].append(raws[1:], preload)
return raws[0]
+
+
+def get_chpi_positions(raw, t_step=None):
+ """Extract head positions
+
+ Note that the raw instance must have CHPI channels recorded.
+
+ Parameters
+ ----------
+ raw : instance of Raw | str
+ Raw instance to extract the head positions from. Can also be a
+ path to a Maxfilter log file (str).
+ t_step : float | None
+ Sampling interval to use when converting data. If None, it will
+ be automatically determined. By default, a sampling interval of
+ 1 second is used if processing a raw data. If processing a
+ Maxfilter log file, this must be None because the log file
+ itself will determine the sampling interval.
+
+ Returns
+ -------
+ translation : array
+ A 2-dimensional array of head position vectors (n_time x 3).
+ rotation : array
+ A 3-dimensional array of rotation matrices (n_time x 3 x 3).
+ t : array
+ The time points associated with each position (n_time).
+
+ Notes
+ -----
+ The digitized HPI head frame y is related to the frame position X as:
+
+ Y = np.dot(rotation, X) + translation
+
+ Note that if a Maxfilter log file is being processed, the start time
+ may not use the same reference point as the rest of mne-python (i.e.,
+ it could be referenced relative to raw.first_samp or something else).
+ """
+ if isinstance(raw, Raw):
+ # for simplicity, we'll sample at 1 sec intervals like maxfilter
+ if t_step is None:
+ t_step = 1.0
+ if not np.isscalar(t_step):
+ raise TypeError('t_step must be a scalar or None')
+ picks = pick_types(raw.info, meg=False, ref_meg=False,
+ chpi=True, exclude=[])
+ if len(picks) == 0:
+ raise RuntimeError('raw file has no CHPI channels')
+ time_idx = raw.time_as_index(np.arange(0, raw.n_times
+ / raw.info['sfreq'], t_step))
+ data = [raw[picks, ti] for ti in time_idx]
+ t = np.array([d[1] for d in data])
+ data = np.array([d[0][:, 0] for d in data])
+ data = np.c_[t, data]
+ else:
+ if not isinstance(raw, basestring):
+ raise TypeError('raw must be an instance of fiff.Raw or string')
+ if not op.isfile(raw):
+ raise IOError('File "%s" does not exist' % raw)
+ if t_step is not None:
+ raise ValueError('t_step must be None if processing a log')
+ data = np.loadtxt(raw, skiprows=1) # first line is header, skip it
+ t = data[:, 0]
+ translation = data[:, 4:7].copy()
+ rotation = _quart_to_rot(data[:, 1:4])
+ return translation, rotation, t
+
+
+def _quart_to_rot(q):
+ """Helper to convert quarternions to rotations"""
+ q0 = np.sqrt(1 - np.sum(q[:, 0:3] ** 2, 1))
+ q1 = q[:, 0]
+ q2 = q[:, 1]
+ q3 = q[:, 2]
+ rotation = np.array((np.c_[(q0 ** 2 + q1 ** 2 - q2 ** 2 - q3 ** 2,
+ 2 * (q1 * q2 - q0 * q3),
+ 2 * (q1 * q3 + q0 * q2))],
+ np.c_[(2 * (q1 * q2 + q0 * q3),
+ q0 ** 2 + q2 ** 2 - q1 ** 2 - q3 ** 2,
+ 2 * (q2 * q3 - q0 * q1))],
+ np.c_[(2 * (q1 * q3 - q0 * q2),
+ 2 * (q2 * q3 + q0 * q1),
+ q0 ** 2 + q3 ** 2 - q1 ** 2 - q2 ** 2)]
+ ))
+ rotation = np.swapaxes(rotation, 0, 1).copy()
+ return rotation
diff --git a/mne/fiff/tag.py b/mne/fiff/tag.py
index 1039bbb..fb9f4a2 100644
--- a/mne/fiff/tag.py
+++ b/mne/fiff/tag.py
@@ -173,6 +173,15 @@ def _fromstring_rows(fid, tag_size, dtype=None, shape=None, rlims=None):
return out
+def _loc_to_trans(loc):
+ """Helper to convert loc vector to coil_trans"""
+ # deal with nasty OSX Anaconda bug by casting to float64
+ loc = loc.astype(np.float64)
+ coil_trans = np.concatenate([loc.reshape(4, 3).T[:, [1, 2, 3, 0]],
+ np.array([0, 0, 0, 1]).reshape(1, 4)])
+ return coil_trans
+
+
def read_tag(fid, pos=None, shape=None, rlims=None):
"""Read a Tag from a file at a given position
@@ -371,7 +380,7 @@ def read_tag(fid, pos=None, shape=None, rlims=None):
tag.data['ident'] = int(np.fromstring(fid.read(4),
dtype=">i4"))
tag.data['r'] = np.fromstring(fid.read(12), dtype=">f4")
- tag.data['coord_frame'] = 0
+ tag.data['coord_frame'] = FIFF.FIFFV_COORD_UNKNOWN
elif tag.type == FIFF.FIFFT_COORD_TRANS_STRUCT:
tag.data = dict()
tag.data['from'] = int(np.fromstring(fid.read(4), dtype=">i4"))
@@ -406,16 +415,16 @@ def read_tag(fid, pos=None, shape=None, rlims=None):
#
loc = tag.data['loc']
kind = tag.data['kind']
- if kind == FIFF.FIFFV_MEG_CH or kind == FIFF.FIFFV_REF_MEG_CH:
- tag.data['coil_trans'] = np.concatenate(
- [loc.reshape(4, 3).T[:, [1, 2, 3, 0]],
- np.array([0, 0, 0, 1]).reshape(1, 4)])
+ if kind in [FIFF.FIFFV_MEG_CH, FIFF.FIFFV_REF_MEG_CH]:
+ tag.data['coil_trans'] = _loc_to_trans(loc)
tag.data['coord_frame'] = FIFF.FIFFV_COORD_DEVICE
elif tag.data['kind'] == FIFF.FIFFV_EEG_CH:
+ # deal with nasty OSX Anaconda bug by casting to float64
+ loc = loc.astype(np.float64)
if linalg.norm(loc[3:6]) > 0.:
tag.data['eeg_loc'] = np.c_[loc[0:3], loc[3:6]]
else:
- tag.data['eeg_loc'] = loc[0:3]
+ tag.data['eeg_loc'] = loc[0:3][:, np.newaxis].copy()
tag.data['coord_frame'] = FIFF.FIFFV_COORD_HEAD
#
# Unit and exponent
diff --git a/mne/fiff/tests/data/fsaverage-fiducials.fif b/mne/fiff/tests/data/fsaverage-fiducials.fif
new file mode 100644
index 0000000..faaae97
Binary files /dev/null and b/mne/fiff/tests/data/fsaverage-fiducials.fif differ
diff --git a/mne/fiff/tests/data/sample-audvis-raw-trans.txt b/mne/fiff/tests/data/sample-audvis-raw-trans.txt
new file mode 100644
index 0000000..07b90de
--- /dev/null
+++ b/mne/fiff/tests/data/sample-audvis-raw-trans.txt
@@ -0,0 +1,4 @@
+0.999310 0.012759 0.034894 0.002070
+0.009985 0.812405 -0.583009 0.011302
+-0.035787 0.582954 0.811716 -0.027555
+0.000000 0.000000 0.000000 1.000000
diff --git a/mne/fiff/tests/data/test-lh.label b/mne/fiff/tests/data/test-lh.label
new file mode 100644
index 0000000..9f84c0d
--- /dev/null
+++ b/mne/fiff/tests/data/test-lh.label
@@ -0,0 +1,101 @@
+#Test lh
+99
+87 0.000000 0.000000 0.000000 1.000000
+121 0.000000 0.000000 0.000000 1.000000
+131 0.000000 0.000000 0.000000 1.000000
+198 0.000000 0.000000 0.000000 1.000000
+519 0.000000 0.000000 0.000000 1.000000
+674 0.000000 0.000000 0.000000 1.000000
+784 0.000000 0.000000 0.000000 1.000000
+987 0.000000 0.000000 0.000000 1.000000
+1296 0.000000 0.000000 0.000000 1.000000
+1351 0.000000 0.000000 0.000000 1.000000
+1415 0.000000 0.000000 0.000000 1.000000
+1457 0.000000 0.000000 0.000000 1.000000
+1865 0.000000 0.000000 0.000000 1.000000
+1891 0.000000 0.000000 0.000000 1.000000
+1908 0.000000 0.000000 0.000000 1.000000
+1926 0.000000 0.000000 0.000000 1.000000
+1929 0.000000 0.000000 0.000000 1.000000
+2020 0.000000 0.000000 0.000000 1.000000
+2030 0.000000 0.000000 0.000000 1.000000
+2354 0.000000 0.000000 0.000000 1.000000
+2369 0.000000 0.000000 0.000000 1.000000
+2466 0.000000 0.000000 0.000000 1.000000
+2489 0.000000 0.000000 0.000000 1.000000
+2562 0.000000 0.000000 0.000000 1.000000
+2660 0.000000 0.000000 0.000000 1.000000
+2884 0.000000 0.000000 0.000000 1.000000
+2943 0.000000 0.000000 0.000000 1.000000
+3143 0.000000 0.000000 0.000000 1.000000
+3182 0.000000 0.000000 0.000000 1.000000
+3233 0.000000 0.000000 0.000000 1.000000
+3469 0.000000 0.000000 0.000000 1.000000
+3505 0.000000 0.000000 0.000000 1.000000
+3603 0.000000 0.000000 0.000000 1.000000
+3734 0.000000 0.000000 0.000000 1.000000
+3818 0.000000 0.000000 0.000000 1.000000
+3931 0.000000 0.000000 0.000000 1.000000
+4099 0.000000 0.000000 0.000000 1.000000
+4135 0.000000 0.000000 0.000000 1.000000
+4244 0.000000 0.000000 0.000000 1.000000
+4312 0.000000 0.000000 0.000000 1.000000
+4474 0.000000 0.000000 0.000000 1.000000
+4615 0.000000 0.000000 0.000000 1.000000
+4742 0.000000 0.000000 0.000000 1.000000
+4753 0.000000 0.000000 0.000000 1.000000
+4856 0.000000 0.000000 0.000000 1.000000
+4883 0.000000 0.000000 0.000000 1.000000
+5067 0.000000 0.000000 0.000000 1.000000
+5103 0.000000 0.000000 0.000000 1.000000
+5244 0.000000 0.000000 0.000000 1.000000
+5264 0.000000 0.000000 0.000000 1.000000
+5389 0.000000 0.000000 0.000000 1.000000
+5426 0.000000 0.000000 0.000000 1.000000
+5457 0.000000 0.000000 0.000000 1.000000
+5497 0.000000 0.000000 0.000000 1.000000
+5688 0.000000 0.000000 0.000000 1.000000
+5704 0.000000 0.000000 0.000000 1.000000
+5834 0.000000 0.000000 0.000000 1.000000
+5948 0.000000 0.000000 0.000000 1.000000
+5981 0.000000 0.000000 0.000000 1.000000
+6114 0.000000 0.000000 0.000000 1.000000
+6409 0.000000 0.000000 0.000000 1.000000
+6656 0.000000 0.000000 0.000000 1.000000
+6718 0.000000 0.000000 0.000000 1.000000
+6736 0.000000 0.000000 0.000000 1.000000
+6742 0.000000 0.000000 0.000000 1.000000
+6755 0.000000 0.000000 0.000000 1.000000
+6757 0.000000 0.000000 0.000000 1.000000
+6779 0.000000 0.000000 0.000000 1.000000
+6905 0.000000 0.000000 0.000000 1.000000
+6943 0.000000 0.000000 0.000000 1.000000
+7051 0.000000 0.000000 0.000000 1.000000
+7070 0.000000 0.000000 0.000000 1.000000
+7087 0.000000 0.000000 0.000000 1.000000
+7089 0.000000 0.000000 0.000000 1.000000
+7096 0.000000 0.000000 0.000000 1.000000
+7275 0.000000 0.000000 0.000000 1.000000
+7437 0.000000 0.000000 0.000000 1.000000
+7764 0.000000 0.000000 0.000000 1.000000
+7816 0.000000 0.000000 0.000000 1.000000
+7949 0.000000 0.000000 0.000000 1.000000
+8009 0.000000 0.000000 0.000000 1.000000
+8380 0.000000 0.000000 0.000000 1.000000
+8397 0.000000 0.000000 0.000000 1.000000
+8484 0.000000 0.000000 0.000000 1.000000
+8773 0.000000 0.000000 0.000000 1.000000
+8836 0.000000 0.000000 0.000000 1.000000
+9081 0.000000 0.000000 0.000000 1.000000
+9300 0.000000 0.000000 0.000000 1.000000
+9340 0.000000 0.000000 0.000000 1.000000
+9519 0.000000 0.000000 0.000000 1.000000
+9667 0.000000 0.000000 0.000000 1.000000
+9813 0.000000 0.000000 0.000000 1.000000
+9858 0.000000 0.000000 0.000000 1.000000
+9889 0.000000 0.000000 0.000000 1.000000
+9937 0.000000 0.000000 0.000000 1.000000
+10097 0.000000 0.000000 0.000000 1.000000
+10106 0.000000 0.000000 0.000000 1.000000
+10179 0.000000 0.000000 0.000000 1.000000
+10219 0.000000 0.000000 0.000000 1.000000
diff --git a/mne/fiff/tests/data/test-rh.label b/mne/fiff/tests/data/test-rh.label
new file mode 100644
index 0000000..6991b91
--- /dev/null
+++ b/mne/fiff/tests/data/test-rh.label
@@ -0,0 +1,102 @@
+#Test rh
+100
+11 0.000000 0.000000 0.000000 1.000000
+29 0.000000 0.000000 0.000000 1.000000
+70 0.000000 0.000000 0.000000 1.000000
+73 0.000000 0.000000 0.000000 1.000000
+75 0.000000 0.000000 0.000000 1.000000
+92 0.000000 0.000000 0.000000 1.000000
+230 0.000000 0.000000 0.000000 1.000000
+264 0.000000 0.000000 0.000000 1.000000
+332 0.000000 0.000000 0.000000 1.000000
+492 0.000000 0.000000 0.000000 1.000000
+532 0.000000 0.000000 0.000000 1.000000
+565 0.000000 0.000000 0.000000 1.000000
+575 0.000000 0.000000 0.000000 1.000000
+820 0.000000 0.000000 0.000000 1.000000
+889 0.000000 0.000000 0.000000 1.000000
+1486 0.000000 0.000000 0.000000 1.000000
+1526 0.000000 0.000000 0.000000 1.000000
+1544 0.000000 0.000000 0.000000 1.000000
+1561 0.000000 0.000000 0.000000 1.000000
+1737 0.000000 0.000000 0.000000 1.000000
+1934 0.000000 0.000000 0.000000 1.000000
+2121 0.000000 0.000000 0.000000 1.000000
+2167 0.000000 0.000000 0.000000 1.000000
+2200 0.000000 0.000000 0.000000 1.000000
+2545 0.000000 0.000000 0.000000 1.000000
+2557 0.000000 0.000000 0.000000 1.000000
+2858 0.000000 0.000000 0.000000 1.000000
+2888 0.000000 0.000000 0.000000 1.000000
+2904 0.000000 0.000000 0.000000 1.000000
+3005 0.000000 0.000000 0.000000 1.000000
+3076 0.000000 0.000000 0.000000 1.000000
+3221 0.000000 0.000000 0.000000 1.000000
+3279 0.000000 0.000000 0.000000 1.000000
+3328 0.000000 0.000000 0.000000 1.000000
+3398 0.000000 0.000000 0.000000 1.000000
+3558 0.000000 0.000000 0.000000 1.000000
+3581 0.000000 0.000000 0.000000 1.000000
+3597 0.000000 0.000000 0.000000 1.000000
+3661 0.000000 0.000000 0.000000 1.000000
+3749 0.000000 0.000000 0.000000 1.000000
+3847 0.000000 0.000000 0.000000 1.000000
+3962 0.000000 0.000000 0.000000 1.000000
+4032 0.000000 0.000000 0.000000 1.000000
+4053 0.000000 0.000000 0.000000 1.000000
+4312 0.000000 0.000000 0.000000 1.000000
+4324 0.000000 0.000000 0.000000 1.000000
+4516 0.000000 0.000000 0.000000 1.000000
+4625 0.000000 0.000000 0.000000 1.000000
+4808 0.000000 0.000000 0.000000 1.000000
+4834 0.000000 0.000000 0.000000 1.000000
+5099 0.000000 0.000000 0.000000 1.000000
+5207 0.000000 0.000000 0.000000 1.000000
+5269 0.000000 0.000000 0.000000 1.000000
+5372 0.000000 0.000000 0.000000 1.000000
+6031 0.000000 0.000000 0.000000 1.000000
+6065 0.000000 0.000000 0.000000 1.000000
+6392 0.000000 0.000000 0.000000 1.000000
+6901 0.000000 0.000000 0.000000 1.000000
+6945 0.000000 0.000000 0.000000 1.000000
+7205 0.000000 0.000000 0.000000 1.000000
+7248 0.000000 0.000000 0.000000 1.000000
+7283 0.000000 0.000000 0.000000 1.000000
+7380 0.000000 0.000000 0.000000 1.000000
+7559 0.000000 0.000000 0.000000 1.000000
+7642 0.000000 0.000000 0.000000 1.000000
+7683 0.000000 0.000000 0.000000 1.000000
+7687 0.000000 0.000000 0.000000 1.000000
+7840 0.000000 0.000000 0.000000 1.000000
+7936 0.000000 0.000000 0.000000 1.000000
+7939 0.000000 0.000000 0.000000 1.000000
+8042 0.000000 0.000000 0.000000 1.000000
+8339 0.000000 0.000000 0.000000 1.000000
+8352 0.000000 0.000000 0.000000 1.000000
+8427 0.000000 0.000000 0.000000 1.000000
+8491 0.000000 0.000000 0.000000 1.000000
+8496 0.000000 0.000000 0.000000 1.000000
+8524 0.000000 0.000000 0.000000 1.000000
+8578 0.000000 0.000000 0.000000 1.000000
+8797 0.000000 0.000000 0.000000 1.000000
+8810 0.000000 0.000000 0.000000 1.000000
+8829 0.000000 0.000000 0.000000 1.000000
+8903 0.000000 0.000000 0.000000 1.000000
+9062 0.000000 0.000000 0.000000 1.000000
+9081 0.000000 0.000000 0.000000 1.000000
+9164 0.000000 0.000000 0.000000 1.000000
+9165 0.000000 0.000000 0.000000 1.000000
+9225 0.000000 0.000000 0.000000 1.000000
+9226 0.000000 0.000000 0.000000 1.000000
+9322 0.000000 0.000000 0.000000 1.000000
+9532 0.000000 0.000000 0.000000 1.000000
+9633 0.000000 0.000000 0.000000 1.000000
+9659 0.000000 0.000000 0.000000 1.000000
+9700 0.000000 0.000000 0.000000 1.000000
+9789 0.000000 0.000000 0.000000 1.000000
+9831 0.000000 0.000000 0.000000 1.000000
+9851 0.000000 0.000000 0.000000 1.000000
+9891 0.000000 0.000000 0.000000 1.000000
+10055 0.000000 0.000000 0.000000 1.000000
+10065 0.000000 0.000000 0.000000 1.000000
+10082 0.000000 0.000000 0.000000 1.000000
diff --git a/mne/fiff/tests/data/test_chpi_raw_hp.txt b/mne/fiff/tests/data/test_chpi_raw_hp.txt
new file mode 100644
index 0000000..05c7555
--- /dev/null
+++ b/mne/fiff/tests/data/test_chpi_raw_hp.txt
@@ -0,0 +1,5 @@
+ Time q1 q2 q3 q4 q5 q6 g-value error velocity
+ 118.000 -0.00496 -0.04121 -0.00402 0.00159 -0.01443 0.04823 0.99928 0.00171 0.00002
+ 119.000 -0.00479 -0.04117 -0.00415 0.00158 -0.01441 0.04825 0.99928 0.00169 0.00004
+ 120.000 -0.00501 -0.04118 -0.00415 0.00159 -0.01443 0.04822 0.99928 0.00169 0.00004
+ 121.000 -0.00500 -0.04119 -0.00414 0.00159 -0.01443 0.04823 0.99928 0.00169 0.00000
diff --git a/mne/fiff/tests/data/test_chpi_raw_sss.fif b/mne/fiff/tests/data/test_chpi_raw_sss.fif
new file mode 100644
index 0000000..99aac1b
Binary files /dev/null and b/mne/fiff/tests/data/test_chpi_raw_sss.fif differ
diff --git a/mne/fiff/tests/test_compensator.py b/mne/fiff/tests/test_compensator.py
index 539e419..5a94431 100644
--- a/mne/fiff/tests/test_compensator.py
+++ b/mne/fiff/tests/test_compensator.py
@@ -13,6 +13,8 @@ ctf_comp_fname = op.join(base_dir, 'test_ctf_comp_raw.fif')
def test_compensation():
+ """Test compensation
+ """
raw = Raw(ctf_comp_fname, compensation=None)
comp1 = make_compensator(raw.info, 3, 1, exclude_comp_chs=False)
assert_true(comp1.shape == (340, 340))
diff --git a/mne/fiff/tests/test_evoked.py b/mne/fiff/tests/test_evoked.py
index 19efcc1..3f18c03 100644
--- a/mne/fiff/tests/test_evoked.py
+++ b/mne/fiff/tests/test_evoked.py
@@ -7,8 +7,8 @@ import os.path as op
from copy import deepcopy
import numpy as np
-from numpy.testing import assert_array_almost_equal, assert_equal,\
- assert_array_equal, assert_allclose
+from numpy.testing import (assert_array_almost_equal, assert_equal,
+ assert_array_equal, assert_allclose)
from nose.tools import assert_true, assert_raises
from mne.fiff import read_evoked, write_evoked, pick_types
diff --git a/mne/fiff/tests/test_meas_info.py b/mne/fiff/tests/test_meas_info.py
new file mode 100644
index 0000000..84b048e
--- /dev/null
+++ b/mne/fiff/tests/test_meas_info.py
@@ -0,0 +1,66 @@
+import os.path as op
+
+from nose.tools import assert_true, assert_equal, assert_raises
+from numpy.testing import assert_array_equal
+
+from mne import fiff, Epochs, read_events
+from mne.fiff import read_fiducials, write_fiducials, FIFF
+from mne.fiff.meas_info import Info
+from mne.utils import _TempDir
+
+base_dir = op.join(op.dirname(__file__), 'data')
+fiducials_fname = op.join(base_dir, 'fsaverage-fiducials.fif')
+raw_fname = op.join(base_dir, 'test_raw.fif')
+event_name = op.join(base_dir, 'test-eve.fif')
+evoked_nf_name = op.join(base_dir, 'test-nf-ave.fif')
+
+tempdir = _TempDir()
+
+
+def test_fiducials_io():
+ """Test fiducials i/o"""
+ pts, coord_frame = read_fiducials(fiducials_fname)
+ assert_equal(pts[0]['coord_frame'], FIFF.FIFFV_COORD_MRI)
+ assert_equal(pts[0]['ident'], FIFF.FIFFV_POINT_CARDINAL)
+
+ temp_fname = op.join(tempdir, 'test.fif')
+ write_fiducials(temp_fname, pts, coord_frame)
+ pts_1, coord_frame_1 = read_fiducials(temp_fname)
+ assert_equal(coord_frame, coord_frame_1)
+ for pt, pt_1 in zip(pts, pts_1):
+ assert_equal(pt['kind'], pt_1['kind'])
+ assert_equal(pt['ident'], pt_1['ident'])
+ assert_equal(pt['coord_frame'], pt_1['coord_frame'])
+ assert_array_equal(pt['r'], pt_1['r'])
+
+ # test safeguards
+ pts[0]['coord_frame'] += 1
+ assert_raises(ValueError, write_fiducials, temp_fname, pts, coord_frame)
+
+
+def test_info():
+ """Test info object"""
+ raw = fiff.Raw(raw_fname)
+ event_id, tmin, tmax = 1, -0.2, 0.5
+ events = read_events(event_name)
+ event_id = int(events[0, 2])
+ epochs = Epochs(raw, events[:1], event_id, tmin, tmax, picks=None,
+ baseline=(None, 0))
+
+ evoked = epochs.average()
+
+ events = read_events(event_name)
+
+ # Test subclassing was successful.
+ info = Info(a=7, b='aaaaa')
+ assert_true('a' in info)
+ assert_true('b' in info)
+ info[42] = 'foo'
+ assert_true(info[42] == 'foo')
+
+ # test info attribute in API objects
+ for obj in [raw, epochs, evoked]:
+ assert_true(isinstance(obj.info, Info))
+ info_str = '%s' % obj.info
+ assert_equal(len(info_str.split('\n')), (len(obj.info.keys()) + 2))
+ assert_true(all(k in info_str for k in obj.info.keys()))
diff --git a/mne/fiff/tests/test_raw.py b/mne/fiff/tests/test_raw.py
index 7042045..ad59f44 100644
--- a/mne/fiff/tests/test_raw.py
+++ b/mne/fiff/tests/test_raw.py
@@ -9,14 +9,17 @@ from copy import deepcopy
import warnings
import numpy as np
-from numpy.testing import assert_array_almost_equal, assert_array_equal, \
- assert_allclose
+from numpy.testing import (assert_array_almost_equal, assert_array_equal,
+ assert_allclose)
from nose.tools import assert_true, assert_raises, assert_equal
-from mne.fiff import Raw, pick_types, pick_channels, concatenate_raws, FIFF
+from mne.fiff import (Raw, pick_types, pick_channels, concatenate_raws, FIFF,
+ get_chpi_positions, set_eeg_reference)
from mne import concatenate_events, find_events
from mne.utils import _TempDir, requires_nitime, requires_pandas
+warnings.simplefilter('always') # enable b/c these tests throw warnings
+
base_dir = op.join(op.dirname(__file__), 'data')
fif_fname = op.join(base_dir, 'test_raw.fif')
fif_gz_fname = op.join(base_dir, 'test_raw.fif.gz')
@@ -25,10 +28,29 @@ ctf_comp_fname = op.join(base_dir, 'test_ctf_comp_raw.fif')
fif_bad_marked_fname = op.join(base_dir, 'test_withbads_raw.fif')
bad_file_works = op.join(base_dir, 'test_bads.txt')
bad_file_wrong = op.join(base_dir, 'test_wrong_bads.txt')
+hp_fname = op.join(base_dir, 'test_chpi_raw_hp.txt')
+hp_fif_fname = op.join(base_dir, 'test_chpi_raw_sss.fif')
tempdir = _TempDir()
+def test_get_chpi():
+ """Test CHPI position computation
+ """
+ trans0, rot0, _ = get_chpi_positions(hp_fname)
+ raw = Raw(hp_fif_fname)
+ out = get_chpi_positions(raw)
+ trans1, rot1, t1 = out
+ trans1 = trans1[2:]
+ rot1 = rot1[2:]
+ # these will not be exact because they don't use equiv. time points
+ assert_allclose(trans0, trans1, atol=1e-6, rtol=1e-1)
+ assert_allclose(rot0, rot1, atol=1e-6, rtol=1e-1)
+ # run through input checking
+ assert_raises(TypeError, get_chpi_positions, 1)
+ assert_raises(ValueError, get_chpi_positions, hp_fname, [1])
+
+
def test_copy_append():
"""Test raw copying and appending combinations
"""
@@ -76,18 +98,26 @@ def test_output_formats():
assert_true(raw2.orig_format == format)
+def _compare_combo(raw, new, times, n_times):
+ for ti in times: # let's do a subset of points for speed
+ orig = raw[:, ti % n_times][0]
+ # these are almost_equals because of possible dtype differences
+ assert_allclose(orig, new[:, ti][0])
+
+
def test_multiple_files():
"""Test loading multiple files simultaneously
"""
# split file
- raw = Raw(fif_fname, preload=True)
- split_size = 10. # in seconds
+ raw = Raw(fif_fname, preload=True).crop(0, 10)
+ split_size = 3. # in seconds
sfreq = raw.info['sfreq']
nsamp = (raw.last_samp - raw.first_samp)
tmins = np.round(np.arange(0., nsamp, split_size * sfreq))
tmaxs = np.concatenate((tmins[1:] - 1, [nsamp]))
tmaxs /= sfreq
tmins /= sfreq
+ assert_equal(raw.n_times, len(raw._times))
# going in reverse order so the last fname is the first file (need later)
raws = [None] * len(tmins)
@@ -114,59 +144,60 @@ def test_multiple_files():
assert_array_equal(events, events2)
# test various methods of combining files
- n_combos = 9
- raw_combos = [None] * n_combos
-
raw = Raw(fif_fname, preload=True)
- raw_combos[0] = Raw([fif_fname, fif_fname], preload=True)
- raw_combos[1] = Raw([fif_fname, fif_fname], preload=False)
- raw_combos[2] = Raw([fif_fname, fif_fname], preload='memmap8.dat')
+ n_times = len(raw._times)
+ # make sure that all our data match
+ times = range(0, 2 * n_times, 999)
+ # add potentially problematic points
+ times.extend([n_times - 1, n_times, 2 * n_times - 1])
+
+ raw_combo0 = Raw([fif_fname, fif_fname], preload=True)
+ _compare_combo(raw, raw_combo0, times, n_times)
+ raw_combo = Raw([fif_fname, fif_fname], preload=False)
+ _compare_combo(raw, raw_combo, times, n_times)
+ raw_combo = Raw([fif_fname, fif_fname], preload='memmap8.dat')
+ _compare_combo(raw, raw_combo, times, n_times)
assert_raises(ValueError, Raw, [fif_fname, ctf_fname])
assert_raises(ValueError, Raw, [fif_fname, fif_bad_marked_fname])
- n_times = len(raw._times)
- assert_true(raw[:, :][0].shape[1] * 2 == raw_combos[0][:, :][0].shape[1])
- assert_true(raw_combos[0][:, :][0].shape[1] == len(raw_combos[0]._times))
+ assert_true(raw[:, :][0].shape[1] * 2 == raw_combo0[:, :][0].shape[1])
+ assert_true(raw_combo0[:, :][0].shape[1] == len(raw_combo0._times))
# with all data preloaded, result should be preloaded
- raw_combos[3] = Raw(fif_fname, preload=True)
- raw_combos[3].append(Raw(fif_fname, preload=True))
- assert_true(raw_combos[0]._preloaded == True)
- assert_true(len(raw_combos[3]._times) == raw_combos[3]._data.shape[1])
+ raw_combo = Raw(fif_fname, preload=True)
+ raw_combo.append(Raw(fif_fname, preload=True))
+ assert_true(raw_combo._preloaded is True)
+ assert_true(len(raw_combo._times) == raw_combo._data.shape[1])
+ _compare_combo(raw, raw_combo, times, n_times)
# with any data not preloaded, don't set result as preloaded
- raw_combos[4] = concatenate_raws([Raw(fif_fname, preload=True),
- Raw(fif_fname, preload=False)])
- assert_true(raw_combos[1]._preloaded == False)
- assert_array_equal(find_events(raw_combos[4], stim_channel='STI 014'),
- find_events(raw_combos[0], stim_channel='STI 014'))
+ raw_combo = concatenate_raws([Raw(fif_fname, preload=True),
+ Raw(fif_fname, preload=False)])
+ assert_true(raw_combo._preloaded is False)
+ assert_array_equal(find_events(raw_combo, stim_channel='STI 014'),
+ find_events(raw_combo0, stim_channel='STI 014'))
+ _compare_combo(raw, raw_combo, times, n_times)
# user should be able to force data to be preloaded upon concat
- raw_combos[5] = concatenate_raws([Raw(fif_fname, preload=False),
- Raw(fif_fname, preload=True)],
- preload=True)
- assert_true(raw_combos[2]._preloaded == True)
-
- raw_combos[6] = concatenate_raws([Raw(fif_fname, preload=False),
- Raw(fif_fname, preload=True)],
- preload='memmap3.dat')
-
- raw_combos[7] = concatenate_raws([Raw(fif_fname, preload=True),
- Raw(fif_fname, preload=True)],
- preload='memmap4.dat')
-
- raw_combos[8] = concatenate_raws([Raw(fif_fname, preload=False),
- Raw(fif_fname, preload=False)],
- preload='memmap5.dat')
-
- # make sure that all our data match
- times = range(0, 2 * n_times, 999)
- # add potentially problematic points
- times.extend([n_times - 1, n_times, 2 * n_times - 1])
- for ti in times: # let's do a subset of points for speed
- orig = raw[:, ti % n_times][0]
- for raw_combo in raw_combos:
- # these are almost_equals because of possible dtype differences
- assert_allclose(orig, raw_combo[:, ti][0])
+ raw_combo = concatenate_raws([Raw(fif_fname, preload=False),
+ Raw(fif_fname, preload=True)],
+ preload=True)
+ assert_true(raw_combo._preloaded is True)
+ _compare_combo(raw, raw_combo, times, n_times)
+
+ raw_combo = concatenate_raws([Raw(fif_fname, preload=False),
+ Raw(fif_fname, preload=True)],
+ preload='memmap3.dat')
+ _compare_combo(raw, raw_combo, times, n_times)
+
+ raw_combo = concatenate_raws([Raw(fif_fname, preload=True),
+ Raw(fif_fname, preload=True)],
+ preload='memmap4.dat')
+ _compare_combo(raw, raw_combo, times, n_times)
+
+ raw_combo = concatenate_raws([Raw(fif_fname, preload=False),
+ Raw(fif_fname, preload=False)],
+ preload='memmap5.dat')
+ _compare_combo(raw, raw_combo, times, n_times)
# verify that combining raws with different projectors throws an exception
raw.add_proj([], remove_existing=True)
@@ -178,7 +209,7 @@ def test_multiple_files():
last_samps = [raw.last_samp, raw.last_samp]
first_samps = [raw.first_samp, raw.first_samp]
events = concatenate_events(events, first_samps, last_samps)
- events2 = find_events(raw_combos[0], stim_channel='STI 014')
+ events2 = find_events(raw_combo0, stim_channel='STI 014')
assert_array_equal(events, events2)
# check out the len method
@@ -339,8 +370,8 @@ def test_io_complex():
with warnings.catch_warnings(record=True) as w:
raw_cp.save(op.join(tempdir, 'raw.fif'), picks, tmin=0, tmax=5,
overwrite=True)
- # warning only gets thrown on first instance
- assert_equal(len(w), 1 if di == 0 else 0)
+ # warning gets thrown on every instance b/c simplifilter('always')
+ assert_equal(len(w), 1)
raw2 = Raw(op.join(tempdir, 'raw.fif'))
raw2_data, _ = raw2[picks, :]
@@ -458,7 +489,7 @@ def test_preload_modify():
def test_filter():
""" Test filtering (FIR and IIR) and Raw.apply_function interface """
- raw = Raw(fif_fname, preload=True).crop(0, 10, False)
+ raw = Raw(fif_fname, preload=True).crop(0, 7, False)
sig_dec = 11
sig_dec_notch = 12
sig_dec_notch_fit = 12
@@ -509,7 +540,7 @@ def test_filter():
# do a very simple check on line filtering
raw_bs = raw.copy()
- with warnings.catch_warnings(True) as w:
+ with warnings.catch_warnings(True) as _:
raw_bs.filter(60.0 + 0.5, 60.0 - 0.5, picks=picks, n_jobs=2)
data_bs, _ = raw_bs[picks, :]
raw_notch = raw.copy()
@@ -529,7 +560,7 @@ def test_crop():
"""Test cropping raw files
"""
# split a concatenated file to test a difficult case
- raw = Raw([fif_fname, fif_fname], preload=True)
+ raw = Raw([fif_fname, fif_fname], preload=False)
split_size = 10. # in seconds
sfreq = raw.info['sfreq']
nsamp = (raw.last_samp - raw.first_samp + 1)
@@ -543,7 +574,7 @@ def test_crop():
raws = [None] * len(tmins)
for ri, (tmin, tmax) in enumerate(zip(tmins, tmaxs)):
raws[ri] = raw.crop(tmin, tmax, True)
- all_raw_2 = concatenate_raws(raws, preload=True)
+ all_raw_2 = concatenate_raws(raws, preload=False)
assert_true(raw.first_samp == all_raw_2.first_samp)
assert_true(raw.last_samp == all_raw_2.last_samp)
assert_array_equal(raw[:, :][0], all_raw_2[:, :][0])
@@ -559,7 +590,7 @@ def test_crop():
raws[ri] = raw.copy()
raws[ri].crop(tmin, tmax, False)
# test concatenation of split file
- all_raw_1 = concatenate_raws(raws, preload=True)
+ all_raw_1 = concatenate_raws(raws, preload=False)
all_raw_2 = raw.crop(0, None, True)
for ar in [all_raw_1, all_raw_2]:
@@ -575,6 +606,7 @@ def test_resample():
sfreq = raw.info['sfreq']
# test parallel on upsample
raw_resamp.resample(sfreq * 2, n_jobs=2)
+ assert_true(raw_resamp.n_times == len(raw_resamp._times))
raw_resamp.save(op.join(tempdir, 'raw_resamp.fif'))
raw_resamp = Raw(op.join(tempdir, 'raw_resamp.fif'), preload=True)
assert_true(sfreq == raw_resamp.info['sfreq'] / 2)
@@ -749,6 +781,8 @@ def test_with_statement():
def test_compensation_raw():
+ """Test Raw compensation
+ """
raw1 = Raw(ctf_comp_fname, compensation=None)
assert_true(raw1.comp is None)
data1, times1 = raw1[:, :]
@@ -782,3 +816,35 @@ def test_compensation_raw():
data5, times5 = raw5[:, :]
assert_array_equal(times1, times5)
assert_allclose(data1, data5, rtol=1e-12, atol=1e-22)
+
+
+def test_set_eeg_reference():
+ """ Test rereference eeg data"""
+ raw = Raw(fif_fname, preload=True)
+
+ # Rereference raw data by creating a copy of original data
+ reref, ref_data = set_eeg_reference(raw, ['EEG 001', 'EEG 002'], copy=True)
+
+ # Separate EEG channels from other channel types
+ picks_eeg = pick_types(raw.info, meg=False, eeg=True, exclude='bads')
+ picks_other = pick_types(raw.info, meg=True, eeg=False, eog=True,
+ stim=True, exclude='bads')
+
+ # Get the raw EEG data and other channel data
+ raw_eeg_data = raw[picks_eeg][0]
+ raw_other_data = raw[picks_other][0]
+
+ # Get the rereferenced EEG data and channel other
+ reref_eeg_data = reref[picks_eeg][0]
+ unref_eeg_data = reref_eeg_data + ref_data
+ # Undo rereferencing of EEG channels
+ reref_other_data = reref[picks_other][0]
+
+ # Check that both EEG data and other data is the same
+ assert_array_equal(raw_eeg_data, unref_eeg_data)
+ assert_array_equal(raw_other_data, reref_other_data)
+
+ # Test that data is modified in place when copy=False
+ reref, ref_data = set_eeg_reference(raw, ['EEG 001', 'EEG 002'],
+ copy=False)
+ assert_true(raw is reref)
diff --git a/mne/fiff/tree.py b/mne/fiff/tree.py
index 3132342..8f65e3e 100644
--- a/mne/fiff/tree.py
+++ b/mne/fiff/tree.py
@@ -3,11 +3,8 @@
#
# License: BSD (3-clause)
-import logging
-logger = logging.getLogger('mne')
-
from .tag import read_tag
-from .. import verbose
+from ..utils import logger, verbose
def dir_tree_find(tree, kind):
diff --git a/mne/fiff/write.py b/mne/fiff/write.py
index 77d58a2..bb9be8c 100644
--- a/mne/fiff/write.py
+++ b/mne/fiff/write.py
@@ -8,10 +8,13 @@ import numpy as np
from scipy import linalg
import os.path as op
import gzip
-import logging
-logger = logging.getLogger('mne')
+import sys
+import os
+import re
+import uuid
from .constants import FIFF
+from ..utils import logger
def _write(fid, data, kind, data_size, FIFFT_TYPE, dtype):
@@ -142,15 +145,26 @@ def write_int_matrix(fid, kind, mat):
fid.write(np.array(dims, dtype='>i4').tostring())
+def get_machid():
+ """Get (mostly) unique machine ID
+
+ Returns
+ -------
+ ids : array (length 2, int32)
+ The machine identifier used in MNE.
+ """
+ mac = re.findall('..', '%012x' % uuid.getnode())
+ mac += ['00', '00'] # add two more fields
+
+ # Convert to integer in reverse-order (for some reason)
+ mac = ''.join([h.decode('hex') for h in mac[::-1]])
+ ids = np.flipud(np.fromstring(mac, np.int32, count=2))
+ return ids
+
+
def write_id(fid, kind, id_=None):
"""Writes fiff id"""
-
- if id_ is None:
- id_ = dict()
- id_['version'] = (1 << 16) | 2
- id_['machid'] = 65536 * np.random.rand(2) # Machine id (andom for now)
- id_['secs'] = time.time()
- id_['usecs'] = 0 # Do not know how we could get this XXX
+ id_ = _generate_meas_id() if id_ is None else id_
FIFFT_ID_STRUCT = 31
FIFFV_NEXT_SEQ = 0
@@ -352,3 +366,13 @@ def write_float_sparse_rcs(fid, kind, mat):
dims = [nnzm, mat.shape[0], mat.shape[1], 2]
fid.write(np.array(dims, dtype='>i4').tostring())
+
+
+def _generate_meas_id():
+ """Helper to generate a new meas_id dict"""
+ id_ = dict()
+ id_['version'] = (1 << 16) | 2
+ id_['machid'] = get_machid()
+ id_['secs'] = time.time()
+ id_['usecs'] = 0 # Do not know how we could get this XXX
+ return id_
diff --git a/mne/filter.py b/mne/filter.py
index 91d8752..70adb9a 100644
--- a/mne/filter.py
+++ b/mne/filter.py
@@ -7,15 +7,12 @@ from scipy.signal import freqz, iirdesign, iirfilter, filter_dict, get_window
from scipy import signal, stats
from copy import deepcopy
-import logging
-logger = logging.getLogger('mne')
-
from .fixes import firwin2, filtfilt # back port for old scipy
from .time_frequency.multitaper import dpss_windows, _mt_spectra
-from . import verbose
from .parallel import parallel_func
-from .cuda import setup_cuda_fft_multiply_repeated, fft_multiply_repeated, \
- setup_cuda_fft_resample, fft_resample, _smart_pad
+from .cuda import (setup_cuda_fft_multiply_repeated, fft_multiply_repeated,
+ setup_cuda_fft_resample, fft_resample, _smart_pad)
+from .utils import logger, verbose, sum_squared
def is_power2(num):
@@ -584,6 +581,9 @@ def band_pass_filter(x, Fs, Fp1, Fp2, filter_length='10s',
Fp2 = float(Fp2)
Fs1 = Fp1 - l_trans_bandwidth
Fs2 = Fp2 + h_trans_bandwidth
+ if Fs2 > Fs / 2:
+ raise ValueError('Effective band-stop frequency (%s) is too high '
+ '(maximum based on Nyquist is %s)' % (Fs2, Fs / 2.))
if Fs1 <= 0:
raise ValueError('Filter specification invalid: Lower stop frequency '
@@ -785,6 +785,10 @@ def low_pass_filter(x, Fs, Fp, filter_length='10s', trans_bandwidth=0.5,
Fs = float(Fs)
Fp = float(Fp)
Fstop = Fp + trans_bandwidth
+ if Fstop > Fs / 2.:
+ raise ValueError('Effective stop frequency (%s) is too high '
+ '(maximum based on Nyquist is %s)' % (Fstop, Fs / 2.))
+
if method == 'fft':
freq = [0, Fp, Fstop, Fs / 2]
gain = [1, 1, 0, 0]
@@ -984,8 +988,8 @@ def notch_filter(x, Fs, freqs, filter_length='10s', notch_widths=None,
if freqs is not None:
freqs = np.atleast_1d(freqs)
elif method != 'spectrum_fit':
- raise ValueError('freqs=None can only be used with method '
- 'spectrum_fit')
+ raise ValueError('freqs=None can only be used with method '
+ 'spectrum_fit')
# Only have to deal with notch_widths for non-autodetect
if freqs is not None:
@@ -1079,7 +1083,9 @@ def _mt_spectrum_remove(x, sfreq, line_freqs, notch_widths,
# compute dpss windows
n_tapers_max = int(2 * half_nbw)
window_fun, eigvals = dpss_windows(n_times, half_nbw, n_tapers_max,
- low_bias=False, interp_from=min(n_times, dpss_n_times_max))
+ low_bias=False,
+ interp_from=min(n_times,
+ dpss_n_times_max))
# drop the even tapers
n_tapers = len(window_fun)
@@ -1091,7 +1097,7 @@ def _mt_spectrum_remove(x, sfreq, line_freqs, notch_widths,
H0 = np.sum(tapers_use, axis=1)
# sum of squares across tapers (1, )
- H0_sq = np.sum(H0 ** 2)
+ H0_sq = sum_squared(H0)
# make "time" vector
rads = 2 * np.pi * (np.arange(n_times) / float(sfreq))
@@ -1267,7 +1273,7 @@ def detrend(x, order=1, axis=-1):
--------
As in scipy.signal.detrend:
>>> randgen = np.random.RandomState(9)
- >>> npoints = 1e3
+ >>> npoints = int(1e3)
>>> noise = randgen.randn(npoints)
>>> x = 3 + 2*np.linspace(0, 1, npoints) + noise
>>> (detrend(x) - noise).max() < 0.01
diff --git a/mne/fixes.py b/mne/fixes.py
index 6f9068e..1ab35d0 100644
--- a/mne/fixes.py
+++ b/mne/fixes.py
@@ -22,6 +22,8 @@ from math import ceil, log
from numpy.fft import irfft
from scipy.signal import filtfilt as sp_filtfilt
from distutils.version import LooseVersion
+from functools import partial
+import copy_reg
try:
Counter = collections.Counter
@@ -519,3 +521,27 @@ if LooseVersion(np.__version__) > '1.7.1':
from numpy.linalg import matrix_rank
else:
matrix_rank = _matrix_rank
+
+
+def _reconstruct_partial(func, args, kwargs):
+ """Helper to pickle partial functions"""
+ return partial(func, *args, **(kwargs or {}))
+
+
+def _reduce_partial(p):
+ """Helper to pickle partial functions"""
+ return _reconstruct_partial, (p.func, p.args, p.keywords)
+
+# This adds pickling functionality to older Python 2.6
+# Please always import partial from here.
+copy_reg.pickle(partial, _reduce_partial)
+
+
+def normalize_colors(vmin, vmax, clip=False):
+ """Helper to handle matplotlib API"""
+ import matplotlib.pyplot as plt
+ if 'Normalize' in vars(plt):
+ return plt.Normalize(vmin, vmax, clip=clip)
+ else:
+ return plt.normalize(vmin, vmax, clip=clip)
+
diff --git a/mne/forward/__init__.py b/mne/forward/__init__.py
new file mode 100644
index 0000000..1616053
--- /dev/null
+++ b/mne/forward/__init__.py
@@ -0,0 +1,12 @@
+from .forward import (read_forward_solution, write_forward_solution,
+ is_fixed_orient, read_forward_meas_info,
+ write_forward_meas_info,
+ compute_orient_prior, compute_depth_prior,
+ apply_forward, apply_forward_raw,
+ restrict_forward_to_stc, restrict_forward_to_label,
+ do_forward_solution, average_forward_solutions,
+ _restrict_gain_matrix, _stc_src_sel,
+ _fill_measurement_info, _apply_forward,
+ _subject_from_forward, convert_forward_solution,
+ _to_fixed_ori, prepare_bem_model)
+from ._make_forward import make_forward_solution
diff --git a/mne/forward/_compute_forward.py b/mne/forward/_compute_forward.py
new file mode 100644
index 0000000..67b1e37
--- /dev/null
+++ b/mne/forward/_compute_forward.py
@@ -0,0 +1,346 @@
+# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
+# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Eric Larson <larsoner at uw.edu>
+#
+# License: BSD (3-clause)
+
+import numpy as np
+from copy import deepcopy
+
+from ..surface import (fast_cross_3d, _find_nearest_tri_pt, _get_tri_supp_geom,
+ _triangle_coords)
+from ..fiff.constants import FIFF
+from ..transforms import apply_trans
+from ..utils import logger
+from ..parallel import parallel_func
+from ..fiff.compensator import get_current_comp, make_compensator
+from ..fiff.pick import pick_types
+
+
+##############################################################################
+# COIL SPECIFICATION
+
+def _dup_coil_set(coils, coord_frame, t):
+ """Make a duplicate"""
+ if t is not None and coord_frame != t['from']:
+ raise RuntimeError('transformation frame does not match the coil set')
+ coils = deepcopy(coils)
+ if t is not None:
+ coord_frame = t['to']
+ for coil in coils:
+ coil['r0'] = apply_trans(t['trans'], coil['r0'])
+ coil['ex'] = apply_trans(t['trans'], coil['ex'], False)
+ coil['ey'] = apply_trans(t['trans'], coil['ey'], False)
+ coil['ez'] = apply_trans(t['trans'], coil['ez'], False)
+ coil['rmag'] = apply_trans(t['trans'], coil['rmag'])
+ coil['cosmag'] = apply_trans(t['trans'], coil['cosmag'], False)
+ coil['coord_frame'] = t['to']
+ return coils, coord_frame
+
+
+def _check_coil_frame(coils, coord_frame, bem):
+ """Check to make sure the coils are in the correct coordinate frame"""
+ if coord_frame != FIFF.FIFFV_COORD_MRI:
+ if coord_frame == FIFF.FIFFV_COORD_HEAD:
+ # Make a transformed duplicate
+ coils, coord_Frame = _dup_coil_set(coils, coord_frame,
+ bem['head_mri_t'])
+ else:
+ raise RuntimeError('Bad coil coordinate frame %d' % coord_frame)
+ return coils, coord_frame
+
+
+def _bem_lin_field_coeffs_simple(dest, normal, tri_rr, tri_nn, tri_area):
+ """Simple version..."""
+ out = np.zeros((3, len(dest)))
+ for rr, o in zip(tri_rr, out):
+ diff = dest - rr
+ dl = np.sum(diff * diff, axis=1)
+ x = fast_cross_3d(diff, tri_nn[np.newaxis, :])
+ o[:] = tri_area * np.sum(x * normal, axis=1) / (3.0 * dl * np.sqrt(dl))
+ return out
+
+
+def _lin_field_coeff(s, mult, rmags, cosmags, ws, lims, func, n_jobs):
+ """Use the linear field approximation to get field coefficients"""
+ parallel, p_fun, _ = parallel_func(_do_lin_field_coeff, n_jobs)
+ nas = np.array_split
+ coeffs = parallel(p_fun(s['rr'], t, tn, ta, rmags, cosmags, ws, lims, func)
+ for t, tn, ta in zip(nas(s['tris'], n_jobs),
+ nas(s['tri_nn'], n_jobs),
+ nas(s['tri_area'], n_jobs)))
+ return mult * np.sum(coeffs, axis=0)
+
+
+def _do_lin_field_coeff(rr, t, tn, ta, rmags, cosmags, ws, lims, func):
+ """Actually get field coefficients (parallel-friendly)"""
+ coeff = np.zeros((len(lims) - 1, len(rr)))
+ for tri, tri_nn, tri_area in zip(t, tn, ta):
+ # Accumulate the coefficients for each triangle node
+ # and add to the corresponding coefficient matrix
+ tri_rr = rr[tri]
+
+ # The following is equivalent to:
+ #for j, coil in enumerate(coils['coils']):
+ # x = func(coil['rmag'], coil['cosmag'],
+ # tri_rr, tri_nn, tri_area)
+ # res = np.sum(coil['w'][np.newaxis, :] * x, axis=1)
+ # coeff[j][tri + off] += mult * res
+
+ xx = func(rmags, cosmags, tri_rr, tri_nn, tri_area)
+ yy = np.c_[np.zeros((3, 1)), np.cumsum(xx * ws, axis=1)]
+ zz = np.diff(yy[:, lims], axis=1)
+ coeff[:, tri] += zz.T
+ return coeff
+
+
+def _bem_specify_coils(bem, coils, coord_frame, n_jobs):
+ """Set up for computing the solution at a set of coils"""
+ # Compute the weighting factors to obtain the magnetic field
+ # in the linear potential approximation
+ coils, coord_frame = _check_coil_frame(coils, coord_frame, bem)
+
+ # leaving this in in case we want to easily add in the future
+ #if method != 'simple': # in ['ferguson', 'urankar']:
+ # raise NotImplementedError
+ #else:
+ func = _bem_lin_field_coeffs_simple
+
+ # Process each of the surfaces
+ rmags = np.concatenate([coil['rmag'] for coil in coils])
+ cosmags = np.concatenate([coil['cosmag'] for coil in coils])
+ lims = np.cumsum(np.r_[0, [len(coil['rmag']) for coil in coils]])
+ ws = np.concatenate([coil['w'] for coil in coils])
+
+ lens = np.cumsum(np.r_[0, [len(s['rr']) for s in bem['surfs']]])
+ coeff = np.empty((len(lims) - 1, lens[-1]))
+ for o1, o2, surf, mult in zip(lens[:-1], lens[1:],
+ bem['surfs'], bem['field_mult']):
+ coeff[:, o1:o2] = _lin_field_coeff(surf, mult, rmags, cosmags,
+ ws, lims, func, n_jobs)
+ # put through the bem
+ sol = np.dot(coeff, bem['solution'])
+ return sol
+
+
+def _bem_specify_els(bem, els):
+ """Set up for computing the solution at a set of electrodes"""
+ sol = np.zeros((len(els), bem['solution'].shape[1]))
+ # Go through all coils
+ scalp = bem['surfs'][0]
+ scalp['geom'] = _get_tri_supp_geom(scalp['tris'], scalp['rr'])
+ inds = np.arange(len(scalp['tris']))
+
+ # In principle this could be parallelized, but pickling overhead is huge
+ # (makes it slower than non-parallel)
+ for k, el in enumerate(els):
+ # Go through all 'integration points'
+ el_r = apply_trans(bem['head_mri_t']['trans'], el['rmag'])
+ for elw, r in zip(el['w'], el_r):
+ best = _find_nearest_tri_pt(inds, r, scalp['geom'], True)[2]
+ # Calculate a linear interpolation between the vertex values
+ tri = scalp['tris'][best]
+ x, y, z = _triangle_coords(r, scalp['geom'], best)
+ w = elw * np.array([(1.0 - x - y), x, y])
+ amt = np.dot(w, bem['solution'][tri])
+ sol[k] += amt
+ return sol
+
+
+#############################################################################
+# FORWARD COMPUTATION
+
+def _make_ctf_comp_coils(info, coils):
+ """Get the correct compensator for CTF coils"""
+ # adapted from mne_make_ctf_comp() from mne_ctf_comp.c
+ logger.info('Setting up compensation data...')
+ comp_num = get_current_comp(info)
+ if comp_num is None or comp_num == 0:
+ logger.info(' No compensation set. Nothing more to do.')
+ return None
+
+ # Need to meaningfully populate comp['set'] dict a.k.a. compset
+ n_comp_ch = sum([c['kind'] == FIFF.FIFFV_MEG_CH for c in info['chs']])
+ logger.info(' %d out of %d channels have the compensation set.'
+ % (n_comp_ch, len(coils)))
+
+ # Find the desired compensation data matrix
+ compensator = make_compensator(info, 0, comp_num, True)
+ logger.info(' Desired compensation data (%s) found.' % comp_num)
+ logger.info(' All compensation channels found.')
+ logger.info(' Preselector created.')
+ logger.info(' Compensation data matrix created.')
+ logger.info(' Postselector created.')
+ return compensator
+
+
+#def _bem_inf_pot(rd, Q, rp):
+# """The infinite medium potential in one direction"""
+# # NOTE: the (4.0 * np.pi) that was in the denominator has been moved!
+# diff = rp - rd
+# diff2 = np.sum(diff * diff, axis=1)
+# return np.sum(Q * diff, axis=1) / (diff2 * np.sqrt(diff2))
+
+
+def _bem_inf_pots(rr, surf_rr, Q=None):
+ """The infinite medium potential in all 3 directions"""
+ # NOTE: the (4.0 * np.pi) that was in the denominator has been moved!
+ diff = surf_rr.T[np.newaxis, :, :] - rr[:, :, np.newaxis] # n_rr, 3, n_bem
+ diff_norm = np.sum(diff * diff, axis=1)
+ diff_norm *= np.sqrt(diff_norm)
+ diff_norm[diff_norm == 0] = 1 # avoid nans
+ if Q is None: # save time when Q=np.eye(3) (e.g., MEG sensors)
+ return diff / diff_norm[:, np.newaxis, :]
+ else: # get components in each direction (e.g., EEG sensors)
+ return np.einsum('ijk,mj->imk', diff, Q) / diff_norm[:, np.newaxis, :]
+
+
+# This function has been refactored to process all points simultaneously
+#def _bem_inf_field(rd, Q, rp, d):
+# """Infinite-medium magnetic field"""
+# diff = rp - rd
+# diff2 = np.sum(diff * diff, axis=1)
+# x = fast_cross_3d(Q[np.newaxis, :], diff)
+# return np.sum(x * d, axis=1) / (diff2 * np.sqrt(diff2))
+
+
+def _bem_inf_fields(rr, rp, c):
+ """Infinite-medium magnetic field in all 3 basis directions"""
+ # Knowing that we're doing all directions, the above can be refactored:
+ diff = rp.T[np.newaxis, :, :] - rr[:, :, np.newaxis]
+ diff_norm = np.sum(diff * diff, axis=1)
+ diff_norm *= np.sqrt(diff_norm)
+ diff_norm[diff_norm == 0] = 1 # avoid nans
+ # This is the result of cross-prod calcs with basis vectors,
+ # as if we had taken (Q=np.eye(3)), then multiplied by the cosmags (c)
+ # factor, and then summed across directions
+ x = np.array([diff[:, 1] * c[:, 2] - diff[:, 2] * c[:, 1],
+ diff[:, 2] * c[:, 0] - diff[:, 0] * c[:, 2],
+ diff[:, 0] * c[:, 1] - diff[:, 1] * c[:, 0]])
+ return np.rollaxis(x / diff_norm, 1)
+
+
+def _bem_pot_or_field(rr, mri_rr, mri_Q, mults, coils, solution, srr,
+ n_jobs, coil_type):
+ """Calculate the magnetic field or electric potential
+
+ The code is very similar between EEG and MEG potentials, so we'll
+ combine them.
+ """
+ # multiply solution by "mults" here for simplicity
+ # we can do this one in-place because it's not used elsewhere
+ solution *= mults
+
+ # Both MEG and EEG have the inifinite-medium potentials
+ # This could be just vectorized, but eats too much memory, so instead we
+ # reduce memory by chunking within _do_inf_pots and parallelize, too:
+ parallel, p_fun, _ = parallel_func(_do_inf_pots, n_jobs)
+ nas = np.array_split
+ B = np.sum(parallel(p_fun(mri_rr, sr.copy(), mri_Q, sol.copy())
+ for sr, sol in zip(nas(srr, n_jobs),
+ nas(solution.T, n_jobs))), axis=0)
+ # The copy()s above should make it so the whole objects don't need to be
+ # pickled...
+
+ # Only MEG gets the primary current distribution
+ if coil_type == 'meg':
+ # Primary current contribution (can be calc. in coil/dipole coords)
+ parallel, p_fun, _ = parallel_func(_do_prim_curr, n_jobs)
+ pcc = np.concatenate(parallel(p_fun(rr, c)
+ for c in nas(coils, n_jobs)), axis=1)
+ B += pcc
+ B *= 1e-7 # MAG_FACTOR from C code
+ return B
+
+
+def _do_prim_curr(rr, coils):
+ """Calculate primary currents in a set of coils"""
+ out = np.empty((len(rr) * 3, len(coils)))
+ for ci, c in enumerate(coils):
+ out[:, ci] = np.sum(c['w'] * _bem_inf_fields(rr, c['rmag'],
+ c['cosmag']), 2).ravel()
+ return out
+
+
+def _do_inf_pots(rr, srr, mri_Q, sol):
+ """Calculate infinite potentials using chunks"""
+ # The following code is equivalent to this, but saves memory
+ #v0s = _bem_inf_pots(rr, srr, mri_Q) # n_rr x 3 x n_surf_rr
+ #v0s.shape = (len(rr) * 3, v0s.shape[2])
+ #B = np.dot(v0s, sol)
+
+ # We chunk the source rr's in order to save memory
+ bounds = np.r_[np.arange(0, len(rr), 1000), len(rr)]
+ B = np.empty((len(rr) * 3, sol.shape[1]))
+ for bi in xrange(len(bounds) - 1):
+ v0s = _bem_inf_pots(rr[bounds[bi]:bounds[bi + 1]], srr, mri_Q)
+ v0s.shape = (v0s.shape[0] * 3, v0s.shape[2])
+ B[3 * bounds[bi]:3 * bounds[bi + 1]] = np.dot(v0s, sol)
+ return B
+
+
+def _compute_forwards(src, bem, coils_list, cfs, ccoils_list, ccfs,
+ infos, coil_types, n_jobs):
+ """Compute the MEG and EEG forward solutions"""
+ if bem['bem_method'] != 'linear collocation':
+ raise RuntimeError('only linear collocation supported')
+
+ # Precompute some things that are used for both MEG and EEG
+ rr = np.concatenate([s['rr'][s['vertno']] for s in src])
+ mults = np.repeat(bem['source_mult'] / (4.0 * np.pi),
+ [len(s['rr']) for s in bem['surfs']])[np.newaxis, :]
+ # The dipole location and orientation must be transformed
+ mri_rr = apply_trans(bem['head_mri_t']['trans'], rr)
+ mri_Q = apply_trans(bem['head_mri_t']['trans'], np.eye(3), False)
+ srr = np.concatenate([s['rr'] for s in bem['surfs']])
+
+ # Now, actually compute MEG and EEG solutions
+ Bs = list()
+ for coil_type, coils, cf, ccoils, ccf, info in zip(coil_types, coils_list,
+ cfs, ccoils_list, ccfs,
+ infos):
+ if coils is None: # nothing to do
+ Bs.append(None)
+ else:
+ if coil_type == 'meg':
+ # Compose a compensation data set if necessary
+ compensator = _make_ctf_comp_coils(info, coils)
+
+ # Field computation matrices...
+ logger.info('')
+ start = 'Composing the field computation matrix'
+ logger.info(start + '...')
+ solution = _bem_specify_coils(bem, coils, cf, n_jobs)
+ if compensator is not None:
+ logger.info(start + ' (compensation coils)...')
+ csolution = _bem_specify_coils(bem, ccoils, ccf, n_jobs)
+
+ elif coil_type == 'eeg':
+ solution = _bem_specify_els(bem, coils)
+ compensator = None
+
+ # Do the actual calculation
+ logger.info('Computing %s at %d source locations '
+ '(free orientations)...'
+ % (coil_type.upper(), len(rr)))
+ # Note: this function modifies "solution" in-place
+ B = _bem_pot_or_field(rr, mri_rr, mri_Q, mults, coils,
+ solution, srr, n_jobs, coil_type)
+
+ # Compensate if needed (only done for MEG systems w/compensation)
+ if compensator is not None:
+ # Compute the field in the compensation coils
+ work = _bem_pot_or_field(rr, mri_rr, mri_Q, mults,
+ ccoils, csolution, srr, n_jobs,
+ coil_type)
+ # Combine solutions so we can do the compensation
+ both = np.zeros((work.shape[0], B.shape[1] + work.shape[1]))
+ picks = pick_types(info, meg=True, ref_meg=False)
+ both[:, picks] = B
+ picks = pick_types(info, meg=False, ref_meg=True)
+ both[:, picks] = work
+ B = np.dot(both, compensator.T)
+ Bs.append(B)
+
+ return Bs
diff --git a/mne/forward/_make_forward.py b/mne/forward/_make_forward.py
new file mode 100644
index 0000000..1470c0f
--- /dev/null
+++ b/mne/forward/_make_forward.py
@@ -0,0 +1,494 @@
+# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
+# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Eric Larson <larsoner at uw.edu>
+#
+# License: BSD (3-clause)
+
+import os
+from os import path as op
+import numpy as np
+
+from ..fiff import read_info, pick_types, pick_info, FIFF, _has_kit_refs
+from .forward import write_forward_solution, _merge_meg_eeg_fwds
+from ._compute_forward import _compute_forwards
+from ..transforms import (invert_transform, transform_source_space_to,
+ read_trans, _get_mri_head_t_from_trans_file,
+ apply_trans, _print_coord_trans, _coord_frame_name)
+from ..utils import logger, verbose
+from ..source_space import (read_source_spaces, _filter_source_spaces,
+ SourceSpaces)
+from ..surface import read_bem_solution, _normalize_vectors
+
+
+def _read_coil_defs(fname):
+ """Read a coil definition file"""
+ big_val = 0.5
+ with open(fname, 'r') as fid:
+ lines = fid.readlines()
+ res = dict(coils=list())
+ lines = lines[::-1]
+ while len(lines) > 0:
+ line = lines.pop()
+ if line[0] != '#':
+ vals = np.fromstring(line, sep=' ')
+ assert len(vals) == 7
+ start = line.find('"')
+ end = len(line.strip()) - 1
+ assert line.strip()[end] == '"'
+ desc = line[start:end]
+ npts = int(vals[3])
+ coil = dict(coil_type=vals[1], coil_class=vals[0], desc=desc,
+ accuracy=vals[2], size=vals[4], base=vals[5])
+ # get parameters of each component
+ rmag = list()
+ cosmag = list()
+ w = list()
+ for p in xrange(npts):
+ # get next non-comment line
+ line = lines.pop()
+ while(line[0] == '#'):
+ line = lines.pop()
+ vals = np.fromstring(line, sep=' ')
+ assert len(vals) == 7
+ # Read and verify data for each integration point
+ w.append(vals[0])
+ rmag.append(vals[[1, 2, 3]])
+ cosmag.append(vals[[4, 5, 6]])
+ w = np.array(w)
+ rmag = np.array(rmag)
+ cosmag = np.array(cosmag)
+ size = np.sqrt(np.sum(cosmag ** 2, axis=1))
+ if np.any(np.sqrt(np.sum(rmag ** 2, axis=1)) > big_val):
+ raise RuntimeError('Unreasonable integration point')
+ if np.any(size <= 0):
+ raise RuntimeError('Unreasonable normal')
+ cosmag /= size[:, np.newaxis]
+ coil.update(dict(w=w, cosmag=cosmag, rmag=rmag))
+ res['coils'].append(coil)
+ logger.info('%d coil definitions read', len(res['coils']))
+ return res
+
+
+def _create_meg_coil(coilset, ch, acc, t):
+ """Create a coil definition using templates, transform if necessary"""
+ # Also change the coordinate frame if so desired
+
+ if ch['kind'] not in [FIFF.FIFFV_MEG_CH, FIFF.FIFFV_REF_MEG_CH]:
+ raise RuntimeError('%s is not a MEG channel' % ch['ch_name'])
+
+ # Simple linear search from the coil definitions
+ d = None
+ for coil in coilset['coils']:
+ if coil['coil_type'] == (ch['coil_type'] & 0xFFFF) and \
+ coil['accuracy'] == acc:
+ d = coil
+
+ if d is None:
+ raise RuntimeError('Desired coil definition not found '
+ '(type = %d acc = %d)' % (ch['coil_type'], acc))
+
+ # Create the result
+ res = dict(chname=ch['ch_name'], desc=None, coil_class=d['coil_class'],
+ accuracy=d['accuracy'], base=d['base'], size=d['size'],
+ type=ch['coil_type'], w=d['w'])
+
+ if d['desc']:
+ res['desc'] = d['desc']
+
+ # Apply a coordinate transformation if so desired
+ coil_trans = ch['coil_trans'].copy() # make sure we don't botch it
+ if t is not None:
+ coil_trans = np.dot(t['trans'], coil_trans)
+ res['coord_frame'] = t['to']
+ else:
+ res['coord_frame'] = FIFF.FIFFV_COORD_DEVICE
+
+ res['rmag'] = apply_trans(coil_trans, d['rmag'])
+ res['cosmag'] = apply_trans(coil_trans, d['cosmag'], False)
+ res.update(ex=coil_trans[:3, 0], ey=coil_trans[:3, 1],
+ ez=coil_trans[:3, 2], r0=coil_trans[:3, 3])
+ return res
+
+
+def _create_eeg_el(ch, t):
+ """Create an electrode definition, transform coords if necessary"""
+ if ch['kind'] != FIFF.FIFFV_EEG_CH:
+ raise RuntimeError('%s is not an EEG channel. Cannot create an '
+ 'electrode definition.' % ch['ch_name'])
+ if t is not None and t['from'] != FIFF.FIFFV_COORD_HEAD:
+ raise RuntimeError('Inappropriate coordinate transformation')
+
+ r0ex = ch['eeg_loc'][:, :2]
+ if r0ex.shape[1] == 1: # no reference
+ w = np.array([1.])
+ else: # has reference
+ w = np.array([1., -1.])
+
+ # Optional coordinate transformation
+ r0ex = r0ex.T.copy()
+ if t is not None:
+ r0ex = apply_trans(t['trans'], r0ex)
+ coord_frame = t['to']
+ else:
+ coord_frame = FIFF.FIFFV_COORD_HEAD
+
+ # The electrode location
+ cosmag = r0ex.copy()
+ _normalize_vectors(cosmag)
+ res = dict(chname=ch['ch_name'], coil_class=FIFF.FWD_COILC_EEG, w=w,
+ accuracy=FIFF.FWD_COIL_ACCURACY_NORMAL, type=ch['coil_type'],
+ coord_frame=coord_frame, rmag=r0ex, cosmag=cosmag)
+ return res
+
+
+def _create_coils(coilset, chs, acc, t, coil_type='meg'):
+ """Create a set of MEG or EEG coils"""
+ coils = list()
+ if coil_type == 'meg':
+ for ch in chs:
+ coils.append(_create_meg_coil(coilset, ch, acc, t))
+ elif coil_type == 'eeg':
+ for ch in chs:
+ coils.append(_create_eeg_el(ch, t))
+ else:
+ raise RuntimeError('unknown coil type')
+ return coils, t['to']
+
+
+ at verbose
+def make_forward_solution(info, mri, src, bem, fname=None, meg=True, eeg=True,
+ mindist=0.0, ignore_ref=False, overwrite=False,
+ n_jobs=1, verbose=None):
+ """Calculate a forward solution for a subject
+
+ Parameters
+ ----------
+ info : instance of mne.fiff.meas_info.Info | str
+ If str, then it should be a filename to a Raw, Epochs, or Evoked
+ file with measurement information. If dict, should be an info
+ dict (such as one from Raw, Epochs, or Evoked).
+ mri : dict | str
+ Either a transformation filename (usually made using mne_analyze)
+ or an info dict (usually opened using read_trans()).
+ If string, an ending of `.fif` or `.fif.gz` will be assumed to
+ be in FIF format, any other ending will be assumed to be a text
+ file with a 4x4 transformation matrix (like the `--trans` MNE-C
+ option).
+ src : str | instance of SourceSpaces
+ If string, should be a source space filename. Can also be an
+ instance of loaded or generated SourceSpaces.
+ bem : str
+ Filename of the BEM (e.g., "sample-5120-5120-5120-bem-sol.fif") to
+ use.
+ fname : str | None
+ Destination forward solution filename. If None, the solution
+ will not be saved.
+ meg : bool
+ If True (Default), include MEG computations.
+ eeg : bool
+ If True (Default), include EEG computations.
+ mindist : float
+ Minimum distance of sources from inner skull surface (in mm).
+ ignore_ref : bool
+ If True, do not include reference channels in compensation. This
+ option should be True for KIT files, since forward computation
+ with reference channels is not currently supported.
+ overwrite : bool
+ If True, the destination file (if it exists) will be overwritten.
+ If False (default), an error will be raised if the file exists.
+ n_jobs : int
+ Number of jobs to run in parallel.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ fwd : dict
+ The generated forward solution.
+
+ Notes
+ -----
+ Some of the forward solution calculation options from the C code
+ (e.g., `--grad`, `--fixed`) are not implemented here. For those,
+ consider using the C command line tools or the Python wrapper
+ `do_forward_solution`.
+ """
+ # Currently not (sup)ported:
+ # 1. EEG Sphere model (not used much)
+ # 2. --grad option (gradients of the field, not used much)
+ # 3. --fixed option (can be computed post-hoc)
+ # 4. --mricoord option (probably not necessary)
+
+ if isinstance(mri, basestring):
+ if not op.isfile(mri):
+ raise IOError('mri file "%s" not found' % mri)
+ if op.splitext(mri)[1] in ['.fif', '.gz']:
+ mri_head_t = read_trans(mri)
+ else:
+ mri_head_t = _get_mri_head_t_from_trans_file(mri)
+ else: # dict
+ mri_head_t = mri
+ mri = 'dict'
+
+ if not isinstance(src, basestring):
+ if not isinstance(src, SourceSpaces):
+ raise TypeError('src must be a string or SourceSpaces')
+ src_extra = 'list'
+ else:
+ src_extra = src
+ if not op.isfile(src):
+ raise IOError('Source space file "%s" not found' % src)
+ if not op.isfile(bem):
+ raise IOError('BEM file "%s" not found' % bem)
+ if fname is not None and op.isfile(fname) and not overwrite:
+ raise IOError('file "%s" exists, consider using overwrite=True'
+ % fname)
+ if not isinstance(info, (dict, basestring)):
+ raise TypeError('info should be a dict or string')
+ if isinstance(info, basestring):
+ info_extra = op.split(info)[1]
+ info_extra_long = info
+ info = read_info(info, verbose=False)
+ else:
+ info_extra = 'info dict'
+ info_extra_long = info_extra
+ arg_list = [info_extra, mri, src_extra, bem, fname, meg, eeg,
+ mindist, overwrite, n_jobs, verbose]
+ cmd = 'make_forward_solution(%s)' % (', '.join([str(a) for a in arg_list]))
+
+ # this could, in principle, be an option
+ coord_frame = FIFF.FIFFV_COORD_HEAD
+
+ # Report the setup
+ mri_extra = mri if isinstance(mri, basestring) else 'dict'
+ logger.info('Source space : %s' % src)
+ logger.info('MRI -> head transform source : %s' % mri_extra)
+ logger.info('Measurement data : %s' % info_extra_long)
+ logger.info('BEM model : %s' % bem)
+ logger.info('Accurate field computations')
+ logger.info('Do computations in %s coordinates',
+ _coord_frame_name(coord_frame))
+ logger.info('Free source orientations')
+ logger.info('Destination for the solution : %s' % fname)
+
+ # Read the source locations
+ logger.info('')
+ if isinstance(src, basestring):
+ logger.info('Reading %s...' % src)
+ src = read_source_spaces(src, verbose=False)
+ else:
+ # let's make a copy in case we modify something
+ src = src.copy()
+ nsource = sum(s['nuse'] for s in src)
+ if nsource == 0:
+ raise RuntimeError('No sources are active in these source spaces. '
+ '"do_all" option should be used.')
+ logger.info('Read %d source spaces a total of %d active source locations'
+ % (len(src), nsource))
+
+ # Read the MRI -> head coordinate transformation
+ logger.info('')
+
+ # it's actually usually a head->MRI transform, so we probably need to
+ # invert it
+ if mri_head_t['from'] == FIFF.FIFFV_COORD_HEAD:
+ mri_head_t = invert_transform(mri_head_t)
+ if not (mri_head_t['from'] == FIFF.FIFFV_COORD_MRI and
+ mri_head_t['to'] == FIFF.FIFFV_COORD_HEAD):
+ raise RuntimeError('Incorrect MRI transform provided')
+ _print_coord_trans(mri_head_t)
+
+ # make a new dict with the relevant information
+ mri_id = dict(machid=np.zeros(2, np.int32), version=0, secs=0, usecs=0)
+ info = dict(nchan=info['nchan'], chs=info['chs'], comps=info['comps'],
+ ch_names=info['ch_names'], dev_head_t=info['dev_head_t'],
+ mri_file=mri_extra, mri_id=mri_id, meas_file=info_extra_long,
+ meas_id=None, working_dir=os.getcwd(),
+ command_line=cmd, bads=info['bads'])
+ meg_head_t = info['dev_head_t']
+ logger.info('')
+
+ # MEG channels
+ megnames = None
+ if meg:
+ picks = pick_types(info, meg=True, eeg=False, ref_meg=False,
+ exclude=[])
+ nmeg = len(picks)
+ if nmeg > 0:
+ megchs = pick_info(info, picks)['chs']
+ megnames = [info['ch_names'][p] for p in picks]
+ logger.info('Read %3d MEG channels from %s'
+ % (len(picks), info_extra))
+
+ # comp channels
+ if not ignore_ref:
+ picks = pick_types(info, meg=False, ref_meg=True, exclude=[])
+ ncomp = len(picks)
+ if (ncomp > 0):
+ compchs = pick_info(info, picks)['chs']
+ logger.info('Read %3d MEG compensation channels from %s'
+ % (ncomp, info_extra))
+ # We need to check to make sure these are NOT KIT refs
+ if _has_kit_refs(info, picks):
+ err = ('Cannot create forward solution with KIT '
+ 'reference channels. Consider using '
+ '"ignore_ref=True" in calculation')
+ raise NotImplementedError(err)
+ _print_coord_trans(meg_head_t)
+ # make info structure to allow making compensator later
+ else:
+ ncomp = 0
+ ncomp_data = len(info['comps'])
+ ref_meg = True if not ignore_ref else False
+ picks = pick_types(info, meg=True, ref_meg=ref_meg, exclude=[])
+ meg_info = pick_info(info, picks)
+ else:
+ logger.info('MEG not requested. MEG channels omitted.')
+ nmeg = 0
+ meg_info = None
+
+ # EEG channels
+ eegnames = None
+ if eeg:
+ picks = pick_types(info, meg=False, eeg=True, ref_meg=False,
+ exclude=[])
+ neeg = len(picks)
+ if neeg > 0:
+ eegchs = pick_info(info, picks)['chs']
+ eegnames = [info['ch_names'][p] for p in picks]
+ logger.info('Read %3d EEG channels from %s'
+ % (len(picks), info_extra))
+ else:
+ neeg = 0
+ logger.info('EEG not requested. EEG channels omitted.')
+
+ if neeg <= 0 and nmeg <= 0:
+ raise RuntimeError('Could not find any MEG or EEG channels')
+
+ # Create coil descriptions with transformation to head or MRI frame
+ templates = _read_coil_defs(op.join(op.split(__file__)[0],
+ '..', 'data', 'coil_def.dat'))
+ if nmeg > 0 and ncomp > 0: # Compensation channel information
+ logger.info('%d compensation data sets in %s'
+ % (ncomp_data, info_extra))
+
+ meg_xform = meg_head_t
+ eeg_xform = {'trans': np.eye(4), 'to': FIFF.FIFFV_COORD_HEAD,
+ 'from': FIFF.FIFFV_COORD_HEAD}
+ extra_str = 'Head'
+
+ megcoils, megcf, compcoils, compcf = None, None, None, None
+ if nmeg > 0:
+ megcoils, megcf = _create_coils(templates, megchs,
+ FIFF.FWD_COIL_ACCURACY_ACCURATE,
+ meg_xform, coil_type='meg')
+ if ncomp > 0:
+ compcoils, compcf = _create_coils(templates, compchs,
+ FIFF.FWD_COIL_ACCURACY_NORMAL,
+ meg_xform, coil_type='meg')
+ eegels = None
+ if neeg > 0:
+ eegels, _ = _create_coils(templates, eegchs, None,
+ eeg_xform, coil_type='eeg')
+ logger.info('%s coordinate coil definitions created.' % extra_str)
+
+ # Transform the source spaces into the appropriate coordinates
+ for s in src:
+ transform_source_space_to(s, coord_frame, mri_head_t)
+ logger.info('Source spaces are now in %s coordinates.'
+ % _coord_frame_name(coord_frame))
+
+ # Prepare the BEM model
+ logger.info('')
+ logger.info('Setting up the BEM model using %s...\n' % bem)
+ bem_name = bem
+ bem = read_bem_solution(bem)
+ if neeg > 0 and len(bem['surfs']) == 1:
+ raise RuntimeError('Cannot use a homogeneous model in EEG '
+ 'calculations')
+ logger.info('Employing the head->MRI coordinate transform with the '
+ 'BEM model.')
+ # fwd_bem_set_head_mri_t: Set the coordinate transformation
+ to, fro = mri_head_t['to'], mri_head_t['from']
+ if fro == FIFF.FIFFV_COORD_HEAD and to == FIFF.FIFFV_COORD_MRI:
+ bem['head_mri_t'] = mri_head_t
+ elif fro == FIFF.FIFFV_COORD_MRI and to == FIFF.FIFFV_COORD_HEAD:
+ bem['head_mri_t'] = invert_transform(mri_head_t)
+ else:
+ raise RuntimeError('Improper coordinate transform')
+ logger.info('BEM model %s is now set up' % op.split(bem_name)[1])
+ logger.info('')
+
+ # Circumvent numerical problems by excluding points too close to the skull
+ idx = np.where(np.array([s['id'] for s in bem['surfs']])
+ == FIFF.FIFFV_BEM_SURF_ID_BRAIN)[0]
+ if len(idx) != 1:
+ raise RuntimeError('BEM model does not have the inner skull '
+ 'triangulation')
+ _filter_source_spaces(bem['surfs'][idx[0]], mindist, mri_head_t, src,
+ n_jobs)
+ logger.info('')
+
+ # Time to do the heavy lifting: MEG first, then EEG
+ coil_types = ['meg', 'eeg']
+ coils = [megcoils, eegels]
+ cfs = [megcf, None]
+ ccoils = [compcoils, None]
+ ccfs = [compcf, None]
+ infos = [meg_info, None]
+ megfwd, eegfwd = _compute_forwards(src, bem, coils, cfs, ccoils, ccfs,
+ infos, coil_types, n_jobs)
+
+ # merge forwards into one
+ megfwd = _to_forward_dict(megfwd, None, megnames, coord_frame,
+ FIFF.FIFFV_MNE_FREE_ORI)
+ eegfwd = _to_forward_dict(eegfwd, None, eegnames, coord_frame,
+ FIFF.FIFFV_MNE_FREE_ORI)
+ fwd = _merge_meg_eeg_fwds(megfwd, eegfwd, verbose=False)
+ logger.info('')
+
+ # pick out final dict info
+ picks = pick_types(info, meg=meg, eeg=eeg, ref_meg=False, exclude=[])
+ info = pick_info(info, picks)
+ source_rr = np.concatenate([s['rr'][s['vertno']] for s in src])
+ # deal with free orientations:
+ nsource = fwd['sol']['data'].shape[1] / 3
+ source_nn = np.tile(np.eye(3), (nsource, 1))
+
+ # Don't transform the source spaces back into MRI coordinates (which is
+ # done in the C code) because mne-python assumes forward solution source
+ # spaces are in head coords. We will delete some keys to clean up the
+ # source space, though:
+ for key in ['working_dir', 'command_line']:
+ if key in src.info:
+ del src.info[key]
+ fwd.update(dict(nchan=fwd['sol']['data'].shape[0], nsource=nsource,
+ info=info, src=src, source_nn=source_nn,
+ source_rr=source_rr, surf_ori=False,
+ mri_head_t=mri_head_t))
+ fwd['info']['mri_head_t'] = mri_head_t
+ if fname is not None:
+ logger.info('writing %s...', fname)
+ write_forward_solution(fname, fwd, overwrite, verbose=False)
+
+ logger.info('Finished.')
+ return fwd
+
+
+def _to_forward_dict(fwd, fwd_grad, names, coord_frame, source_ori):
+ """Convert forward solution matrices to dicts"""
+ if fwd is not None:
+ sol = dict(data=fwd.T, nrow=fwd.shape[1], ncol=fwd.shape[0],
+ row_names=names, col_names=[])
+ fwd = dict(sol=sol, source_ori=source_ori, nsource=sol['ncol'],
+ coord_frame=coord_frame, sol_grad=None,
+ nchan=sol['nrow'], _orig_source_ori=source_ori,
+ _orig_sol=sol['data'].copy(), _orig_sol_grad=None)
+ if fwd_grad is not None:
+ sol_grad = dict(data=fwd_grad.T, nrow=fwd_grad.shape[1],
+ ncol=fwd_grad.shape[0], row_names=names,
+ col_names=[])
+ fwd.update(dict(sol_grad=sol_grad),
+ _orig_sol_grad=sol_grad['data'].copy())
+ return fwd
diff --git a/mne/forward.py b/mne/forward/forward.py
similarity index 84%
rename from mne/forward.py
rename to mne/forward/forward.py
index e5b12eb..df480df 100644
--- a/mne/forward.py
+++ b/mne/forward/forward.py
@@ -7,6 +7,7 @@
from time import time
import warnings
from copy import deepcopy
+import re
import numpy as np
from scipy import linalg, sparse
@@ -16,32 +17,52 @@ import os
from os import path as op
import tempfile
-import logging
-logger = logging.getLogger('mne')
-
-from .fiff.constants import FIFF
-from .fiff.open import fiff_open
-from .fiff.tree import dir_tree_find
-from .fiff.channels import read_bad_channels
-from .fiff.tag import find_tag, read_tag
-from .fiff.matrix import _read_named_matrix, _transpose_named_matrix, \
- write_named_matrix
-from .fiff.pick import pick_channels_forward, pick_info, pick_channels, \
- pick_types
-from .fiff.write import write_int, start_block, end_block, \
- write_coord_trans, write_ch_info, write_name_list, \
- write_string, start_file, end_file, write_id
-from .fiff.raw import Raw
-from .fiff.evoked import Evoked, write_evoked
-from .event import make_fixed_length_events
-from .epochs import Epochs
-from .source_space import read_source_spaces_from_tree, \
- find_source_space_hemi, write_source_spaces_to_fid
-from .transforms import transform_source_space_to, invert_transform, \
- write_trans
-from .utils import _check_fname, get_subjects_dir, has_command_line_tools, \
- run_subprocess
-from . import verbose
+from ..fiff.constants import FIFF
+from ..fiff.open import fiff_open
+from ..fiff.tree import dir_tree_find
+from ..fiff.channels import read_bad_channels
+from ..fiff.tag import find_tag, read_tag
+from ..fiff.matrix import (_read_named_matrix, _transpose_named_matrix,
+ write_named_matrix)
+from ..fiff.pick import (pick_channels_forward, pick_info, pick_channels,
+ pick_types)
+from ..fiff.write import (write_int, start_block, end_block,
+ write_coord_trans, write_ch_info, write_name_list,
+ write_string, start_file, end_file, write_id)
+from ..fiff.raw import Raw
+from ..fiff.evoked import Evoked, write_evoked
+from ..event import make_fixed_length_events
+from ..epochs import Epochs
+from ..source_space import (read_source_spaces_from_tree,
+ find_source_space_hemi,
+ _write_source_spaces_to_fid)
+from ..transforms import (transform_source_space_to, invert_transform,
+ write_trans)
+from ..utils import (_check_fname, get_subjects_dir, has_command_line_tools,
+ run_subprocess, logger, verbose)
+
+
+def prepare_bem_model(bem, sol_fname=None, method='linear'):
+ """Wrapper for the mne_prepare_bem_model command line utility
+
+ Parameters
+ ----------
+ bem : str
+ The name of the file containing the triangulations of the BEM surfaces
+ and the conductivities of the compartments. The standard ending for
+ this file is -bem.fif and it is produced either with the utility
+ mne_surf2bem or the convenience script mne_setup_forward_model.
+ sol_fname : None | str
+ The output file. None (the default) will employ the standard naming
+ scheme. To conform with the standard naming conventions the filename
+ should start with the subject name and end in "-bem-sol.fif".
+ method : 'linear' | 'constant'
+ The BEM approach.
+ """
+ cmd = ['mne_prepare_bem_model', '--bem', bem, '--method', method]
+ if sol_fname is not None:
+ cmd.extend(('--sol', sol_fname))
+ run_subprocess(cmd)
def _block_diag(A, n):
@@ -174,6 +195,7 @@ def _read_one(fid, node):
one['sol'] = _read_named_matrix(fid, node,
FIFF.FIFF_MNE_FORWARD_SOLUTION)
one['sol'] = _transpose_named_matrix(one['sol'], copy=False)
+ one['_orig_sol'] = one['sol']['data'].copy()
except:
fid.close()
logger.error('Forward solution data not found')
@@ -183,6 +205,7 @@ def _read_one(fid, node):
one['sol_grad'] = _read_named_matrix(fid, node,
FIFF.FIFF_MNE_FORWARD_SOLUTION_GRAD)
one['sol_grad'] = _transpose_named_matrix(one['sol_grad'], copy=False)
+ one['_orig_sol_grad'] = one['sol_grad']['data'].copy()
except:
one['sol_grad'] = None
@@ -215,7 +238,7 @@ def read_forward_meas_info(tree, fid):
Returns
-------
- info : dict
+ info : instance of mne.fiff.meas_info.Info
The measurement info.
"""
info = dict()
@@ -259,17 +282,19 @@ def read_forward_meas_info(tree, fid):
# Get the MRI <-> head coordinate transformation
tag = find_tag(fid, parent_mri, FIFF.FIFF_COORD_TRANS)
+ coord_head = FIFF.FIFFV_COORD_HEAD
+ coord_mri = FIFF.FIFFV_COORD_MRI
+ coord_device = FIFF.FIFFV_COORD_DEVICE
+ coord_ctf_head = FIFF.FIFFV_MNE_COORD_CTF_HEAD
if tag is None:
fid.close()
raise ValueError('MRI/head coordinate transformation not found')
else:
cand = tag.data
- if cand['from'] == FIFF.FIFFV_COORD_MRI and \
- cand['to'] == FIFF.FIFFV_COORD_HEAD:
+ if cand['from'] == coord_mri and cand['to'] == coord_head:
info['mri_head_t'] = cand
else:
- raise ValueError('MEG device/head coordinate transformation not '
- 'found')
+ raise ValueError('MRI/head coordinate transformation not found')
# Get the MEG device <-> head coordinate transformation
tag = find_tag(fid, parent_meg, FIFF.FIFF_COORD_TRANS)
@@ -278,15 +303,12 @@ def read_forward_meas_info(tree, fid):
raise ValueError('MEG/head coordinate transformation not found')
else:
cand = tag.data
- if cand['from'] == FIFF.FIFFV_COORD_DEVICE and \
- cand['to'] == FIFF.FIFFV_COORD_HEAD:
+ if cand['from'] == coord_device and cand['to'] == coord_head:
info['dev_head_t'] = cand
- elif cand['from'] == FIFF.FIFFV_MNE_COORD_CTF_HEAD and \
- cand['to'] == FIFF.FIFFV_COORD_HEAD:
+ elif cand['from'] == coord_ctf_head and cand['to'] == coord_head:
info['ctf_head_t'] = cand
else:
- raise ValueError('MEG device/head coordinate transformation not '
- 'found')
+ raise ValueError('MEG/head coordinate transformation not found')
info['bads'] = read_bad_channels(fid, parent_meg)
return info
@@ -298,8 +320,44 @@ def _subject_from_forward(forward):
@verbose
+def _merge_meg_eeg_fwds(megfwd, eegfwd, verbose=None):
+ """Merge loaded MEG and EEG forward dicts into one dict"""
+ if megfwd is not None and eegfwd is not None:
+ if (megfwd['sol']['data'].shape[1] != eegfwd['sol']['data'].shape[1] or
+ megfwd['source_ori'] != eegfwd['source_ori'] or
+ megfwd['nsource'] != eegfwd['nsource'] or
+ megfwd['coord_frame'] != eegfwd['coord_frame']):
+ raise ValueError('The MEG and EEG forward solutions do not match')
+
+ fwd = megfwd
+ fwd['sol']['data'] = np.r_[fwd['sol']['data'], eegfwd['sol']['data']]
+ fwd['_orig_sol'] = np.r_[fwd['_orig_sol'], eegfwd['_orig_sol']]
+ fwd['sol']['nrow'] = fwd['sol']['nrow'] + eegfwd['sol']['nrow']
+
+ fwd['sol']['row_names'] = (fwd['sol']['row_names'] +
+ eegfwd['sol']['row_names'])
+ if fwd['sol_grad'] is not None:
+ fwd['sol_grad']['data'] = np.r_[fwd['sol_grad']['data'],
+ eegfwd['sol_grad']['data']]
+ fwd['_orig_sol_grad'] = np.r_[fwd['_orig_sol_grad'],
+ eegfwd['_orig_sol_grad']]
+ fwd['sol_grad']['nrow'] = (fwd['sol_grad']['nrow'] +
+ eegfwd['sol_grad']['nrow'])
+ fwd['sol_grad']['row_names'] = (fwd['sol_grad']['row_names'] +
+ eegfwd['sol_grad']['row_names'])
+
+ fwd['nchan'] = fwd['nchan'] + eegfwd['nchan']
+ logger.info(' MEG and EEG forward solutions combined')
+ elif megfwd is not None:
+ fwd = megfwd
+ else:
+ fwd = eegfwd
+ return fwd
+
+
+ at verbose
def read_forward_solution(fname, force_fixed=False, surf_ori=False,
- include=[], exclude=[], verbose=None):
+ include=[], exclude=[], verbose=None):
"""Read a forward solution a.k.a. lead field
Parameters
@@ -309,7 +367,7 @@ def read_forward_solution(fname, force_fixed=False, surf_ori=False,
force_fixed : bool, optional (default False)
Force fixed source orientation mode?
surf_ori : bool, optional (default False)
- Use surface based source coordinate system?
+ Use surface-based source coordinate system?
include : list, optional
List of names of channels to include. If empty all channels
are included.
@@ -389,37 +447,11 @@ def read_forward_solution(fname, force_fixed=False, surf_ori=False,
ori))
# Merge the MEG and EEG solutions together
- if megfwd is not None and eegfwd is not None:
- if (megfwd['sol']['data'].shape[1] != eegfwd['sol']['data'].shape[1] or
- megfwd['source_ori'] != eegfwd['source_ori'] or
- megfwd['nsource'] != eegfwd['nsource'] or
- megfwd['coord_frame'] != eegfwd['coord_frame']):
- fid.close()
- raise ValueError('The MEG and EEG forward solutions do not match')
-
- fwd = megfwd
- fwd['sol']['data'] = np.r_[fwd['sol']['data'], eegfwd['sol']['data']]
- fwd['sol']['nrow'] = fwd['sol']['nrow'] + eegfwd['sol']['nrow']
-
- fwd['sol']['row_names'] = fwd['sol']['row_names'] + \
- eegfwd['sol']['row_names']
- if fwd['sol_grad'] is not None:
- fwd['sol_grad']['data'] = np.r_[fwd['sol_grad']['data'],
- eegfwd['sol_grad']['data']]
- fwd['sol_grad']['nrow'] = fwd['sol_grad']['nrow'] + \
- eegfwd['sol_grad']['nrow']
- fwd['sol_grad']['row_names'] = fwd['sol_grad']['row_names'] + \
- eegfwd['sol_grad']['row_names']
-
- fwd['nchan'] = fwd['nchan'] + eegfwd['nchan']
- logger.info(' MEG and EEG forward solutions combined')
- elif megfwd is not None:
- fwd = megfwd
- else:
- fwd = eegfwd
-
- del megfwd
- del eegfwd
+ try:
+ fwd = _merge_meg_eeg_fwds(megfwd, eegfwd)
+ except:
+ fid.close()
+ raise
# Get the MRI <-> head coordinate transformation
tag = find_tag(fid, parent_mri, FIFF.FIFF_COORD_TRANS)
@@ -483,42 +515,88 @@ def read_forward_solution(fname, force_fixed=False, surf_ori=False,
# Handle the source locations and orientations
fwd['source_rr'] = np.concatenate([s['rr'][s['vertno'], :] for s in src],
axis=0)
- if is_fixed_orient(fwd) or force_fixed:
+
+ # deal with transformations, storing orig copies so transforms can be done
+ # as necessary later
+ fwd['_orig_source_ori'] = fwd['source_ori']
+ fwd['surf_ori'] = False # tell it that it's not surf oriented by default
+ convert_forward_solution(fwd, surf_ori, force_fixed, copy=False)
+ fwd = pick_channels_forward(fwd, include=include, exclude=exclude)
+ return fwd
+
+
+ at verbose
+def convert_forward_solution(fwd, surf_ori=False, force_fixed=False,
+ copy=True, verbose=None):
+ """Convert forward solution between different source orientations
+
+ Parameters
+ ----------
+ fwd : dict
+ The forward solution to modify.
+ surf_ori : bool, optional (default False)
+ Use surface-based source coordinate system?
+ force_fixed : bool, optional (default False)
+ Force fixed source orientation mode?
+ copy : bool, optional (default True)
+ If False, operation will be done in-place (modifying the input).
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ fwd : dict
+ The modified forward solution.
+ """
+ if copy is True:
+ fwd = deepcopy(fwd)
+
+ # We need to change these entries (only):
+ # 1. source_nn
+ # 2. sol['data']
+ # 3. sol['ncol']
+ # 4. sol_grad['data']
+ # 5. sol_grad['ncol']
+ # 6. source_ori
+ if is_fixed_orient(fwd, orig=True) or force_fixed: # Fixed
nuse = 0
fwd['source_nn'] = np.concatenate([s['nn'][s['vertno'], :]
- for s in src], axis=0)
+ for s in fwd['src']], axis=0)
# Modify the forward solution for fixed source orientations
- if not is_fixed_orient(fwd):
+ if not is_fixed_orient(fwd, orig=True):
logger.info(' Changing to fixed-orientation forward '
'solution...')
fix_rot = _block_diag(fwd['source_nn'].T, 1)
# newer versions of numpy require explicit casting here, so *= no
# longer works
- fwd['sol']['data'] = (fwd['sol']['data']
+ fwd['sol']['data'] = (fwd['_orig_sol']
* fix_rot).astype('float32')
fwd['sol']['ncol'] = fwd['nsource']
fwd['source_ori'] = FIFF.FIFFV_MNE_FIXED_ORI
if fwd['sol_grad'] is not None:
- fwd['sol_grad']['data'] = np.dot(fwd['sol_grad']['data'],
+ fwd['sol_grad']['data'] = np.dot(fwd['_orig_sol_grad'],
np.kron(fix_rot, np.eye(3)))
fwd['sol_grad']['ncol'] = 3 * fwd['nsource']
logger.info(' [done]')
- elif surf_ori:
+ fwd['source_ori'] = FIFF.FIFFV_MNE_FIXED_ORI
+ elif surf_ori: # Free, surf-oriented
# Rotate the local source coordinate systems
- logger.info(' Converting to surface-based source orientations...')
- nuse_total = sum([s['nuse'] for s in src])
+ nuse_total = sum([s['nuse'] for s in fwd['src']])
fwd['source_nn'] = np.empty((3 * nuse_total, 3), dtype=np.float)
+ logger.info(' Converting to surface-based source orientations...')
if s['patch_inds'] is not None:
use_ave_nn = True
logger.info(' Average patch normals will be employed in the '
'rotation to the local surface coordinates....')
else:
use_ave_nn = False
+
+ # Actually determine the source orientations
nuse = 0
pp = 0
- for s in src:
+ for s in fwd['src']:
for p in range(s['nuse']):
# Project out the surface normal and compute SVD
if use_ave_nn is True:
@@ -535,21 +613,28 @@ def read_forward_solution(fname, force_fixed=False, surf_ori=False,
pp += 3
nuse += s['nuse']
+ # Rotate the solution components as well
surf_rot = _block_diag(fwd['source_nn'].T, 3)
- fwd['sol']['data'] = fwd['sol']['data'] * surf_rot
+ fwd['sol']['data'] = fwd['_orig_sol'] * surf_rot
+ fwd['sol']['ncol'] = 3 * fwd['nsource']
if fwd['sol_grad'] is not None:
- fwd['sol_grad']['data'] = np.dot(fwd['sol_grad']['data'] *
- np.kron(surf_rot, np.eye(3)))
+ fwd['sol_grad'] = np.dot(fwd['_orig_sol_grad'] *
+ np.kron(surf_rot, np.eye(3)))
+ fwd['sol_grad']['ncol'] = 3 * fwd['nsource']
logger.info('[done]')
- else:
+ fwd['source_ori'] = FIFF.FIFFV_MNE_FREE_ORI
+ else: # Free, cartesian
logger.info(' Cartesian source orientations...')
fwd['source_nn'] = np.kron(np.ones((fwd['nsource'], 1)), np.eye(3))
+ fwd['sol']['data'] = fwd['_orig_sol'].copy()
+ fwd['sol']['ncol'] = 3 * fwd['nsource']
+ if fwd['sol_grad'] is not None:
+ fwd['sol_grad']['data'] = fwd['_orig_sol_grad'].copy()
+ fwd['sol_grad']['ncol'] = 3 * fwd['nsource']
+ fwd['source_ori'] = FIFF.FIFFV_MNE_FREE_ORI
logger.info('[done]')
fwd['surf_ori'] = surf_ori
-
- fwd = pick_channels_forward(fwd, include=include, exclude=exclude)
-
return fwd
@@ -613,7 +698,7 @@ def write_forward_solution(fname, fwd, overwrite=False, verbose=None):
#
# Write the source spaces (again)
#
- write_source_spaces_to_fid(fid, src)
+ _write_source_spaces_to_fid(fid, src)
n_vert = sum([s['nuse'] for s in src])
n_col = fwd['sol']['data'].shape[1]
if fwd['source_ori'] == FIFF.FIFFV_MNE_FIXED_ORI:
@@ -637,8 +722,10 @@ def write_forward_solution(fname, fwd, overwrite=False, verbose=None):
#
# MEG forward solution
#
- picks_meg = pick_types(fwd['info'], meg=True, eeg=False, exclude=[])
- picks_eeg = pick_types(fwd['info'], meg=False, eeg=True, exclude=[])
+ picks_meg = pick_types(fwd['info'], meg=True, eeg=False, ref_meg=False,
+ exclude=[])
+ picks_eeg = pick_types(fwd['info'], meg=False, eeg=True, ref_meg=False,
+ exclude=[])
n_meg = len(picks_meg)
n_eeg = len(picks_eeg)
row_names_meg = [fwd['sol']['row_names'][p] for p in picks_meg]
@@ -706,11 +793,14 @@ def _to_fixed_ori(forward):
return forward
-def is_fixed_orient(forward):
+def is_fixed_orient(forward, orig=False):
"""Has forward operator fixed orientation?
"""
- is_fixed_ori = (forward['source_ori'] == FIFF.FIFFV_MNE_FIXED_ORI)
- return is_fixed_ori
+ if orig: # if we want to know about the original version
+ fixed_ori = (forward['_orig_source_ori'] == FIFF.FIFFV_MNE_FIXED_ORI)
+ else: # most of the time we want to know about the current version
+ fixed_ori = (forward['source_ori'] == FIFF.FIFFV_MNE_FIXED_ORI)
+ return fixed_ori
def write_forward_meas_info(fid, info):
@@ -720,7 +810,7 @@ def write_forward_meas_info(fid, info):
----------
fid : file id
The file id
- info : dict
+ info : instance of mne.fiff.meas_info.Info
The measurement info.
"""
#
@@ -803,12 +893,12 @@ def _restrict_gain_matrix(G, info):
if not (len(info['chs']) == G.shape[0]):
raise ValueError("G.shape[0] and length of info['chs'] do not match: "
"%d != %d" % (G.shape[0], len(info['chs'])))
- sel = pick_types(info, meg='grad', exclude=[])
+ sel = pick_types(info, meg='grad', ref_meg=False, exclude=[])
if len(sel) > 0:
G = G[sel]
logger.info(' %d planar channels' % len(sel))
else:
- sel = pick_types(info, meg='mag', exclude=[])
+ sel = pick_types(info, meg='mag', ref_meg=False, exclude=[])
if len(sel) > 0:
G = G[sel]
logger.info(' %d magnetometer or axial gradiometer '
@@ -886,8 +976,8 @@ def _stc_src_sel(src, stc):
src_sel_lh = np.searchsorted(src[0]['vertno'], src_sel_lh)
src_sel_rh = np.intersect1d(src[1]['vertno'], stc.vertno[1])
- src_sel_rh = np.searchsorted(src[1]['vertno'], src_sel_rh)\
- + len(src[0]['vertno'])
+ src_sel_rh = (np.searchsorted(src[1]['vertno'], src_sel_rh)
+ + len(src[0]['vertno']))
src_sel = np.r_[src_sel_lh, src_sel_rh]
@@ -929,7 +1019,7 @@ def _apply_forward(fwd, stc, start=None, stop=None, verbose=None):
if np.all(stc.data > 0):
warnings.warn('Source estimate only contains currents with positive '
- 'values. Use pick_normal=True when computing the '
+ 'values. Use pick_ori="normal" when computing the '
'inverse to compute currents not current magnitudes.')
max_cur = np.max(np.abs(stc.data))
@@ -1175,8 +1265,8 @@ def restrict_forward_to_label(fwd, labels):
else:
i = 1
src_sel = np.intersect1d(fwd['src'][1]['vertno'], label.vertices)
- src_sel = np.searchsorted(fwd['src'][1]['vertno'], src_sel)\
- + len(fwd['src'][0]['vertno'])
+ src_sel = (np.searchsorted(fwd['src'][1]['vertno'], src_sel)
+ + len(fwd['src'][0]['vertno']))
fwd_out['source_rr'] = np.vstack([fwd_out['source_rr'],
fwd['source_rr'][src_sel]])
@@ -1207,10 +1297,10 @@ def do_forward_solution(subject, meas, fname=None, src=None, spacing=None,
eeg=True, meg=True, fixed=False, grad=False,
mricoord=False, overwrite=False, subjects_dir=None,
verbose=None):
- """Calculate a forward solution for a subject
+ """Calculate a forward solution for a subject using MNE-C routines
This function wraps to mne_do_forward_solution, so the mne
- command-line tools must be installed.
+ command-line tools must be installed and accessible from Python.
Parameters
----------
@@ -1226,8 +1316,10 @@ def do_forward_solution(subject, meas, fname=None, src=None, spacing=None,
will be created in a temporary directory, loaded, and deleted.
src : str | None
Source space name. If None, the MNE default is used.
- spacing : str | None
- Source space spacing to use. If None, the MNE default is used.
+ spacing : str
+ The spacing to use. Can be ``'#'`` for spacing in mm, ``'ico#'`` for a
+ recursively subdivided icosahedron, or ``'oct#'`` for a recursively
+ subdivided octahedron (e.g., ``spacing='ico4'``). Default is 7 mm.
mindist : float | str | None
Minimum distance of sources from inner skull surface (in mm).
If None, the MNE default value is used. If string, 'all'
@@ -1364,6 +1456,14 @@ def do_forward_solution(subject, meas, fname=None, src=None, spacing=None,
if src is not None:
cmd += ['--src', src]
if spacing is not None:
+ if spacing.isdigit():
+ pass # spacing in mm
+ else:
+ # allow both "ico4" and "ico-4" style values
+ match = re.match("(oct|ico)-?(\d+)$", spacing)
+ if match is None:
+ raise ValueError("Invalid spacing parameter: %r" % spacing)
+ spacing = '-'.join(match.groups())
cmd += ['--spacing', spacing]
if mindist is not None:
cmd += mindist
@@ -1397,7 +1497,7 @@ def do_forward_solution(subject, meas, fname=None, src=None, spacing=None,
except Exception as exception:
raise exception
else:
- fwd = read_forward_solution(op.join(path, fname))
+ fwd = read_forward_solution(op.join(path, fname), verbose=False)
finally:
shutil.rmtree(temp_dir, ignore_errors=True)
return fwd
@@ -1446,9 +1546,10 @@ def average_forward_solutions(fwds, weights=None):
if not isinstance(fwd, dict):
raise TypeError('Each entry in fwds must be a dict')
# check to make sure the dict is actually a fwd
- if not all([key in fwd for key in ['info', 'sol_grad', 'nchan',
- 'src', 'source_nn', 'sol', 'source_rr', 'source_ori',
- 'surf_ori', 'coord_frame', 'mri_head_t', 'nsource']]):
+ check_keys = ['info', 'sol_grad', 'nchan', 'src', 'source_nn', 'sol',
+ 'source_rr', 'source_ori', 'surf_ori', 'coord_frame',
+ 'mri_head_t', 'nsource']
+ if not all([key in fwd for key in check_keys]):
raise KeyError('forward solution dict does not have all standard '
'entries, cannot compute average.')
@@ -1460,9 +1561,17 @@ def average_forward_solutions(fwds, weights=None):
for k in ['source_ori', 'surf_ori', 'coord_frame']]):
raise ValueError('Forward solutions have incompatible orientations')
- # actually average them
+ # actually average them (solutions and gradients)
fwd_ave = deepcopy(fwds[0])
fwd_ave['sol']['data'] *= weights[0]
+ fwd_ave['_orig_sol'] *= weights[0]
for fwd, w in zip(fwds[1:], weights[1:]):
fwd_ave['sol']['data'] += w * fwd['sol']['data']
+ fwd_ave['_orig_sol'] += w * fwd['_orig_sol']
+ if fwd_ave['sol_grad'] is not None:
+ fwd_ave['sol_grad']['data'] *= weights[0]
+ fwd_ave['_orig_sol_grad'] *= weights[0]
+ for fwd, w in zip(fwds[1:], weights[1:]):
+ fwd_ave['sol_grad']['data'] += w * fwd['sol_grad']['data']
+ fwd_ave['_orig_sol_grad'] += w * fwd['_orig_sol_grad']
return fwd_ave
diff --git a/mne/tests/__init__.py b/mne/forward/tests/__init__.py
similarity index 100%
copy from mne/tests/__init__.py
copy to mne/forward/tests/__init__.py
diff --git a/mne/tests/test_forward.py b/mne/forward/tests/test_forward.py
similarity index 65%
rename from mne/tests/test_forward.py
rename to mne/forward/tests/test_forward.py
index 8dab51a..27f3bfd 100644
--- a/mne/tests/test_forward.py
+++ b/mne/forward/tests/test_forward.py
@@ -1,34 +1,35 @@
import os
import os.path as op
-from subprocess import CalledProcessError
import warnings
from nose.tools import assert_true, assert_raises
import numpy as np
-from numpy.testing import assert_array_almost_equal, assert_equal, \
- assert_array_equal, assert_allclose
+from numpy.testing import (assert_array_almost_equal, assert_equal,
+ assert_array_equal, assert_allclose)
from mne.datasets import sample
from mne.fiff import Raw, Evoked, pick_types_forward
-from mne import read_forward_solution, apply_forward, apply_forward_raw, \
- do_forward_solution, average_forward_solutions, \
- write_forward_solution
-from mne import SourceEstimate, read_trans
+from mne import (read_forward_solution, apply_forward, apply_forward_raw,
+ average_forward_solutions, write_forward_solution,
+ convert_forward_solution)
+from mne import SourceEstimate
from mne.label import read_label
from mne.utils import requires_mne, run_subprocess, _TempDir
from mne.forward import restrict_forward_to_stc, restrict_forward_to_label
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis-meg-oct-6-fwd.fif')
fname_meeg = op.join(data_path, 'MEG', 'sample',
'sample_audvis-meg-eeg-oct-6-fwd.fif')
-fname_raw = op.join(op.dirname(__file__), '..', 'fiff', 'tests', 'data',
+fname_raw = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data',
'test_raw.fif')
-fname_evoked = op.join(op.dirname(__file__), '..', 'fiff', 'tests', 'data',
- 'test-ave.fif')
+fname_evoked = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests',
+ 'data', 'test-ave.fif')
fname_mri = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw-trans.fif')
+subjects_dir = os.path.join(data_path, 'subjects')
+fname_src = op.join(subjects_dir, 'sample', 'bem', 'sample-oct-6-src.fif')
temp_dir = _TempDir()
# make a file that exists with some data in it
existing_file = op.join(temp_dir, 'test.fif')
@@ -36,6 +37,44 @@ with open(existing_file, 'wb') as fid:
fid.write('aoeu')
+def compare_forwards(f1, f2):
+ """Helper to compare two potentially converted forward solutions"""
+ assert_allclose(f1['sol']['data'], f2['sol']['data'])
+ assert_equal(f1['sol']['ncol'], f2['sol']['ncol'])
+ assert_allclose(f1['source_nn'], f2['source_nn'])
+ if f1['sol_grad'] is not None:
+ assert_allclose(f1['sol_grad']['data'], f2['sol_grad']['data'])
+ assert_equal(f1['sol_grad']['ncol'], f2['sol_grad']['ncol'])
+ else:
+ assert_equal(f2['sol_grad'], None)
+ assert_equal(f1['source_ori'], f2['source_ori'])
+ assert_equal(f1['surf_ori'], f2['surf_ori'])
+
+
+ at sample.requires_sample_data
+def test_convert_forward():
+ """Test converting forward solution between different representations
+ """
+ fwd = read_forward_solution(fname_meeg)
+ # look at surface orientation
+ fwd_surf = convert_forward_solution(fwd, surf_ori=True)
+ fwd_surf_io = read_forward_solution(fname_meeg, surf_ori=True)
+ compare_forwards(fwd_surf, fwd_surf_io)
+ # go back
+ fwd_new = convert_forward_solution(fwd_surf, surf_ori=False)
+ compare_forwards(fwd, fwd_new)
+ # now go to fixed
+ fwd_fixed = convert_forward_solution(fwd_surf, surf_ori=False,
+ force_fixed=True)
+ fwd_fixed_io = read_forward_solution(fname_meeg, surf_ori=False,
+ force_fixed=True)
+ compare_forwards(fwd_fixed, fwd_fixed_io)
+ # now go back to cartesian (original condition)
+ fwd_new = convert_forward_solution(fwd_fixed)
+ compare_forwards(fwd, fwd_new)
+
+
+ at sample.requires_sample_data
def test_io_forward():
"""Test IO for forward solutions
"""
@@ -79,6 +118,7 @@ def test_io_forward():
assert_true('mri_head_t' in fwd)
+ at sample.requires_sample_data
def test_apply_forward():
"""Test projection of source space data to sensor space
"""
@@ -123,6 +163,7 @@ def test_apply_forward():
assert_array_almost_equal(times[-1], t_start + (n_times - 1) / sfreq)
+ at sample.requires_sample_data
def test_restrict_forward_to_stc():
"""Test restriction of source space to source SourceEstimate
"""
@@ -163,6 +204,7 @@ def test_restrict_forward_to_stc():
assert_equal(fwd_out['src'][1]['vertno'], fwd['src'][1]['vertno'][0:5])
+ at sample.requires_sample_data
def test_restrict_forward_to_label():
"""Test restriction of source space to label
"""
@@ -180,8 +222,8 @@ def test_restrict_forward_to_label():
src_sel_lh = np.searchsorted(fwd['src'][0]['vertno'], src_sel_lh)
src_sel_rh = np.intersect1d(fwd['src'][1]['vertno'], label_rh.vertices)
- src_sel_rh = np.searchsorted(fwd['src'][1]['vertno'], src_sel_rh)\
- + len(fwd['src'][0]['vertno'])
+ src_sel_rh = (np.searchsorted(fwd['src'][1]['vertno'], src_sel_rh)
+ + len(fwd['src'][0]['vertno']))
assert_equal(fwd_out['sol']['ncol'], len(src_sel_lh) + len(src_sel_rh))
assert_equal(fwd_out['src'][0]['nuse'], len(src_sel_lh))
@@ -203,8 +245,8 @@ def test_restrict_forward_to_label():
src_sel_lh = np.searchsorted(fwd['src'][0]['vertno'], src_sel_lh)
src_sel_rh = np.intersect1d(fwd['src'][1]['vertno'], label_rh.vertices)
- src_sel_rh = np.searchsorted(fwd['src'][1]['vertno'], src_sel_rh)\
- + len(fwd['src'][0]['vertno'])
+ src_sel_rh = (np.searchsorted(fwd['src'][1]['vertno'], src_sel_rh)
+ + len(fwd['src'][0]['vertno']))
assert_equal(fwd_out['sol']['ncol'],
3 * (len(src_sel_lh) + len(src_sel_rh)))
@@ -214,6 +256,7 @@ def test_restrict_forward_to_label():
assert_equal(fwd_out['src'][1]['vertno'], src_sel_rh)
+ at sample.requires_sample_data
@requires_mne
def test_average_forward_solution():
"""Test averaging forward solutions
@@ -241,7 +284,7 @@ def test_average_forward_solution():
fname_copy = op.join(temp_dir, 'fwd.fif')
write_forward_solution(fname_copy, fwd_copy, overwrite=True)
cmd = ('mne_average_forward_solutions', '--fwd', fname, '--fwd',
- fname_copy, '--out' , fname_copy)
+ fname_copy, '--out', fname_copy)
run_subprocess(cmd)
# now let's actually do it, with one filename and one fwd
@@ -249,81 +292,3 @@ def test_average_forward_solution():
assert_array_equal(0.75 * fwd['sol']['data'], fwd_ave['sol']['data'])
# fwd_ave_mne = read_forward_solution(fname_copy)
# assert_array_equal(fwd_ave_mne['sol']['data'], fwd_ave['sol']['data'])
-
-
- at requires_mne
-def test_do_forward_solution():
- """Test making forward solution from python
- """
- subjects_dir = os.path.join(data_path, 'subjects')
-
- raw = Raw(fname_raw)
- mri = read_trans(fname_mri)
- fname_fake = op.join(temp_dir, 'no_have.fif')
-
- # ## Error checks
- # bad subject
- assert_raises(ValueError, do_forward_solution, 1, fname_raw,
- subjects_dir=subjects_dir)
- # bad meas
- assert_raises(ValueError, do_forward_solution, 'sample', 1,
- subjects_dir=subjects_dir)
- # meas doesn't exist
- assert_raises(IOError, do_forward_solution, 'sample', fname_fake,
- subjects_dir=subjects_dir)
- # don't specify trans and meas
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- subjects_dir=subjects_dir)
- # specify both trans and meas
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- trans='me', mri='you', subjects_dir=subjects_dir)
- # specify non-existent trans
- assert_raises(IOError, do_forward_solution, 'sample', fname_raw,
- trans=fname_fake, subjects_dir=subjects_dir)
- # specify non-existent mri
- assert_raises(IOError, do_forward_solution, 'sample', fname_raw,
- mri=fname_fake, subjects_dir=subjects_dir)
- # specify non-string mri
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- mri=1, subjects_dir=subjects_dir)
- # specify non-string trans
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- trans=1, subjects_dir=subjects_dir)
- # test specifying an actual trans in python space -- this should work but
- # the transform I/O reduces our accuracy -- so we'll just hack a test here
- # by making it bomb with eeg=False and meg=False
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- mri=mri, eeg=False, meg=False, subjects_dir=subjects_dir)
- # mindist as non-integer
- assert_raises(TypeError, do_forward_solution, 'sample', fname_raw,
- mri=fname_mri, mindist=dict(), subjects_dir=subjects_dir)
- # mindist as string but not 'all'
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- mri=fname_mri, eeg=False, mindist='yall',
- subjects_dir=subjects_dir)
- # src, spacing, and bem as non-str
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- mri=fname_mri, src=1, subjects_dir=subjects_dir)
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- mri=fname_mri, spacing=1, subjects_dir=subjects_dir)
- assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
- mri=fname_mri, bem=1, subjects_dir=subjects_dir)
- # no overwrite flag
- assert_raises(IOError, do_forward_solution, 'sample', fname_raw,
- existing_file, mri=fname_mri, subjects_dir=subjects_dir)
- # let's catch an MNE error, this time about trans being wrong
- assert_raises(CalledProcessError, do_forward_solution, 'sample', fname_raw,
- existing_file, trans=fname_mri, overwrite=True,
- spacing='oct-6', subjects_dir=subjects_dir)
-
- # ## Actually calculate one and check
- # make a meas from raw (tests all steps in creating evoked),
- # don't do EEG or 5120-5120-5120 BEM because they're ~3x slower
- fwd_py = do_forward_solution('sample', raw, mindist=5, spacing='oct-6',
- bem='sample-5120', mri=fname_mri, eeg=False,
- subjects_dir=subjects_dir)
- fwd = read_forward_solution(fname)
- assert_allclose(fwd['sol']['data'], fwd_py['sol']['data'],
- rtol=1e-5, atol=1e-8)
- assert_equal(fwd_py['sol']['data'].shape, (306, 22494))
- assert_equal(len(fwd['sol']['row_names']), 306)
diff --git a/mne/forward/tests/test_make_forward.py b/mne/forward/tests/test_make_forward.py
new file mode 100644
index 0000000..116a141
--- /dev/null
+++ b/mne/forward/tests/test_make_forward.py
@@ -0,0 +1,227 @@
+import os
+import os.path as op
+from subprocess import CalledProcessError
+
+from nose.tools import assert_raises
+from numpy.testing import (assert_equal, assert_allclose)
+
+from mne.datasets import sample
+from mne.fiff.kit import read_raw_kit
+from mne.fiff.bti import read_raw_bti
+from mne import (read_forward_solution, make_forward_solution,
+ do_forward_solution, setup_source_space, read_trans,
+ convert_forward_solution)
+from mne.utils import requires_mne, _TempDir
+from mne.tests.test_source_space import _compare_source_spaces
+
+data_path = sample.data_path(download=False)
+fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis-meg-oct-6-fwd.fif')
+fname_meeg = op.join(data_path, 'MEG', 'sample',
+ 'sample_audvis-meg-eeg-oct-6-fwd.fif')
+
+fname_raw = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data',
+ 'test_raw.fif')
+
+fname_evoked = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests',
+ 'data', 'test-ave.fif')
+fname_mri = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw-trans.fif')
+subjects_dir = os.path.join(data_path, 'subjects')
+temp_dir = _TempDir()
+
+# make a file that exists with some data in it
+existing_file = op.join(temp_dir, 'test.fif')
+with open(existing_file, 'wb') as fid:
+ fid.write('aoeu')
+
+
+def _compare_forwards(fwd, fwd_py, n_sensors, n_src,
+ meg_rtol=1e-4, meg_atol=1e-9):
+ """Helper to test forwards"""
+ # check source spaces
+ assert_equal(len(fwd['src']), len(fwd_py['src']))
+ _compare_source_spaces(fwd['src'], fwd_py['src'], mode='approx')
+ for surf_ori in [False, True]:
+ if surf_ori:
+ # use copy here to leave our originals unmodified
+ fwd = convert_forward_solution(fwd, surf_ori, copy=True)
+ fwd_py = convert_forward_solution(fwd, surf_ori, copy=True)
+
+ for key in ['nchan', 'source_nn', 'source_rr', 'source_ori',
+ 'surf_ori', 'coord_frame', 'nsource']:
+ print key
+ assert_allclose(fwd_py[key], fwd[key], rtol=1e-4, atol=1e-7)
+ assert_allclose(fwd_py['mri_head_t']['trans'],
+ fwd['mri_head_t']['trans'], rtol=1e-5, atol=1e-8)
+
+ assert_equal(fwd_py['sol']['data'].shape, (n_sensors, n_src))
+ assert_equal(len(fwd['sol']['row_names']), n_sensors)
+ assert_equal(len(fwd_py['sol']['row_names']), n_sensors)
+
+ # check MEG
+ print 'check MEG'
+ assert_allclose(fwd['sol']['data'][:306],
+ fwd_py['sol']['data'][:306],
+ rtol=meg_rtol, atol=meg_atol)
+ # check EEG
+ if fwd['sol']['data'].shape[0] > 306:
+ print 'check EEG'
+ assert_allclose(fwd['sol']['data'][306:],
+ fwd_py['sol']['data'][306:],
+ rtol=1e-3, atol=1e-3)
+
+
+ at sample.requires_sample_data
+ at requires_mne
+def test_make_forward_solution_kit():
+ """Test making fwd using KIT, BTI, and CTF (compensated) files
+ """
+ fname_bem = op.join(subjects_dir, 'sample', 'bem',
+ 'sample-5120-bem-sol.fif')
+ kit_dir = op.join(op.dirname(__file__), '..', '..', 'fiff', 'kit',
+ 'tests', 'data')
+ sqd_path = op.join(kit_dir, 'test.sqd')
+ mrk_path = op.join(kit_dir, 'test_mrk.sqd')
+ elp_path = op.join(kit_dir, 'test_elp.txt')
+ hsp_path = op.join(kit_dir, 'test_hsp.txt')
+ mri_path = op.join(kit_dir, 'trans-sample.fif')
+ fname_kit_raw = op.join(kit_dir, 'test_bin.fif')
+
+ bti_dir = op.join(op.dirname(__file__), '..', '..', 'fiff', 'bti',
+ 'tests', 'data')
+ bti_pdf = op.join(bti_dir, 'test_pdf_linux')
+ bti_config = op.join(bti_dir, 'test_config_linux')
+ bti_hs = op.join(bti_dir, 'test_hs_linux')
+ fname_bti_raw = op.join(bti_dir, 'exported4D_linux.fif')
+
+ fname_ctf_raw = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests',
+ 'data', 'test_ctf_comp_raw.fif')
+
+ # first set up a testing source space
+ fname_src = op.join(temp_dir, 'oct2-src.fif')
+ src = setup_source_space('sample', fname_src, 'oct2',
+ subjects_dir=subjects_dir)
+
+ # first use mne-C: convert file, make forward solution
+ fwd = do_forward_solution('sample', fname_kit_raw, src=fname_src,
+ mindist=0.0, bem=fname_bem, mri=mri_path,
+ eeg=False, meg=True, subjects_dir=subjects_dir)
+
+ # now let's use python with the same raw file
+ fwd_py = make_forward_solution(fname_kit_raw, mindist=0.0,
+ src=src, eeg=False, meg=True,
+ bem=fname_bem, mri=mri_path)
+ _compare_forwards(fwd, fwd_py, 157, 108)
+
+ # now let's use mne-python all the way
+ raw_py = read_raw_kit(sqd_path, mrk_path, elp_path, hsp_path)
+ # without ignore_ref=True, this should throw an error:
+ assert_raises(NotImplementedError, make_forward_solution, raw_py.info,
+ mindist=0.0, src=src, eeg=False, meg=True,
+ bem=fname_bem, mri=mri_path)
+ fwd_py = make_forward_solution(raw_py.info, mindist=0.0,
+ src=src, eeg=False, meg=True,
+ bem=fname_bem, mri=mri_path,
+ ignore_ref=True)
+ _compare_forwards(fwd, fwd_py, 157, 108,
+ meg_rtol=1e-3, meg_atol=1e-7)
+
+ # BTI python end-to-end versus C
+ fwd = do_forward_solution('sample', fname_bti_raw, src=fname_src,
+ mindist=0.0, bem=fname_bem, mri=mri_path,
+ eeg=False, meg=True, subjects_dir=subjects_dir)
+ raw_py = read_raw_bti(bti_pdf, bti_config, bti_hs)
+ fwd_py = make_forward_solution(raw_py.info, mindist=0.0,
+ src=src, eeg=False, meg=True,
+ bem=fname_bem, mri=mri_path)
+ _compare_forwards(fwd, fwd_py, 248, 108)
+
+ # now let's test CTF w/compensation
+ fwd_py = make_forward_solution(fname_ctf_raw, mindist=0.0,
+ src=src, eeg=False, meg=True,
+ bem=fname_bem, mri=fname_mri)
+
+ fwd = do_forward_solution('sample', fname_ctf_raw, src=fname_src,
+ mindist=0.0, bem=fname_bem, mri=fname_mri,
+ eeg=False, meg=True, subjects_dir=subjects_dir)
+ _compare_forwards(fwd, fwd_py, 274, 108)
+
+
+ at sample.requires_sample_data
+def test_make_forward_solution():
+ """Test making M-EEG forward solution from python
+ """
+ fname_src = op.join(subjects_dir, 'sample', 'bem', 'sample-oct-6-src.fif')
+ fname_bem = op.join(subjects_dir, 'sample', 'bem',
+ 'sample-5120-5120-5120-bem-sol.fif')
+ fwd_py = make_forward_solution(fname_raw, mindist=5.0,
+ src=fname_src, eeg=True, meg=True,
+ bem=fname_bem, mri=fname_mri)
+ fwd = read_forward_solution(fname_meeg)
+ _compare_forwards(fwd, fwd_py, 366, 22494)
+
+
+ at sample.requires_sample_data
+ at requires_mne
+def test_do_forward_solution():
+ """Test wrapping forward solution from python
+ """
+ mri = read_trans(fname_mri)
+ fname_fake = op.join(temp_dir, 'no_have.fif')
+
+ # ## Error checks
+ # bad subject
+ assert_raises(ValueError, do_forward_solution, 1, fname_raw,
+ subjects_dir=subjects_dir)
+ # bad meas
+ assert_raises(ValueError, do_forward_solution, 'sample', 1,
+ subjects_dir=subjects_dir)
+ # meas doesn't exist
+ assert_raises(IOError, do_forward_solution, 'sample', fname_fake,
+ subjects_dir=subjects_dir)
+ # don't specify trans and meas
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ subjects_dir=subjects_dir)
+ # specify both trans and meas
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ trans='me', mri='you', subjects_dir=subjects_dir)
+ # specify non-existent trans
+ assert_raises(IOError, do_forward_solution, 'sample', fname_raw,
+ trans=fname_fake, subjects_dir=subjects_dir)
+ # specify non-existent mri
+ assert_raises(IOError, do_forward_solution, 'sample', fname_raw,
+ mri=fname_fake, subjects_dir=subjects_dir)
+ # specify non-string mri
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ mri=1, subjects_dir=subjects_dir)
+ # specify non-string trans
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ trans=1, subjects_dir=subjects_dir)
+ # test specifying an actual trans in python space -- this should work but
+ # the transform I/O reduces our accuracy -- so we'll just hack a test here
+ # by making it bomb with eeg=False and meg=False
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ mri=mri, eeg=False, meg=False, subjects_dir=subjects_dir)
+ # mindist as non-integer
+ assert_raises(TypeError, do_forward_solution, 'sample', fname_raw,
+ mri=fname_mri, mindist=dict(), subjects_dir=subjects_dir)
+ # mindist as string but not 'all'
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ mri=fname_mri, eeg=False, mindist='yall',
+ subjects_dir=subjects_dir)
+ # src, spacing, and bem as non-str
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ mri=fname_mri, src=1, subjects_dir=subjects_dir)
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ mri=fname_mri, spacing=1, subjects_dir=subjects_dir)
+ assert_raises(ValueError, do_forward_solution, 'sample', fname_raw,
+ mri=fname_mri, bem=1, subjects_dir=subjects_dir)
+ # no overwrite flag
+ assert_raises(IOError, do_forward_solution, 'sample', fname_raw,
+ existing_file, mri=fname_mri, subjects_dir=subjects_dir)
+ # let's catch an MNE error, this time about trans being wrong
+ assert_raises(CalledProcessError, do_forward_solution, 'sample',
+ fname_raw, existing_file, trans=fname_mri, overwrite=True,
+ spacing='oct6', subjects_dir=subjects_dir)
+
+ # No need to actually calculate and check here, since it's effectively
+ # done in previous tests.
diff --git a/mne/inverse_sparse/_gamma_map.py b/mne/inverse_sparse/_gamma_map.py
index eeaf3c1..f26b839 100644
--- a/mne/inverse_sparse/_gamma_map.py
+++ b/mne/inverse_sparse/_gamma_map.py
@@ -6,13 +6,10 @@ from copy import deepcopy
import numpy as np
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
from ..forward import is_fixed_orient, _to_fixed_ori
from ..fiff.pick import pick_channels_evoked
from ..minimum_norm.inverse import _prepare_forward
-from .. import verbose
+from ..utils import logger, verbose
from .mxne_inverse import _make_sparse_stc, _prepare_gain
diff --git a/mne/inverse_sparse/mxne_debiasing.py b/mne/inverse_sparse/mxne_debiasing.py
index c794ea4..f49a89d 100755
--- a/mne/inverse_sparse/mxne_debiasing.py
+++ b/mne/inverse_sparse/mxne_debiasing.py
@@ -7,11 +7,7 @@ from math import sqrt
import numpy as np
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
-from ..utils import check_random_state
-from .. import verbose
+from ..utils import check_random_state, logger, verbose
def power_iteration_kron(A, C, max_iter=1000, tol=1e-3, random_state=0):
diff --git a/mne/inverse_sparse/mxne_inverse.py b/mne/inverse_sparse/mxne_inverse.py
index 4932653..8d32591 100644
--- a/mne/inverse_sparse/mxne_inverse.py
+++ b/mne/inverse_sparse/mxne_inverse.py
@@ -6,15 +6,12 @@ from copy import deepcopy
import numpy as np
from scipy import linalg, signal
-import logging
-logger = logging.getLogger('mne')
-
from ..source_estimate import SourceEstimate
from ..minimum_norm.inverse import combine_xyz, _prepare_forward
from ..forward import compute_orient_prior, is_fixed_orient, _to_fixed_ori
from ..fiff.pick import pick_channels_evoked
from .mxne_optim import mixed_norm_solver, norm_l2inf, tf_mixed_norm_solver
-from .. import verbose
+from ..utils import logger, verbose
@verbose
diff --git a/mne/inverse_sparse/mxne_optim.py b/mne/inverse_sparse/mxne_optim.py
index 64acea5..92429b7 100644
--- a/mne/inverse_sparse/mxne_optim.py
+++ b/mne/inverse_sparse/mxne_optim.py
@@ -7,11 +7,8 @@ from math import sqrt, ceil
import numpy as np
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
from .mxne_debiasing import compute_bias
-from .. import verbose
+from ..utils import logger, verbose, sum_squared
from ..time_frequency.stft import stft_norm2, stft, istft
@@ -165,7 +162,7 @@ def dgap_l21(M, G, X, active_set, alpha, n_orient):
GX = np.dot(G[:, active_set], X)
R = M - GX
penalty = norm_l21(X, n_orient, copy=True)
- nR2 = np.sum(R ** 2)
+ nR2 = sum_squared(R)
pobj = 0.5 * nR2 + alpha * penalty
dual_norm = norm_l2inf(np.dot(G.T, R), n_orient, copy=False)
scaling = alpha / dual_norm
@@ -251,8 +248,11 @@ def _mixed_norm_solver_cd(M, G, alpha, maxit=10000, tol=1e-8,
init = init.T
clf = MultiTaskLasso(alpha=alpha / len(M), tol=tol, normalize=False,
- fit_intercept=False, max_iter=maxit).fit(G, M,
- coef_init=init)
+ fit_intercept=False, max_iter=maxit,
+ warm_start=True)
+ clf.coef_ = init
+ clf.fit(G, M)
+
X = clf.coef_.T
active_set = np.any(X, axis=1)
X = X[active_set]
diff --git a/mne/inverse_sparse/tests/test_gamma_map.py b/mne/inverse_sparse/tests/test_gamma_map.py
index c6bc337..ce134bf 100644
--- a/mne/inverse_sparse/tests/test_gamma_map.py
+++ b/mne/inverse_sparse/tests/test_gamma_map.py
@@ -12,23 +12,23 @@ from mne.datasets import sample
from mne import fiff, read_cov, read_forward_solution
from mne.inverse_sparse import gamma_map
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
fname_evoked = op.join(data_path, 'MEG', 'sample', 'sample_audvis-ave.fif')
fname_cov = op.join(data_path, 'MEG', 'sample', 'sample_audvis-cov.fif')
fname_fwd = op.join(data_path, 'MEG', 'sample',
'sample_audvis-eeg-oct-6-fwd.fif')
-forward = read_forward_solution(fname_fwd, force_fixed=False, surf_ori=True)
-evoked = fiff.Evoked(fname_evoked, setno=0, baseline=(None, 0))
-evoked.crop(tmin=0, tmax=0.3)
-
-cov = read_cov(fname_cov)
-cov = mne.cov.regularize(cov, evoked.info)
-
-
+ at sample.requires_sample_data
def test_gamma_map():
"""Test Gamma MAP inverse"""
+ forward = read_forward_solution(fname_fwd, force_fixed=False,
+ surf_ori=True)
+ evoked = fiff.Evoked(fname_evoked, setno=0, baseline=(None, 0))
+ evoked.crop(tmin=0, tmax=0.3)
+
+ cov = read_cov(fname_cov)
+ cov = mne.cov.regularize(cov, evoked.info)
alpha = 0.2
stc = gamma_map(evoked, forward, cov, alpha, tol=1e-5,
diff --git a/mne/inverse_sparse/tests/test_mxne_debiasing.py b/mne/inverse_sparse/tests/test_mxne_debiasing.py
index e48795a..a2c3458 100755
--- a/mne/inverse_sparse/tests/test_mxne_debiasing.py
+++ b/mne/inverse_sparse/tests/test_mxne_debiasing.py
@@ -6,7 +6,7 @@
import numpy as np
from numpy.testing import assert_almost_equal
-from mne.inverse_sparse.mnxe_debiasing import compute_bias
+from mne.inverse_sparse.mxne_debiasing import compute_bias
def test_compute_debiasing():
diff --git a/mne/inverse_sparse/tests/test_mxne_inverse.py b/mne/inverse_sparse/tests/test_mxne_inverse.py
index 42853de..93aca04 100644
--- a/mne/inverse_sparse/tests/test_mxne_inverse.py
+++ b/mne/inverse_sparse/tests/test_mxne_inverse.py
@@ -16,7 +16,7 @@ from mne.inverse_sparse import mixed_norm, tf_mixed_norm
from mne.minimum_norm import apply_inverse, make_inverse_operator
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
fname_data = op.join(data_path, 'MEG', 'sample', 'sample_audvis-ave.fif')
fname_cov = op.join(data_path, 'MEG', 'sample', 'sample_audvis-cov.fif')
fname_fwd = op.join(data_path, 'MEG', 'sample',
@@ -24,40 +24,41 @@ fname_fwd = op.join(data_path, 'MEG', 'sample',
label = 'Aud-rh'
fname_label = op.join(data_path, 'MEG', 'sample', 'labels', '%s.label' % label)
-evoked = fiff.Evoked(fname_data, setno=1, baseline=(None, 0))
-
-# Read noise covariance matrix
-cov = read_cov(fname_cov)
-
-# Handling average file
-setno = 0
-loose = None
-depth = 0.9
-
-evoked = fiff.read_evoked(fname_data, setno=setno, baseline=(None, 0))
-evoked.crop(tmin=-0.1, tmax=0.4)
-
-evoked_l21 = copy.deepcopy(evoked)
-evoked_l21.crop(tmin=0.08, tmax=0.1)
-
-# Handling forward solution
-forward = read_forward_solution(fname_fwd, force_fixed=False, surf_ori=True)
-label = read_label(fname_label)
-
-# Reduce source space to make test computation faster
-inverse_operator = make_inverse_operator(evoked.info, forward, cov,
- loose=loose, depth=depth,
- fixed=True)
-stc_dspm = apply_inverse(evoked_l21, inverse_operator, lambda2=1. / 9.,
- method='dSPM')
-del inverse_operator
-stc_dspm.data[np.abs(stc_dspm.data) < 12] = 0.0
-stc_dspm.data[np.abs(stc_dspm.data) >= 12] = 1.
-weights_min = 0.5
-
+ at sample.requires_sample_data
def test_mxne_inverse():
- """Test MxNE inverse computation"""
+ """Test (TF-)MxNE inverse computation"""
+ # Handling forward solution
+ evoked = fiff.Evoked(fname_data, setno=1, baseline=(None, 0))
+
+ # Read noise covariance matrix
+ cov = read_cov(fname_cov)
+
+ # Handling average file
+ setno = 0
+ loose = None
+ depth = 0.9
+
+ evoked = fiff.read_evoked(fname_data, setno=setno, baseline=(None, 0))
+ evoked.crop(tmin=-0.1, tmax=0.4)
+
+ evoked_l21 = copy.deepcopy(evoked)
+ evoked_l21.crop(tmin=0.08, tmax=0.1)
+ label = read_label(fname_label)
+ weights_min = 0.5
+ forward = read_forward_solution(fname_fwd, force_fixed=False,
+ surf_ori=True)
+
+ # Reduce source space to make test computation faster
+ inverse_operator = make_inverse_operator(evoked.info, forward, cov,
+ loose=loose, depth=depth,
+ fixed=True)
+ stc_dspm = apply_inverse(evoked_l21, inverse_operator, lambda2=1. / 9.,
+ method='dSPM')
+ stc_dspm.data[np.abs(stc_dspm.data) < 12] = 0.0
+ stc_dspm.data[np.abs(stc_dspm.data) >= 12] = 1.
+
+ # MxNE tests
alpha = 60 # spatial regularization parameter
stc_prox = mixed_norm(evoked_l21, forward, cov, alpha, loose=None,
@@ -80,9 +81,7 @@ def test_mxne_inverse():
assert_array_almost_equal(stc.times, evoked_l21.times, 5)
assert_true(stc.vertno[1][0] in label.vertices)
-
-def test_tf_mxne_inverse():
- """Test TF-MxNE inverse computation"""
+ # Do with TF-MxNE for test memory savings
alpha_space = 60. # spatial regularization parameter
alpha_time = 1. # temporal regularization parameter
diff --git a/mne/inverse_sparse/tests/test_mxne_optim.py b/mne/inverse_sparse/tests/test_mxne_optim.py
index 714296e..21af4f4 100644
--- a/mne/inverse_sparse/tests/test_mxne_optim.py
+++ b/mne/inverse_sparse/tests/test_mxne_optim.py
@@ -6,7 +6,10 @@ import numpy as np
import warnings
from numpy.testing import assert_array_equal, assert_array_almost_equal
-from mne.inverse_sparse.mxne_optim import mixed_norm_solver, tf_mixed_norm_solver
+from mne.inverse_sparse.mxne_optim import (mixed_norm_solver,
+ tf_mixed_norm_solver)
+
+warnings.simplefilter('always') # enable b/c these tests throw warnings
def _generate_tf_data():
@@ -67,7 +70,7 @@ def test_l21_mxne():
n_orient=2, solver='prox')
assert_array_equal(np.where(active_set)[0], [0, 1, 4, 5])
# suppress a coordinate-descent warning here
- with warnings.catch_warnings(True) as w:
+ with warnings.catch_warnings(True):
X_hat_cd, active_set, _ = mixed_norm_solver(M,
G, alpha, maxit=1000, tol=1e-8,
active_set_size=2, debias=True,
@@ -80,7 +83,8 @@ def test_l21_mxne():
active_set_size=2, debias=True,
n_orient=5)
assert_array_equal(np.where(active_set)[0], [0, 1, 2, 3, 4])
- X_hat_cd, active_set, _ = mixed_norm_solver(M,
+ with warnings.catch_warnings(True): # coordinate-ascent warning
+ X_hat_cd, active_set, _ = mixed_norm_solver(M,
G, alpha, maxit=1000, tol=1e-8,
active_set_size=2, debias=True,
n_orient=5, solver='cd')
diff --git a/mne/label.py b/mne/label.py
index 17ab7ab..45398a7 100644
--- a/mne/label.py
+++ b/mne/label.py
@@ -11,14 +11,12 @@ import numpy as np
import re
from scipy import linalg, sparse
-import logging
-logger = logging.getLogger('mne')
-
-from .utils import get_subjects_dir, _check_subject
-from .source_estimate import _read_stc, mesh_edges, mesh_dist, morph_data, \
- SourceEstimate
+from .utils import get_subjects_dir, _check_subject, logger, verbose
+from .source_estimate import (_read_stc, mesh_edges, mesh_dist, morph_data,
+ SourceEstimate, spatial_src_connectivity)
from .surface import read_surface
-from . import verbose
+from .parallel import parallel_func, check_n_jobs
+from .stats.cluster_level import _find_clusters
class Label(object):
@@ -73,6 +71,10 @@ class Label(object):
if not isinstance(hemi, basestring):
raise ValueError('hemi must be a string, not %s' % type(hemi))
vertices = np.asarray(vertices)
+ if np.any(np.diff(vertices.astype(int)) <= 0):
+ raise ValueError('Vertices must be ordered in increasing '
+ 'order.')
+
if values is None:
values = np.ones(len(vertices))
if pos is None:
@@ -185,6 +187,9 @@ class Label(object):
name0 = self.name if self.name else 'unnamed'
name1 = other.name if other.name else 'unnamed'
+ indcs = np.argsort(vertices)
+ vertices, pos, values = vertices[indcs], pos[indcs, :], values[indcs]
+
label = Label(vertices, pos=pos, values=values, hemi=self.hemi,
comment="%s + %s" % (self.comment, other.comment),
name="%s + %s" % (name0, name1))
@@ -447,8 +452,16 @@ def read_label(filename, subject=None):
' with lh.label or rh.label')
fid.close()
- label = Label(vertices=np.array(data[0], dtype=np.int32),
- pos=1e-3 * data[1:4].T, values=data[4], hemi=hemi,
+ # let's make sure everything is ordered correctly
+ vertices = np.array(data[0], dtype=np.int32)
+ pos = 1e-3 * data[1:4].T
+ values = data[4]
+ order = np.argsort(vertices)
+ vertices = vertices[order]
+ pos = pos[order]
+ values = values[order]
+
+ label = Label(vertices=vertices, pos=pos, values=values, hemi=hemi,
comment=comment, filename=filename, subject=subject)
return label
@@ -569,7 +582,7 @@ def label_sign_flip(label, src):
return flip
-def stc_to_label(stc, src=None, smooth=5, subjects_dir=None):
+def stc_to_label(stc, src=None, smooth=5, connected=False, subjects_dir=None):
"""Compute a label from the non-zero sources in an stc object.
Parameters
@@ -582,13 +595,22 @@ def stc_to_label(stc, src=None, smooth=5, subjects_dir=None):
Can be None if stc.subject is not None.
smooth : int
Number of smoothing steps to use.
+ connected : bool
+ If True a list of connected labels will be returned in each
+ hemisphere. The labels are ordered in decreasing order depending
+ of the maximum value in the stc.
subjects_dir : string, or None
Path to SUBJECTS_DIR if it is not set in the environment.
Returns
-------
- labels : list of Labels
- The generated labels. One per hemisphere containing sources.
+ labels : list of Labels | list of list of Labels
+ The generated labels. If connected is False, it returns
+ a list of Labels (One per hemisphere). If no Label is available
+ in an hemisphere, None is returned. If connected is True,
+ it returns for each hemisphere a list of connected labels
+ ordered in decreasing order depending of the maximum value in the stc.
+ If no Label is available in an hemisphere, an empty list is returned.
"""
src = stc.subject if src is None else src
if src is None:
@@ -598,7 +620,7 @@ def stc_to_label(stc, src=None, smooth=5, subjects_dir=None):
else:
subject = stc.subject
- if not stc.is_surface():
+ if not isinstance(stc, SourceEstimate):
raise ValueError('SourceEstimate should be surface source estimates')
if isinstance(src, basestring):
@@ -610,40 +632,81 @@ def stc_to_label(stc, src=None, smooth=5, subjects_dir=None):
'rh.white'))
rr = [rr_lh, rr_rh]
tris = [tris_lh, tris_rh]
+ if connected:
+ raise ValueError('The option to return only connected labels'
+ ' is only available if a source space is passed'
+ ' as parameter.')
else:
if len(src) != 2:
raise ValueError('source space should contain the 2 hemispheres')
- tris = [src[0]['tris'], src[1]['tris']]
rr = [1e3 * src[0]['rr'], 1e3 * src[1]['rr']]
+ tris = [src[0]['tris'], src[1]['tris']]
+ src_conn = spatial_src_connectivity(src).tocsr()
labels = []
cnt = 0
- for hemi, this_vertno, this_tris, this_rr in \
- zip(['lh', 'rh'], stc.vertno, tris, rr):
- if len(this_vertno) == 0:
- continue
+ cnt_full = 0
+ for hemi_idx, (hemi, this_vertno, this_tris, this_rr) in enumerate(
+ zip(['lh', 'rh'], stc.vertno, tris, rr)):
+
+ this_data = stc.data[cnt:cnt + len(this_vertno)]
+
e = mesh_edges(this_tris)
e.data[e.data == 2] = 1
n_vertices = e.shape[0]
- this_data = stc.data[cnt:cnt + len(this_vertno)]
- cnt += len(this_vertno)
e = e + sparse.eye(n_vertices, n_vertices)
- idx_use = this_vertno[np.any(this_data, axis=1)]
- if len(idx_use) == 0:
- continue
- for k in range(smooth):
- e_use = e[:, idx_use]
- data1 = e_use * np.ones(len(idx_use))
- idx_use = np.where(data1)[0]
-
- label = Label(vertices=idx_use,
- pos=this_rr[idx_use],
- values=np.ones(len(idx_use)),
- hemi=hemi,
- comment='Label from stc',
- subject=subject)
- labels.append(label)
+ if connected:
+ if not isinstance(src, basestring): # XXX : ugly
+ inuse = np.where(src[hemi_idx]['inuse'])[0]
+ tmp = np.zeros((len(inuse), this_data.shape[1]))
+ this_vertno_idx = np.searchsorted(inuse, this_vertno)
+ tmp[this_vertno_idx] = this_data
+ this_data = tmp
+ offset = cnt_full + len(this_data)
+ this_src_conn = src_conn[cnt_full:offset, cnt_full:offset].tocoo()
+ this_data_abs_max = np.abs(this_data).max(axis=1)
+ clusters, _ = _find_clusters(this_data_abs_max, 0.,
+ connectivity=this_src_conn)
+ cnt_full += len(this_data)
+ # Then order clusters in descending order based on maximum value
+ clusters_max = np.argsort([np.max(this_data_abs_max[c])
+ for c in clusters])[::-1]
+ clusters = [clusters[k] for k in clusters_max]
+ clusters = [inuse[c] for c in clusters]
+ else:
+ clusters = [this_vertno[np.any(this_data, axis=1)]]
+
+ cnt += len(this_vertno)
+
+ clusters = [c for c in clusters if len(c) > 0]
+
+ if len(clusters) == 0:
+ if not connected:
+ this_labels = None
+ else:
+ this_labels = []
+ else:
+ this_labels = []
+ for c in clusters:
+ idx_use = c
+ for k in range(smooth):
+ e_use = e[:, idx_use]
+ data1 = e_use * np.ones(len(idx_use))
+ idx_use = np.where(data1)[0]
+
+ label = Label(vertices=idx_use,
+ pos=this_rr[idx_use],
+ values=np.ones(len(idx_use)),
+ hemi=hemi,
+ comment='Label from stc',
+ subject=subject)
+ this_labels.append(label)
+
+ if not connected:
+ this_labels = this_labels[0]
+
+ labels.append(this_labels)
return labels
@@ -696,7 +759,26 @@ def _verts_within_dist(graph, source, max_dist):
return verts, dist
-def grow_labels(subject, seeds, extents, hemis, subjects_dir=None):
+def _grow_labels(seeds, extents, hemis, dist, vert):
+ """Helper for parallelization of grow_labels
+ """
+ labels = []
+ for seed, extent, hemi in zip(seeds, extents, hemis):
+ label_verts, label_dist = _verts_within_dist(dist[hemi], seed, extent)
+
+ # create a label
+ comment = 'Circular label: seed=%d, extent=%0.1fmm' % (seed, extent)
+ label = Label(vertices=label_verts,
+ pos=vert[hemi][label_verts],
+ values=label_dist,
+ hemi=hemi,
+ comment=comment)
+ labels.append(label)
+ return labels
+
+
+def grow_labels(subject, seeds, extents, hemis, subjects_dir=None,
+ n_jobs=1):
"""Generate circular labels in source space with region growing
This function generates a number of labels in source space by growing
@@ -712,15 +794,18 @@ def grow_labels(subject, seeds, extents, hemis, subjects_dir=None):
Parameters
----------
subject : string
- Name of the subject as in SUBJECTS_DIR
+ Name of the subject as in SUBJECTS_DIR.
seeds : array or int
- Seed vertex numbers
+ Seed vertex numbers.
extents : array or float
- Extents (radius in mm) of the labels
+ Extents (radius in mm) of the labels.
hemis : array or int
- Hemispheres to use for the labels (0: left, 1: right)
+ Hemispheres to use for the labels (0: left, 1: right).
subjects_dir : string
- Path to SUBJECTS_DIR if not set in the environment
+ Path to SUBJECTS_DIR if not set in the environment.
+ n_jobs : int
+ Number of jobs to run in parallel. Likely only useful if tens
+ or hundreds of labels are being expanded simultaneously.
Returns
-------
@@ -730,6 +815,7 @@ def grow_labels(subject, seeds, extents, hemis, subjects_dir=None):
"""
subjects_dir = get_subjects_dir(subjects_dir)
+ n_jobs = check_n_jobs(n_jobs)
# make sure the inputs are arrays
seeds = np.atleast_1d(seeds)
@@ -763,19 +849,12 @@ def grow_labels(subject, seeds, extents, hemis, subjects_dir=None):
dist[hemi] = mesh_dist(tris[hemi], vert[hemi])
# create the patches
- labels = []
- for seed, extent, hemi in zip(seeds, extents, hemis):
- label_verts, label_dist = _verts_within_dist(dist[hemi], seed, extent)
-
- # create a label
- comment = 'Circular label: seed=%d, extent=%0.1fmm' % (seed, extent)
- label = Label(vertices=label_verts,
- pos=vert[hemi][label_verts],
- values=label_dist,
- hemi=hemi,
- comment=comment)
- labels.append(label)
-
+ parallel, my_grow_labels, _ = parallel_func(_grow_labels, n_jobs)
+ seeds = np.array_split(seeds, n_jobs)
+ extents = np.array_split(extents, n_jobs)
+ hemis = np.array_split(hemis, n_jobs)
+ labels = sum(parallel(my_grow_labels(s, e, h, dist, vert)
+ for s, e, h in zip(seeds, extents, hemis)), [])
return labels
@@ -793,7 +872,7 @@ def _read_annot(fname):
-------
annot : numpy array, shape=(n_verts)
Annotation id at each vertex
- ctab : numpy array, shape=(n_verts, 5)
+ ctab : numpy array, shape=(n_entries, 5)
RGBA + label id colortable array
names : list of str
List of region names as stored in the annot file
@@ -815,7 +894,7 @@ def _read_annot(fname):
with open(fname, "rb") as fid:
n_verts = np.fromfile(fid, '>i4', 1)[0]
data = np.fromfile(fid, '>i4', n_verts * 2).reshape(n_verts, 2)
- annot = data[:, 1]
+ annot = data[data[:, 0], 1]
ctab_exists = np.fromfile(fid, '>i4', 1)[0]
if not ctab_exists:
raise Exception('Color table not found in annotation file')
@@ -853,15 +932,45 @@ def _read_annot(fname):
ctab[i, :4] = np.fromfile(fid, '>i4', 4)
ctab[i, 4] = (ctab[i, 0] + ctab[i, 1] * (2 ** 8) +
ctab[i, 2] * (2 ** 16))
- ctab[:, 3] = 255
+
+ # convert to more common alpha value
+ ctab[:, 3] = 255 - ctab[:, 3]
return annot, ctab, names
+def _get_annot_fname(annot_fname, subject, hemi, parc, subjects_dir):
+ """Helper function to get the .annot filenames and hemispheres"""
+ if annot_fname is not None:
+ # we use use the .annot file specified by the user
+ hemis = [op.basename(annot_fname)[:2]]
+ if hemis[0] not in ['lh', 'rh']:
+ raise ValueError('Could not determine hemisphere from filename, '
+ 'filename has to start with "lh" or "rh".')
+ annot_fname = [annot_fname]
+ else:
+ # construct .annot file names for requested subject, parc, hemi
+ if hemi not in ['lh', 'rh', 'both']:
+ raise ValueError('hemi has to be "lh", "rh", or "both"')
+ if hemi == 'both':
+ hemis = ['lh', 'rh']
+ else:
+ hemis = [hemi]
+
+ annot_fname = list()
+ for hemi in hemis:
+ fname = op.join(subjects_dir, subject, 'label',
+ '%s.%s.annot' % (hemi, parc))
+ annot_fname.append(fname)
+
+ return annot_fname, hemis
+
+
+ at verbose
def labels_from_parc(subject, parc='aparc', hemi='both', surf_name='white',
annot_fname=None, regexp=None, subjects_dir=None,
verbose=None):
- """ Read labels from FreeSurfer parcellation
+ """Read labels from FreeSurfer parcellation
Note: Only cortical labels will be returned.
@@ -899,26 +1008,8 @@ def labels_from_parc(subject, parc='aparc', hemi='both', surf_name='white',
subjects_dir = get_subjects_dir(subjects_dir)
# get the .annot filenames and hemispheres
- if annot_fname is not None:
- # we use use the .annot file specified by the user
- hemis = [op.basename(annot_fname)[:2]]
- if hemis[0] not in ['lh', 'rh']:
- raise ValueError('Could not determine hemisphere from filename, '
- 'filename has to start with "lh" or "rh".')
- annot_fname = [annot_fname]
- else:
- # construct .annot file names for requested subject, parc, hemi
- if hemi not in ['lh', 'rh', 'both']:
- raise ValueError('hemi has to be "lh", "rh", or "both"')
- if hemi == 'both':
- hemis = ['lh', 'rh']
- else:
- hemis = [hemi]
- annot_fname = list()
- for hemi in hemis:
- fname = op.join(subjects_dir, subject, 'label',
- '%s.%s.annot' % (hemi, parc))
- annot_fname.append(fname)
+ annot_fname, hemis = _get_annot_fname(annot_fname, subject, hemi, parc,
+ subjects_dir)
# now we are ready to create the labels
n_read = 0
@@ -944,7 +1035,8 @@ def labels_from_parc(subject, parc='aparc', hemi='both', surf_name='white',
pos = vert_pos[vertices, :]
values = np.zeros(len(vertices))
name = label_name + '-' + hemi
- label = Label(vertices, pos, values, hemi, name=name)
+ label = Label(vertices, pos, values, hemi, name=name,
+ subject=subject)
labels.append(label)
# store the color
@@ -974,3 +1066,163 @@ def labels_from_parc(subject, parc='aparc', hemi='both', surf_name='white',
logger.info('[done]')
return labels, label_colors
+
+
+def _write_annot(fname, annot, ctab, names):
+ """Write a Freesurfer annotation to a .annot file.
+
+ Parameters
+ ----------
+ fname : str
+ Path to annotation file
+ annot : numpy array, shape=(n_verts)
+ Annotation id at each vertex. Note: IDs must be computed from
+ RGBA colors, otherwise the mapping will be invalid.
+ ctab : numpy array, shape=(n_entries, 4)
+ RGBA colortable array.
+ names : list of str
+ List of region names to be stored in the annot file
+ """
+
+ with open(fname, 'wb') as fid:
+ n_verts = len(annot)
+ np.array(n_verts, dtype='>i4').tofile(fid)
+
+ data = np.zeros((n_verts, 2), dtype='>i4')
+ data[:, 0] = np.arange(n_verts)
+ data[:, 1] = annot
+ data.ravel().tofile(fid)
+
+ # indicate that color table exists
+ np.array(1, dtype='>i4').tofile(fid)
+
+ # color table version 2
+ np.array(-2, dtype='>i4').tofile(fid)
+
+ # write color table
+ n_entries = len(ctab)
+ np.array(n_entries, dtype='>i4').tofile(fid)
+
+ # write dummy color table name
+ table_name = 'MNE-Python Colortable'
+ np.array(len(table_name), dtype='>i4').tofile(fid)
+ np.fromstring(table_name, dtype=np.uint8).tofile(fid)
+
+ # number of entries to write
+ np.array(n_entries, dtype='>i4').tofile(fid)
+
+ # write entries
+ for ii, (name, color) in enumerate(zip(names, ctab)):
+ np.array(ii, dtype='>i4').tofile(fid)
+ np.array(len(name), dtype='>i4').tofile(fid)
+ np.fromstring(name, dtype=np.uint8).tofile(fid)
+ np.array(color[:4], dtype='>i4').tofile(fid)
+
+
+ at verbose
+def parc_from_labels(labels, colors, subject=None, parc=None,
+ annot_fname=None, overwrite=False, subjects_dir=None,
+ verbose=None):
+ """Create a FreeSurfer parcellation from labels
+
+ Parameters
+ ----------
+ labels : list with instances of mne.Label
+ The labels to create a parcellation from.
+ colors : list of tuples | None
+ RGBA color to write into the colortable for each label. If None,
+ the colors are created based on the alphabetical order of the label
+ names. Note: Per hemisphere, each label must have a unique color,
+ otherwise the stored parcellation will be invalid.
+ subject : str | None
+ The subject for which to write the parcellation for.
+ parc : str | None
+ The parcellation name to use.
+ annot_fname : str | None
+ Filename of the .annot file. If not None, only this file is written
+ and 'parc' and 'subject' are ignored.
+ overwrite : bool
+ Overwrite files if they already exist.
+ subjects_dir : string, or None
+ Path to SUBJECTS_DIR if it is not set in the environment.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+ logger.info('Writing labels to parcellation..')
+
+ # do some input checking
+ if colors is not None:
+ colors = np.asarray(colors)
+ if colors.shape[1] != 4:
+ raise ValueError('Each color must have 4 values')
+ if len(colors) != len(labels):
+ raise ValueError('colors must have the same length as labels')
+ if np.any(colors < 0) or np.any(colors > 1):
+ raise ValueError('color values must be between 0 and 1')
+
+ subjects_dir = get_subjects_dir(subjects_dir)
+
+ # get the .annot filenames and hemispheres
+ annot_fname, hemis = _get_annot_fname(annot_fname, subject, 'both', parc,
+ subjects_dir)
+
+ if not overwrite:
+ for fname in annot_fname:
+ if op.exists(fname):
+ raise ValueError('File %s exists. Use "overwrite=True" to '
+ 'overwrite it' % fname)
+
+ names = ['%s-%s' % (label.name, label.hemi) for label in labels]
+
+ for hemi, fname in zip(hemis, annot_fname):
+ hemi_labels = [label for label in labels if label.hemi == hemi]
+ n_hemi_labels = len(hemi_labels)
+ if n_hemi_labels == 0:
+ # no labels for this hemisphere
+ continue
+ hemi_labels.sort(key=lambda label: label.name)
+ if colors is not None:
+ hemi_colors = [colors[names.index('%s-%s' % (label.name, hemi))]
+ for label in hemi_labels]
+ else:
+ import matplotlib.pyplot as plt
+ hemi_colors = plt.cm.spectral(np.linspace(0, 1, n_hemi_labels))
+
+ # Creat annot and color table array to write
+ max_vert = 0
+ for label in hemi_labels:
+ max_vert = max(max_vert, np.max(label.vertices))
+ n_vertices = max_vert + 1
+ annot = np.zeros(n_vertices, dtype=np.int)
+ ctab = np.zeros((n_hemi_labels, 4), dtype=np.int32)
+ for ii, (label, color) in enumerate(zip(hemi_labels, hemi_colors)):
+ ctab[ii] = np.round(255 * np.asarray(color))
+ if np.all(ctab[ii, :3] == 0):
+ # we cannot have an all-zero color, otherw. e.g. tksurfer
+ # refuses to read the parcellation
+ if colors is not None:
+ logger.warning(' Colormap contains color with, "r=0, '
+ 'g=0, b=0" value. Some FreeSurfer tools '
+ 'may fail to read the parcellation')
+ else:
+ ctab[ii, :3] = 1
+
+ # create the annotation id from the color
+ annot_id = (ctab[ii, 0] + ctab[ii, 1] * 2 ** 8
+ + ctab[ii, 2] * 2 ** 16)
+
+ annot[label.vertices] = annot_id
+
+ # convert to FreeSurfer alpha values
+ ctab[:, 3] = 255 - ctab[:, 3]
+
+ hemi_names = [label.name for label in hemi_labels]
+
+ # remove hemi ending in names
+ hemi_names = [name[:-3] if name.endswith(hemi) else name
+ for name in hemi_names]
+ # write it
+ logger.info(' writing %d labels to %s' % (n_hemi_labels, fname))
+ _write_annot(fname, annot, ctab, hemi_names)
+
+ logger.info('[done]')
diff --git a/mne/layouts/layout.py b/mne/layouts/layout.py
index f2d1c0f..d1a2b52 100644
--- a/mne/layouts/layout.py
+++ b/mne/layouts/layout.py
@@ -177,7 +177,8 @@ def make_eeg_layout(info, radius=20, width=5, height=4):
The generated Layout
"""
radius_head, origin_head, origin_device = fit_sphere_to_headshape(info)
- inds = pick_types(info, meg=False, eeg=True, exclude='bads')
+ inds = pick_types(info, meg=False, eeg=True, ref_meg=False,
+ exclude='bads')
hsp = [info['chs'][ii]['eeg_loc'][:, 0] for ii in inds]
names = [info['chs'][ii]['ch_name'] for ii in inds]
if len(hsp) <= 0:
@@ -234,7 +235,7 @@ def make_grid_layout(info, picks=None):
The generated layout.
"""
if picks is None:
- picks = pick_types(info, misc=True, exclude='bads')
+ picks = pick_types(info, misc=True, ref_meg=False, exclude='bads')
names = [info['chs'][k]['ch_name'] for k in picks]
@@ -291,6 +292,7 @@ def find_layout(chs):
has_vv_mag = FIFF.FIFFV_COIL_VV_MAG_T3 in coil_types
has_vv_grad = FIFF.FIFFV_COIL_VV_PLANAR_T1 in coil_types
has_4D_mag = FIFF.FIFFV_COIL_MAGNES_MAG in coil_types
+ has_CTF_grad = FIFF.FIFFV_COIL_CTF_GRAD in coil_types
if has_vv_mag and has_vv_grad:
layout_name = 'Vectorview-all'
elif has_vv_mag:
@@ -299,6 +301,8 @@ def find_layout(chs):
layout_name = 'Vectorview-grad'
elif has_4D_mag:
layout_name = 'magnesWH3600'
+ elif has_CTF_grad:
+ layout_name = 'CTF-275'
else:
return None
@@ -402,7 +406,7 @@ def _pair_grad_sensors(info, layout=None, topomap_coords=True, exclude='bads'):
"""
# find all complete pairs of grad channels
pairs = defaultdict(list)
- grad_picks = pick_types(info, meg='grad', exclude=exclude)
+ grad_picks = pick_types(info, meg='grad', ref_meg=False, exclude=exclude)
for i in grad_picks:
ch = info['chs'][i]
name = ch['ch_name']
diff --git a/mne/minimum_norm/__init__.py b/mne/minimum_norm/__init__.py
index fefeaab..c1316a4 100644
--- a/mne/minimum_norm/__init__.py
+++ b/mne/minimum_norm/__init__.py
@@ -1,8 +1,8 @@
"""Linear inverse solvers based on L2 Minimum Norm Estimates (MNE)"""
-from .inverse import read_inverse_operator, apply_inverse, \
- apply_inverse_raw, make_inverse_operator, \
- apply_inverse_epochs, write_inverse_operator, \
- compute_rank_inverse
-from .time_frequency import source_band_induced_power, source_induced_power, \
- compute_source_psd, compute_source_psd_epochs
+from .inverse import (read_inverse_operator, apply_inverse,
+ apply_inverse_raw, make_inverse_operator,
+ apply_inverse_epochs, write_inverse_operator,
+ compute_rank_inverse)
+from .time_frequency import (source_band_induced_power, source_induced_power,
+ compute_source_psd, compute_source_psd_epochs)
diff --git a/mne/minimum_norm/inverse.py b/mne/minimum_norm/inverse.py
index c788399..6c8a79b 100644
--- a/mne/minimum_norm/inverse.py
+++ b/mne/minimum_norm/inverse.py
@@ -9,32 +9,29 @@ from math import sqrt
import numpy as np
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
from ..fiff.constants import FIFF
from ..fiff.open import fiff_open
from ..fiff.tag import find_tag
-from ..fiff.matrix import _read_named_matrix, _transpose_named_matrix, \
- write_named_matrix
+from ..fiff.matrix import (_read_named_matrix, _transpose_named_matrix,
+ write_named_matrix)
from ..fiff.proj import read_proj, make_projector, write_proj
from ..fiff.tree import dir_tree_find
-from ..fiff.write import write_int, write_float_matrix, start_file, \
- start_block, end_block, end_file, write_float, \
- write_coord_trans
+from ..fiff.write import (write_int, write_float_matrix, start_file,
+ start_block, end_block, end_file, write_float,
+ write_coord_trans, write_string)
from ..fiff.cov import read_cov, write_cov
from ..fiff.pick import channel_type, pick_info
from ..cov import prepare_noise_cov
-from ..forward import compute_depth_prior, read_forward_meas_info, \
- write_forward_meas_info, is_fixed_orient, \
- compute_orient_prior, _to_fixed_ori
-from ..source_space import read_source_spaces_from_tree, \
- find_source_space_hemi, _get_vertno, \
- write_source_spaces_to_fid, label_src_vertno_sel
+from ..forward import (compute_depth_prior, read_forward_meas_info,
+ write_forward_meas_info, is_fixed_orient,
+ compute_orient_prior, _to_fixed_ori)
+from ..source_space import (read_source_spaces_from_tree,
+ find_source_space_hemi, _get_vertno,
+ _write_source_spaces_to_fid, label_src_vertno_sel)
from ..transforms import invert_transform, transform_source_space_to
-from ..source_estimate import SourceEstimate
-from .. import verbose
+from ..source_estimate import _make_stc
+from ..utils import logger, verbose
def _pick_channels_inverse_operator(ch_names, inv):
@@ -129,6 +126,22 @@ def read_inverse_operator(fname, verbose=None):
raise Exception('Coordinate frame tag not found')
inv['coord_frame'] = tag.data
+
+ #
+ # Units
+ #
+ tag = find_tag(fid, invs, FIFF.FIFF_MNE_INVERSE_SOURCE_UNIT)
+ if tag is not None:
+ if tag.data == FIFF.FIFF_UNIT_AM:
+ inv['units'] = 'Am'
+ elif tag.data == FIFF.FIFF_UNIT_AM_M2:
+ inv['units'] = 'Am/m^2'
+ elif tag.data == FIFF.FIFF_UNIT_AM_M3:
+ inv['units'] = 'Am/m^3'
+ else:
+ inv['units'] = None
+ else:
+ inv['units'] = None
#
# The actual source orientation vectors
#
@@ -232,7 +245,7 @@ def read_inverse_operator(fname, verbose=None):
inv['coord_frame'] != FIFF.FIFFV_COORD_HEAD:
fid.close()
raise Exception('Only inverse solutions computed in MRI or '
- 'head coordinates are acceptable')
+ 'head coordinates are acceptable')
#
# Number of averages is initially one
@@ -242,6 +255,7 @@ def read_inverse_operator(fname, verbose=None):
# We also need the SSP operator
#
inv['projs'] = read_proj(fid, tree)
+
#
# Some empty fields to be filled in later
#
@@ -293,32 +307,61 @@ def write_inverse_operator(fname, inv, verbose=None):
# Create the file and save the essentials
fid = start_file(fname)
+ start_block(fid, FIFF.FIFFB_MNE)
+
+ #
+ # Parent MEG measurement info
+ #
+ write_forward_meas_info(fid, inv['info'])
+
+ #
+ # Parent MRI data
+ #
+ start_block(fid, FIFF.FIFFB_MNE_PARENT_MRI_FILE)
+ write_string(fid, FIFF.FIFF_MNE_FILE_NAME, inv['info']['mri_file'])
+ write_coord_trans(fid, inv['mri_head_t'])
+ end_block(fid, FIFF.FIFFB_MNE_PARENT_MRI_FILE)
+
+ #
+ # Write SSP operator
+ #
+ write_proj(fid, inv['projs'])
+
+ #
+ # Write the source spaces
+ #
+ if 'src' in inv:
+ _write_source_spaces_to_fid(fid, inv['src'])
start_block(fid, FIFF.FIFFB_MNE_INVERSE_SOLUTION)
logger.info(' Writing inverse operator info...')
write_int(fid, FIFF.FIFF_MNE_INCLUDED_METHODS, inv['methods'])
+ write_int(fid, FIFF.FIFF_MNE_COORD_FRAME, inv['coord_frame'])
+
+ if 'units' in inv:
+ if inv['units'] == 'Am':
+ write_int(fid, FIFF.FIFF_MNE_INVERSE_SOURCE_UNIT,
+ FIFF.FIFF_UNIT_AM)
+ elif inv['units'] == 'Am/m^2':
+ write_int(fid, FIFF.FIFF_MNE_INVERSE_SOURCE_UNIT,
+ FIFF.FIFF_UNIT_AM_M2)
+ elif inv['units'] == 'Am/m^3':
+ write_int(fid, FIFF.FIFF_MNE_INVERSE_SOURCE_UNIT,
+ FIFF.FIFF_UNIT_AM_M3)
+
write_int(fid, FIFF.FIFF_MNE_SOURCE_ORIENTATION, inv['source_ori'])
write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NPOINTS, inv['nsource'])
- write_int(fid, FIFF.FIFF_MNE_COORD_FRAME, inv['coord_frame'])
+ if 'nchan' in inv:
+ write_int(fid, FIFF.FIFF_NCHAN, inv['nchan'])
+ elif 'nchan' in inv['info']:
+ write_int(fid, FIFF.FIFF_NCHAN, inv['info']['nchan'])
write_float_matrix(fid, FIFF.FIFF_MNE_INVERSE_SOURCE_ORIENTATIONS,
inv['source_nn'])
write_float(fid, FIFF.FIFF_MNE_INVERSE_SING, inv['sing'])
#
- # The eigenleads and eigenfields
- #
- if inv['eigen_leads_weighted']:
- write_named_matrix(fid, FIFF.FIFF_MNE_INVERSE_LEADS_WEIGHTED,
- _transpose_named_matrix(inv['eigen_leads']))
- else:
- write_named_matrix(fid, FIFF.FIFF_MNE_INVERSE_LEADS,
- _transpose_named_matrix(inv['eigen_leads']))
-
- write_named_matrix(fid, FIFF.FIFF_MNE_INVERSE_FIELDS, inv['eigen_fields'])
- logger.info(' [done]')
- #
# write the covariance matrices
#
logger.info(' Writing noise covariance matrix.')
@@ -326,50 +369,41 @@ def write_inverse_operator(fname, inv, verbose=None):
logger.info(' Writing source covariance matrix.')
write_cov(fid, inv['source_cov'])
+
#
# write the various priors
#
logger.info(' Writing orientation priors.')
- if inv['orient_prior'] is not None:
- write_cov(fid, inv['orient_prior'])
if inv['depth_prior'] is not None:
write_cov(fid, inv['depth_prior'])
+ if inv['orient_prior'] is not None:
+ write_cov(fid, inv['orient_prior'])
if inv['fmri_prior'] is not None:
write_cov(fid, inv['fmri_prior'])
- #
- # Parent MRI data
- #
- start_block(fid, FIFF.FIFFB_MNE_PARENT_MRI_FILE)
- # write the MRI <-> head coordinate transformation
- write_coord_trans(fid, inv['mri_head_t'])
- end_block(fid, FIFF.FIFFB_MNE_PARENT_MRI_FILE)
-
- #
- # Parent MEG measurement info
- #
- write_forward_meas_info(fid, inv['info'])
+ write_named_matrix(fid, FIFF.FIFF_MNE_INVERSE_FIELDS, inv['eigen_fields'])
#
- # Write the source spaces
+ # The eigenleads and eigenfields
#
- if 'src' in inv:
- write_source_spaces_to_fid(fid, inv['src'])
+ if inv['eigen_leads_weighted']:
+ write_named_matrix(fid, FIFF.FIFF_MNE_INVERSE_LEADS_WEIGHTED,
+ _transpose_named_matrix(inv['eigen_leads']))
+ else:
+ write_named_matrix(fid, FIFF.FIFF_MNE_INVERSE_LEADS,
+ _transpose_named_matrix(inv['eigen_leads']))
#
- # We also need the SSP operator
- #
- write_proj(fid, inv['projs'])
- #
# Done!
#
+ logger.info(' [done]')
end_block(fid, FIFF.FIFFB_MNE_INVERSE_SOLUTION)
+ end_block(fid, FIFF.FIFFB_MNE)
end_file(fid)
fid.close()
-
###############################################################################
# Compute inverse solution
@@ -566,7 +600,7 @@ def prepare_inverse_operator(orig, nave, lambda2, method, verbose=None):
@verbose
-def _assemble_kernel(inv, label, method, pick_normal, verbose=None):
+def _assemble_kernel(inv, label, method, pick_ori, verbose=None):
#
# Simple matrix multiplication followed by combination of the
# current components
@@ -596,14 +630,14 @@ def _assemble_kernel(inv, label, method, pick_normal, verbose=None):
eigen_leads = eigen_leads[src_sel]
source_cov = source_cov[src_sel]
- if pick_normal:
+ if pick_ori == "normal":
if not inv['source_ori'] == FIFF.FIFFV_MNE_FREE_ORI:
- raise ValueError('Pick normal can only be used with a free '
- 'orientation inverse operator.')
+ raise ValueError('Picking normal orientation can only be done '
+ 'with a free orientation inverse operator.')
is_loose = 0 < inv['orient_prior']['data'][0] < 1
if not is_loose:
- raise ValueError('The pick_normal parameter is only valid '
+ raise ValueError('Picking normal orientation can only be done '
'when working with loose orientations.')
# keep only the normal components
@@ -637,26 +671,33 @@ def _assemble_kernel(inv, label, method, pick_normal, verbose=None):
return K, noise_norm, vertno
-def _check_method(method, dSPM):
- if dSPM is not None:
- warnings.warn('DEPRECATION: The dSPM parameter has been changed to '
- 'method. Please update your code')
- method = dSPM
- if method is True:
- warnings.warn('DEPRECATION:Inverse method should now be "MNE" or '
- '"dSPM" or "sLORETA".')
- method = "dSPM"
- if method is False:
- warnings.warn('DEPRECATION:Inverse method should now be "MNE" or '
- '"dSPM" or "sLORETA".')
- method = "MNE"
-
+def _check_method(method):
if method not in ["MNE", "dSPM", "sLORETA"]:
raise ValueError('method parameter should be "MNE" or "dSPM" '
'or "sLORETA".')
return method
+def _check_ori(pick_ori, pick_normal):
+ if pick_normal is not None:
+ warnings.warn('DEPRECATION: The pick_normal parameter has been '
+ 'changed to pick_ori. Please update your code.')
+ pick_ori = pick_normal
+ if pick_ori is True:
+ warnings.warn('DEPRECATION: The pick_ori parameter should now be None '
+ 'or "normal".')
+ pick_ori = "normal"
+ elif pick_ori is False:
+ warnings.warn('DEPRECATION: The pick_ori parameter should now be None '
+ 'or "normal".')
+ pick_ori = None
+
+ if pick_ori not in [None, "normal"]:
+ raise ValueError('The pick_ori parameter should now be None or '
+ '"normal".')
+ return pick_ori
+
+
def _subject_from_inverse(inverse_operator):
"""Get subject id from inverse operator"""
return inverse_operator['src'][0].get('subject_his_id', None)
@@ -664,7 +705,7 @@ def _subject_from_inverse(inverse_operator):
@verbose
def apply_inverse(evoked, inverse_operator, lambda2, method="dSPM",
- pick_normal=False, dSPM=None, verbose=None):
+ pick_ori=None, verbose=None, pick_normal=None):
"""Apply inverse operator to evoked data
Computes a L2-norm inverse solution
@@ -681,8 +722,8 @@ def apply_inverse(evoked, inverse_operator, lambda2, method="dSPM",
The regularization parameter.
method : "MNE" | "dSPM" | "sLORETA"
Use mininum norm, dSPM or sLORETA.
- pick_normal : bool
- If True, rather than pooling the orientations by taking the norm,
+ pick_ori : None | "normal"
+ If "normal", rather than pooling the orientations by taking the norm,
only the radial component is kept. This is only implemented
when working with loose orientations.
verbose : bool, str, int, or None
@@ -690,10 +731,11 @@ def apply_inverse(evoked, inverse_operator, lambda2, method="dSPM",
Returns
-------
- stc : SourceEstimate
+ stc : SourceEstimate | VolSourceEstimate
The source estimates
"""
- method = _check_method(method, dSPM)
+ method = _check_method(method)
+ pick_ori = _check_ori(pick_ori, pick_normal)
#
# Set up the inverse according to the parameters
#
@@ -708,11 +750,11 @@ def apply_inverse(evoked, inverse_operator, lambda2, method="dSPM",
sel = _pick_channels_inverse_operator(evoked.ch_names, inv)
logger.info('Picked %d channels from the data' % len(sel))
logger.info('Computing inverse...')
- K, noise_norm, _ = _assemble_kernel(inv, None, method, pick_normal)
+ K, noise_norm, _ = _assemble_kernel(inv, None, method, pick_ori)
sol = np.dot(K, evoked.data[sel]) # apply imaging kernel
is_free_ori = (inverse_operator['source_ori'] == FIFF.FIFFV_MNE_FREE_ORI
- and not pick_normal)
+ and pick_ori == None)
if is_free_ori:
logger.info('combining the current components...')
@@ -726,8 +768,9 @@ def apply_inverse(evoked, inverse_operator, lambda2, method="dSPM",
tmin = float(evoked.first) / evoked.info['sfreq']
vertno = _get_vertno(inv['src'])
subject = _subject_from_inverse(inverse_operator)
- stc = SourceEstimate(sol, vertices=vertno, tmin=tmin, tstep=tstep,
- subject=subject)
+
+ stc = _make_stc(sol, vertices=vertno, tmin=tmin, tstep=tstep,
+ subject=subject)
logger.info('[done]')
return stc
@@ -736,8 +779,9 @@ def apply_inverse(evoked, inverse_operator, lambda2, method="dSPM",
@verbose
def apply_inverse_raw(raw, inverse_operator, lambda2, method="dSPM",
label=None, start=None, stop=None, nave=1,
- time_func=None, pick_normal=False,
- buffer_size=None, dSPM=None, verbose=None):
+ time_func=None, pick_ori=None,
+ buffer_size=None, verbose=None,
+ pick_normal=None):
"""Apply inverse operator to Raw data
Computes a L2-norm inverse solution
@@ -766,8 +810,8 @@ def apply_inverse_raw(raw, inverse_operator, lambda2, method="dSPM",
Set to 1 on raw data.
time_func : callable
Linear function applied to sensor space time series.
- pick_normal : bool
- If True, rather than pooling the orientations by taking the norm,
+ pick_ori : None | "normal"
+ If "normal", rather than pooling the orientations by taking the norm,
only the radial component is kept. This is only implemented
when working with loose orientations.
buffer_size : int (or None)
@@ -783,10 +827,11 @@ def apply_inverse_raw(raw, inverse_operator, lambda2, method="dSPM",
Returns
-------
- stc : SourceEstimate
+ stc : SourceEstimate | VolSourceEstimate
The source estimates.
"""
- method = _check_method(method, dSPM)
+ method = _check_method(method)
+ pick_ori = _check_ori(pick_ori, pick_normal)
_check_ch_names(inverse_operator, raw.info)
@@ -806,10 +851,10 @@ def apply_inverse_raw(raw, inverse_operator, lambda2, method="dSPM",
if time_func is not None:
data = time_func(data)
- K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_normal)
+ K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_ori)
is_free_ori = (inverse_operator['source_ori'] == FIFF.FIFFV_MNE_FREE_ORI
- and not pick_normal)
+ and pick_ori == None)
if buffer_size is not None and is_free_ori:
# Process the data in segments to conserve memory
@@ -840,18 +885,19 @@ def apply_inverse_raw(raw, inverse_operator, lambda2, method="dSPM",
tmin = float(times[0])
tstep = 1.0 / raw.info['sfreq']
subject = _subject_from_inverse(inverse_operator)
- stc = SourceEstimate(sol, vertices=vertno, tmin=tmin, tstep=tstep,
- subject=subject)
+ stc = _make_stc(sol, vertices=vertno, tmin=tmin, tstep=tstep,
+ subject=subject)
logger.info('[done]')
return stc
def _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2, method="dSPM",
- label=None, nave=1, pick_normal=False, dSPM=None,
- verbose=None):
+ label=None, nave=1, pick_ori=None,
+ verbose=None, pick_normal=None):
""" see apply_inverse_epochs """
- method = _check_method(method, dSPM)
+ method = _check_method(method)
+ pick_ori = _check_ori(pick_ori, pick_normal)
_check_ch_names(inverse_operator, epochs.info)
@@ -865,13 +911,13 @@ def _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2, method="dSPM",
sel = _pick_channels_inverse_operator(epochs.ch_names, inv)
logger.info('Picked %d channels from the data' % len(sel))
logger.info('Computing inverse...')
- K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_normal)
+ K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_ori)
tstep = 1.0 / epochs.info['sfreq']
tmin = epochs.times[0]
is_free_ori = (inverse_operator['source_ori'] == FIFF.FIFFV_MNE_FREE_ORI
- and not pick_normal)
+ and pick_ori == None)
if not is_free_ori and noise_norm is not None:
# premultiply kernel with noise normalization
@@ -896,8 +942,8 @@ def _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2, method="dSPM",
else:
sol = np.dot(K, e[sel])
- stc = SourceEstimate(sol, vertices=vertno, tmin=tmin, tstep=tstep,
- subject=subject)
+ stc = _make_stc(sol, vertices=vertno, tmin=tmin, tstep=tstep,
+ subject=subject)
yield stc
@@ -906,8 +952,9 @@ def _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2, method="dSPM",
@verbose
def apply_inverse_epochs(epochs, inverse_operator, lambda2, method="dSPM",
- label=None, nave=1, pick_normal=False, dSPM=None,
- return_generator=False, verbose=None):
+ label=None, nave=1, pick_ori=None,
+ return_generator=False, verbose=None,
+ pick_normal=None):
"""Apply inverse operator to Epochs
Computes a L2-norm inverse solution on each epochs and returns
@@ -929,8 +976,8 @@ def apply_inverse_epochs(epochs, inverse_operator, lambda2, method="dSPM",
nave : int
Number of averages used to regularize the solution.
Set to 1 on single Epoch by default.
- pick_normal : bool
- If True, rather than pooling the orientations by taking the norm,
+ pick_ori : None | "normal"
+ If "normal", rather than pooling the orientations by taking the norm,
only the radial component is kept. This is only implemented
when working with loose orientations.
return_generator : bool
@@ -941,14 +988,13 @@ def apply_inverse_epochs(epochs, inverse_operator, lambda2, method="dSPM",
Returns
-------
- stc : list of SourceEstimate
+ stc : list of SourceEstimate or VolSourceEstimate
The source estimates for all epochs.
"""
-
stcs = _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2,
method=method, label=label, nave=nave,
- pick_normal=pick_normal, dSPM=dSPM,
- verbose=verbose)
+ pick_ori=pick_ori, verbose=verbose,
+ pick_normal=pick_normal)
if not return_generator:
# return a list
@@ -1314,6 +1360,7 @@ def make_inverse_operator(info, forward, noise_cov, loose=0.2, depth=0.8,
src=deepcopy(forward['src']), fmri_prior=None)
inv_info = deepcopy(forward['info'])
inv_info['bads'] = deepcopy(info['bads'])
+ inv_op['units'] = 'Am'
inv_op['info'] = inv_info
return inv_op
diff --git a/mne/minimum_norm/tests/test_inverse.py b/mne/minimum_norm/tests/test_inverse.py
index 7351399..5ae84b3 100644
--- a/mne/minimum_norm/tests/test_inverse.py
+++ b/mne/minimum_norm/tests/test_inverse.py
@@ -4,19 +4,22 @@ from numpy.testing import assert_array_almost_equal, assert_equal
from scipy import sparse
from nose.tools import assert_true, assert_raises
import copy
+import warnings
from mne.datasets import sample
from mne.label import read_label, label_sign_flip
from mne.event import read_events
from mne.epochs import Epochs
-from mne.source_estimate import read_source_estimate
+from mne.source_estimate import read_source_estimate, VolSourceEstimate
from mne import fiff, read_cov, read_forward_solution
-from mne.minimum_norm.inverse import apply_inverse, read_inverse_operator, \
- apply_inverse_raw, apply_inverse_epochs, make_inverse_operator, \
- write_inverse_operator, compute_rank_inverse
+from mne.minimum_norm.inverse import (apply_inverse, read_inverse_operator,
+ apply_inverse_raw, apply_inverse_epochs,
+ make_inverse_operator,
+ write_inverse_operator,
+ compute_rank_inverse)
from mne.utils import _TempDir
-s_path = op.join(sample.data_path(), 'MEG', 'sample')
+s_path = op.join(sample.data_path(download=False), 'MEG', 'sample')
fname_inv = op.join(s_path, 'sample_audvis-meg-oct-6-meg-inv.fif')
fname_inv_fixed = op.join(s_path, 'sample_audvis-meg-oct-6-meg-fixed-inv.fif')
fname_inv_nodepth = op.join(s_path,
@@ -27,17 +30,11 @@ fname_vol_inv = op.join(s_path, 'sample_audvis-meg-vol-7-meg-inv.fif')
fname_data = op.join(s_path, 'sample_audvis-ave.fif')
fname_cov = op.join(s_path, 'sample_audvis-cov.fif')
fname_fwd = op.join(s_path, 'sample_audvis-meg-oct-6-fwd.fif')
+fname_fwd_meeg = op.join(s_path, 'sample_audvis-meg-eeg-oct-6-fwd.fif')
fname_raw = op.join(s_path, 'sample_audvis_filt-0-40_raw.fif')
fname_event = op.join(s_path, 'sample_audvis_filt-0-40_raw-eve.fif')
fname_label = op.join(s_path, 'labels', '%s.label')
-inverse_operator = read_inverse_operator(fname_inv)
-label_lh = read_label(fname_label % 'Aud-lh')
-label_rh = read_label(fname_label % 'Aud-rh')
-noise_cov = read_cov(fname_cov)
-raw = fiff.Raw(fname_raw)
-evoked = fiff.Evoked(fname_data, setno=0, baseline=(None, 0))
-evoked.crop(0, 0.2)
snr = 3.0
lambda2 = 1.0 / snr ** 2
@@ -45,6 +42,12 @@ tempdir = _TempDir()
last_keys = [None] * 10
+def _get_evoked():
+ evoked = fiff.Evoked(fname_data, setno=0, baseline=(None, 0))
+ evoked.crop(0, 0.2)
+ return evoked
+
+
def _compare(a, b):
global last_keys
skip_types = ['whitener', 'proj', 'reginv', 'noisenorm', 'nchan',
@@ -112,6 +115,7 @@ def _compare_inverses_approx(inv_1, inv_2, evoked, stc_decimals,
assert_true(stc_1.subject == stc_2.subject)
assert_equal(stc_1.times, stc_2.times)
assert_array_almost_equal(stc_1.data, stc_2.data, stc_decimals)
+ assert_true(inv_1['units'] == inv_2['units'])
def _compare_io(inv_op, out_file_ext='.fif'):
@@ -129,9 +133,26 @@ def _compare_io(inv_op, out_file_ext='.fif'):
_compare(inv_init, inv_op)
+ at sample.requires_sample_data
+def test_warn_inverse_operator():
+ """Test MNE inverse warning without average EEG projection
+ """
+ bad_info = copy.deepcopy(_get_evoked().info)
+ bad_info['projs'] = list()
+ fwd_op = read_forward_solution(fname_fwd_meeg, surf_ori=True)
+ noise_cov = read_cov(fname_cov)
+ with warnings.catch_warnings(True) as w:
+ make_inverse_operator(bad_info, fwd_op, noise_cov)
+ assert_equal(len(w), 1)
+
+
+ at sample.requires_sample_data
def test_apply_inverse_operator():
"""Test MNE inverse computation (precomputed and non-precomputed)
"""
+ inverse_operator = read_inverse_operator(fname_inv)
+ evoked = _get_evoked()
+ noise_cov = read_cov(fname_cov)
# Test old version of inverse computation starting from forward operator
fwd_op = read_forward_solution(fname_fwd, surf_ori=True)
@@ -139,6 +160,7 @@ def test_apply_inverse_operator():
loose=0.2, depth=0.8,
limit_depth_chs=False)
_compare_io(my_inv_op)
+ assert_true(inverse_operator['units'] == 'Am')
_compare_inverses_approx(my_inv_op, inverse_operator, evoked, 2,
check_depth=False)
# Inverse has 306 channels - 4 proj = 302
@@ -180,12 +202,15 @@ def test_apply_inverse_operator():
assert_array_almost_equal(stc.data, my_stc.data, 2)
+ at sample.requires_sample_data
def test_make_inverse_operator_fixed():
"""Test MNE inverse computation (fixed orientation)
"""
fwd_op = read_forward_solution(fname_fwd, surf_ori=True)
fwd_1 = read_forward_solution(fname_fwd, surf_ori=False, force_fixed=False)
fwd_2 = read_forward_solution(fname_fwd, surf_ori=False, force_fixed=True)
+ evoked = _get_evoked()
+ noise_cov = read_cov(fname_cov)
# can't make depth-weighted fixed inv without surf ori fwd
assert_raises(ValueError, make_inverse_operator, evoked.info, fwd_1,
@@ -218,12 +243,15 @@ def test_make_inverse_operator_fixed():
assert_true(compute_rank_inverse(inverse_operator_fixed) == 302)
+ at sample.requires_sample_data
def test_make_inverse_operator_free():
"""Test MNE inverse computation (free orientation)
"""
fwd_op = read_forward_solution(fname_fwd, surf_ori=True)
fwd_1 = read_forward_solution(fname_fwd, surf_ori=False, force_fixed=False)
fwd_2 = read_forward_solution(fname_fwd, surf_ori=False, force_fixed=True)
+ evoked = _get_evoked()
+ noise_cov = read_cov(fname_cov)
# can't make free inv with fixed fwd
assert_raises(ValueError, make_inverse_operator, evoked.info, fwd_2,
@@ -242,9 +270,12 @@ def test_make_inverse_operator_free():
_compare_inverses_approx(inv_3, inv_4, evoked, 2)
+ at sample.requires_sample_data
def test_make_inverse_operator_diag():
"""Test MNE inverse computation with diagonal noise cov
"""
+ evoked = _get_evoked()
+ noise_cov = read_cov(fname_cov)
fwd_op = read_forward_solution(fname_fwd, surf_ori=True)
inv_op = make_inverse_operator(evoked.info, fwd_op, noise_cov.as_diag(),
loose=0.2, depth=0.8)
@@ -256,12 +287,15 @@ def test_make_inverse_operator_diag():
assert_true(compute_rank_inverse(inverse_operator_diag) == 302)
+ at sample.requires_sample_data
def test_inverse_operator_volume():
"""Test MNE inverse computation on volume source space
"""
+ evoked = _get_evoked()
inverse_operator_vol = read_inverse_operator(fname_vol_inv)
_compare_io(inverse_operator_vol)
stc = apply_inverse(evoked, inverse_operator_vol, lambda2, "dSPM")
+ assert_true(isinstance(stc, VolSourceEstimate))
# volume inverses don't have associated subject IDs
assert_true(stc.subject is None)
stc.save(op.join(tempdir, 'tmp-vl.stc'))
@@ -272,30 +306,36 @@ def test_inverse_operator_volume():
assert_array_almost_equal(stc.times, stc2.times)
+ at sample.requires_sample_data
def test_io_inverse_operator():
"""Test IO of inverse_operator with GZip
"""
+ inverse_operator = read_inverse_operator(fname_inv)
# just do one example for .gz, as it should generalize
_compare_io(inverse_operator, '.gz')
+ at sample.requires_sample_data
def test_apply_mne_inverse_raw():
"""Test MNE with precomputed inverse operator on Raw
"""
start = 3
stop = 10
+ raw = fiff.Raw(fname_raw)
+ label_lh = read_label(fname_label % 'Aud-lh')
_, times = raw[0, start:stop]
- for pick_normal in [False, True]:
+ inverse_operator = read_inverse_operator(fname_inv)
+ for pick_ori in [None, "normal"]:
stc = apply_inverse_raw(raw, inverse_operator, lambda2, "dSPM",
label=label_lh, start=start, stop=stop, nave=1,
- pick_normal=pick_normal, buffer_size=None)
+ pick_ori=pick_ori, buffer_size=None)
stc2 = apply_inverse_raw(raw, inverse_operator, lambda2, "dSPM",
label=label_lh, start=start, stop=stop,
- nave=1, pick_normal=pick_normal,
+ nave=1, pick_ori=pick_ori,
buffer_size=3)
- if not pick_normal:
+ if pick_ori is None:
assert_true(np.all(stc.data > 0))
assert_true(np.all(stc2.data > 0))
@@ -306,25 +346,29 @@ def test_apply_mne_inverse_raw():
assert_array_almost_equal(stc.data, stc2.data)
+ at sample.requires_sample_data
def test_apply_mne_inverse_fixed_raw():
"""Test MNE with fixed-orientation inverse operator on Raw
"""
+ raw = fiff.Raw(fname_raw)
start = 3
stop = 10
_, times = raw[0, start:stop]
+ label_lh = read_label(fname_label % 'Aud-lh')
# create a fixed-orientation inverse operator
fwd = read_forward_solution(fname_fwd, force_fixed=False, surf_ori=True)
+ noise_cov = read_cov(fname_cov)
inv_op = make_inverse_operator(raw.info, fwd, noise_cov,
loose=None, depth=0.8, fixed=True)
stc = apply_inverse_raw(raw, inv_op, lambda2, "dSPM",
label=label_lh, start=start, stop=stop, nave=1,
- pick_normal=False, buffer_size=None)
+ pick_ori=None, buffer_size=None)
stc2 = apply_inverse_raw(raw, inv_op, lambda2, "dSPM",
label=label_lh, start=start, stop=stop, nave=1,
- pick_normal=False, buffer_size=3)
+ pick_ori=None, buffer_size=3)
assert_true(stc.subject == 'sample')
assert_true(stc2.subject == 'sample')
@@ -333,10 +377,15 @@ def test_apply_mne_inverse_fixed_raw():
assert_array_almost_equal(stc.data, stc2.data)
+ at sample.requires_sample_data
def test_apply_mne_inverse_epochs():
"""Test MNE with precomputed inverse operator on Epochs
"""
+ inverse_operator = read_inverse_operator(fname_inv)
+ label_lh = read_label(fname_label % 'Aud-lh')
+ label_rh = read_label(fname_label % 'Aud-rh')
event_id, tmin, tmax = 1, -0.2, 0.5
+ raw = fiff.Raw(fname_raw)
picks = fiff.pick_types(raw.info, meg=True, eeg=False, stim=True,
ecg=True, eog=True, include=['STI 014'],
@@ -348,7 +397,7 @@ def test_apply_mne_inverse_epochs():
epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
baseline=(None, 0), reject=reject, flat=flat)
stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2, "dSPM",
- label=label_lh, pick_normal=True)
+ label=label_lh, pick_ori="normal")
assert_true(len(stcs) == 4)
assert_true(3 < stcs[0].data.max() < 10)
@@ -364,9 +413,10 @@ def test_apply_mne_inverse_epochs():
# test extracting a BiHemiLabel
stcs_rh = apply_inverse_epochs(epochs, inverse_operator, lambda2, "dSPM",
- label=label_rh, pick_normal=True)
+ label=label_rh, pick_ori="normal")
stcs_bh = apply_inverse_epochs(epochs, inverse_operator, lambda2, "dSPM",
- label=label_lh + label_rh, pick_normal=True)
+ label=label_lh + label_rh,
+ pick_ori="normal")
n_lh = len(stcs[0].data)
assert_array_almost_equal(stcs[0].data, stcs_bh[0].data[:n_lh])
@@ -374,17 +424,20 @@ def test_apply_mne_inverse_epochs():
# test without using a label (so delayed computation is used)
stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2, "dSPM",
- pick_normal=True)
+ pick_ori="normal")
assert_true(stcs[0].subject == 'sample')
label_stc = stcs[0].in_label(label_rh)
assert_true(label_stc.subject == 'sample')
assert_array_almost_equal(stcs_rh[0].data, label_stc.data)
+ at sample.requires_sample_data
def test_make_inverse_operator_bads():
"""Test MNE inverse computation given a mismatch of bad channels
"""
fwd_op = read_forward_solution(fname_fwd, surf_ori=True)
+ evoked = _get_evoked()
+ noise_cov = read_cov(fname_cov)
# test bads
bad = evoked.info['bads'].pop()
diff --git a/mne/minimum_norm/tests/test_time_frequency.py b/mne/minimum_norm/tests/test_time_frequency.py
index 1136c0f..cf40ab9 100644
--- a/mne/minimum_norm/tests/test_time_frequency.py
+++ b/mne/minimum_norm/tests/test_time_frequency.py
@@ -7,23 +7,25 @@ from nose.tools import assert_true
from mne.datasets import sample
from mne import fiff, find_events, Epochs
from mne.label import read_label
-from mne.minimum_norm.inverse import read_inverse_operator, \
- apply_inverse_epochs
-from mne.minimum_norm.time_frequency import source_band_induced_power, \
- source_induced_power, compute_source_psd, \
- compute_source_psd_epochs
+from mne.minimum_norm.inverse import (read_inverse_operator,
+ apply_inverse_epochs)
+from mne.minimum_norm.time_frequency import (source_band_induced_power,
+ source_induced_power,
+ compute_source_psd,
+ compute_source_psd_epochs)
from mne.time_frequency import multitaper_psd
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
fname_inv = op.join(data_path, 'MEG', 'sample',
- 'sample_audvis-meg-oct-6-meg-inv.fif')
+ 'sample_audvis-meg-oct-6-meg-inv.fif')
fname_data = op.join(data_path, 'MEG', 'sample',
- 'sample_audvis_raw.fif')
+ 'sample_audvis_raw.fif')
fname_label = op.join(data_path, 'MEG', 'sample', 'labels', 'Aud-lh.label')
+ at sample.requires_sample_data
def test_tfr_with_inverse_operator():
"""Test time freq with MNE inverse computation"""
@@ -80,6 +82,7 @@ def test_tfr_with_inverse_operator():
assert_true(np.max(power) > 10)
+ at sample.requires_sample_data
def test_source_psd():
"""Test source PSD computation in label"""
raw = fiff.Raw(fname_data)
@@ -90,7 +93,7 @@ def test_source_psd():
NFFT = 2048
stc = compute_source_psd(raw, inverse_operator, lambda2=1. / 9.,
method="dSPM", tmin=tmin, tmax=tmax,
- fmin=fmin, fmax=fmax, pick_normal=True,
+ fmin=fmin, fmax=fmax, pick_ori="normal",
NFFT=NFFT, label=label, overlap=0.1)
assert_true(stc.times[0] >= fmin * 1e-3)
assert_true(stc.times[-1] <= fmax * 1e-3)
@@ -99,6 +102,7 @@ def test_source_psd():
<= 61e-3)
+ at sample.requires_sample_data
def test_source_psd_epochs():
"""Test multi-taper source PSD computation in label from epochs"""
@@ -127,14 +131,14 @@ def test_source_psd_epochs():
# return list
stc_psd = compute_source_psd_epochs(one_epochs, inverse_operator,
lambda2=lambda2, method=method,
- pick_normal=True, label=label,
+ pick_ori="normal", label=label,
bandwidth=bandwidth,
fmin=fmin, fmax=fmax)[0]
# return generator
stcs = compute_source_psd_epochs(one_epochs, inverse_operator,
lambda2=lambda2, method=method,
- pick_normal=True, label=label,
+ pick_ori="normal", label=label,
bandwidth=bandwidth,
fmin=fmin, fmax=fmax,
return_generator=True)
@@ -147,7 +151,7 @@ def test_source_psd_epochs():
# compare with direct computation
stc = apply_inverse_epochs(one_epochs, inverse_operator,
lambda2=lambda2, method=method,
- pick_normal=True, label=label)[0]
+ pick_ori="normal", label=label)[0]
sfreq = epochs.info['sfreq']
psd, freqs = multitaper_psd(stc.data, sfreq=sfreq, bandwidth=bandwidth,
diff --git a/mne/minimum_norm/time_frequency.py b/mne/minimum_norm/time_frequency.py
index 601aef4..f7e0e9c 100644
--- a/mne/minimum_norm/time_frequency.py
+++ b/mne/minimum_norm/time_frequency.py
@@ -8,20 +8,17 @@ from warnings import warn
import numpy as np
from scipy import linalg, signal, fftpack
-import logging
-logger = logging.getLogger('mne')
-
from ..fiff.constants import FIFF
-from ..source_estimate import SourceEstimate
+from ..source_estimate import _make_stc
from ..time_frequency.tfr import cwt, morlet
-from ..time_frequency.multitaper import dpss_windows, _psd_from_mt,\
- _psd_from_mt_adaptive, _mt_spectra
+from ..time_frequency.multitaper import (dpss_windows, _psd_from_mt,
+ _psd_from_mt_adaptive, _mt_spectra)
from ..baseline import rescale
-from .inverse import combine_xyz, prepare_inverse_operator, _assemble_kernel, \
- _pick_channels_inverse_operator, _check_method, \
- _subject_from_inverse
+from .inverse import (combine_xyz, prepare_inverse_operator, _assemble_kernel,
+ _pick_channels_inverse_operator, _check_method,
+ _check_ori, _subject_from_inverse)
from ..parallel import parallel_func
-from .. import verbose
+from ..utils import logger, verbose
@verbose
@@ -29,7 +26,7 @@ def source_band_induced_power(epochs, inverse_operator, bands, label=None,
lambda2=1.0 / 9.0, method="dSPM", nave=1,
n_cycles=5, df=1, use_fft=False, decim=1,
baseline=None, baseline_mode='logratio',
- pca=True, n_jobs=1, dSPM=None, verbose=None):
+ pca=True, n_jobs=1, verbose=None):
"""Compute source space induced power in given frequency bands
Parameters
@@ -77,8 +74,13 @@ def source_band_induced_power(epochs, inverse_operator, bands, label=None,
Number of jobs to run in parallel.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ stcs : dict with a SourceEstimate (or VolSourceEstimate) for each band
+ The estimated source space induced power estimates.
"""
- method = _check_method(method, dSPM)
+ method = _check_method(method)
frequencies = np.concatenate([np.arange(band[0], band[1] + df / 2.0, df)
for _, band in bands.iteritems()])
@@ -107,8 +109,8 @@ def source_band_induced_power(epochs, inverse_operator, bands, label=None,
tmin = epochs.times[0]
tstep = float(decim) / Fs
- stc = SourceEstimate(power, vertices=vertno, tmin=tmin, tstep=tstep,
- subject=subject)
+ stc = _make_stc(power, vertices=vertno, tmin=tmin, tstep=tstep,
+ subject=subject)
stcs[name] = stc
logger.info('[done]')
@@ -118,13 +120,13 @@ def source_band_induced_power(epochs, inverse_operator, bands, label=None,
@verbose
def _compute_pow_plv(data, K, sel, Ws, source_ori, use_fft, Vh, with_plv,
- pick_normal, decim, verbose=None):
+ pick_ori, decim, verbose=None):
"""Aux function for source_induced_power"""
n_times = data[:, :, ::decim].shape[2]
n_freqs = len(Ws)
n_sources = K.shape[0]
is_free_ori = False
- if (source_ori == FIFF.FIFFV_MNE_FREE_ORI and not pick_normal):
+ if (source_ori == FIFF.FIFFV_MNE_FREE_ORI and pick_ori == None):
is_free_ori = True
n_sources /= 3
@@ -186,7 +188,7 @@ def _compute_pow_plv(data, K, sel, Ws, source_ori, use_fft, Vh, with_plv,
@verbose
def _source_induced_power(epochs, inverse_operator, frequencies, label=None,
lambda2=1.0 / 9.0, method="dSPM", nave=1, n_cycles=5,
- decim=1, use_fft=False, pca=True, pick_normal=True,
+ decim=1, use_fft=False, pca=True, pick_ori="normal",
n_jobs=1, with_plv=True, zero_mean=False,
verbose=None):
"""Aux function for source_induced_power
@@ -212,7 +214,7 @@ def _source_induced_power(epochs, inverse_operator, frequencies, label=None,
# This does all the data transformations to compute the weights for the
# eigenleads
#
- K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_normal)
+ K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_ori)
if pca:
U, s, Vh = linalg.svd(K, full_matrices=False)
@@ -232,7 +234,7 @@ def _source_induced_power(epochs, inverse_operator, frequencies, label=None,
n_jobs = min(n_jobs, len(epochs_data))
out = parallel(my_compute_pow_plv(data, K, sel, Ws,
inv['source_ori'], use_fft, Vh,
- with_plv, pick_normal, decim)
+ with_plv, pick_ori, decim)
for data in np.array_split(epochs_data, n_jobs))
power = sum(o[0] for o in out)
power /= len(epochs_data) # average power over epochs
@@ -253,9 +255,10 @@ def _source_induced_power(epochs, inverse_operator, frequencies, label=None,
@verbose
def source_induced_power(epochs, inverse_operator, frequencies, label=None,
lambda2=1.0 / 9.0, method="dSPM", nave=1, n_cycles=5,
- decim=1, use_fft=False, pick_normal=False,
+ decim=1, use_fft=False, pick_ori=None,
baseline=None, baseline_mode='logratio', pca=True,
- n_jobs=1, dSPM=None, zero_mean=False, verbose=None):
+ n_jobs=1, zero_mean=False, verbose=None,
+ pick_normal=None):
"""Compute induced power and phase lock
Computation can optionaly be restricted in a label.
@@ -282,8 +285,8 @@ def source_induced_power(epochs, inverse_operator, frequencies, label=None,
Temporal decimation factor.
use_fft : bool
Do convolutions in time or frequency domain with FFT.
- pick_normal : bool
- If True, rather than pooling the orientations by taking the norm,
+ pick_ori : None | "normal"
+ If "normal", rather than pooling the orientations by taking the norm,
only the radial component is kept. This is only implemented
when working with loose orientations.
baseline : None (default) or tuple of length 2
@@ -310,13 +313,14 @@ def source_induced_power(epochs, inverse_operator, frequencies, label=None,
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
"""
- method = _check_method(method, dSPM)
+ method = _check_method(method)
+ pick_ori = _check_ori(pick_ori, pick_normal)
power, plv, vertno = _source_induced_power(epochs,
inverse_operator, frequencies,
label=label, lambda2=lambda2, method=method,
nave=nave, n_cycles=n_cycles, decim=decim,
- use_fft=use_fft, pick_normal=pick_normal,
+ use_fft=use_fft, pick_ori=pick_ori,
pca=pca, n_jobs=n_jobs)
# Run baseline correction
@@ -330,8 +334,8 @@ def source_induced_power(epochs, inverse_operator, frequencies, label=None,
@verbose
def compute_source_psd(raw, inverse_operator, lambda2=1. / 9., method="dSPM",
tmin=None, tmax=None, fmin=0., fmax=200.,
- NFFT=2048, overlap=0.5, pick_normal=False, label=None,
- nave=1, pca=True, verbose=None):
+ NFFT=2048, overlap=0.5, pick_ori=None, label=None,
+ nave=1, pca=True, verbose=None, pick_normal=None):
"""Compute source power spectrum density (PSD)
Parameters
@@ -359,8 +363,8 @@ def compute_source_psd(raw, inverse_operator, lambda2=1. / 9., method="dSPM",
overlap: float
The overlap fraction between windows. Should be between 0 and 1.
0 means no overlap.
- pick_normal : bool
- If True, rather than pooling the orientations by taking the norm,
+ pick_ori : None | "normal"
+ If "normal", rather than pooling the orientations by taking the norm,
only the radial component is kept. This is only implemented
when working with loose orientations.
label: Label
@@ -376,9 +380,10 @@ def compute_source_psd(raw, inverse_operator, lambda2=1. / 9., method="dSPM",
Returns
-------
- stc : SourceEstimate
+ stc : SourceEstimate | VolSourceEstimate
The PSD (in dB) of each of the sources.
"""
+ pick_ori = _check_ori(pick_ori, pick_normal)
logger.info('Considering frequencies %g ... %g Hz' % (fmin, fmax))
@@ -398,7 +403,7 @@ def compute_source_psd(raw, inverse_operator, lambda2=1. / 9., method="dSPM",
# This does all the data transformations to compute the weights for the
# eigenleads
#
- K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_normal)
+ K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_ori)
if pca:
U, s, Vh = linalg.svd(K, full_matrices=False)
@@ -421,7 +426,7 @@ def compute_source_psd(raw, inverse_operator, lambda2=1. / 9., method="dSPM",
freqs_mask = (freqs >= 0) & (freqs >= fmin) & (freqs <= fmax)
freqs = freqs[freqs_mask]
fstep = np.mean(np.diff(freqs))
- psd = np.zeros((noise_norm.size, np.sum(freqs_mask)))
+ psd = np.zeros((K.shape[0], np.sum(freqs_mask)))
n_windows = 0
for this_start in np.arange(start, stop, int(NFFT * (1. - overlap))):
@@ -438,7 +443,7 @@ def compute_source_psd(raw, inverse_operator, lambda2=1. / 9., method="dSPM",
data_fft = fftpack.fft(data)[:, freqs_mask]
sol = np.dot(K, data_fft)
- if is_free_ori and not pick_normal:
+ if is_free_ori and pick_ori == None:
sol = combine_xyz(sol, square=True)
else:
sol = np.abs(sol) ** 2
@@ -454,15 +459,15 @@ def compute_source_psd(raw, inverse_operator, lambda2=1. / 9., method="dSPM",
psd = 10 * np.log10(psd)
subject = _subject_from_inverse(inverse_operator)
- stc = SourceEstimate(psd, vertices=vertno, tmin=fmin * 1e-3,
- tstep=fstep * 1e-3, subject=subject)
+ stc = _make_stc(psd, vertices=vertno, tmin=fmin * 1e-3,
+ tstep=fstep * 1e-3, subject=subject)
return stc
@verbose
def _compute_source_psd_epochs(epochs, inverse_operator, lambda2=1. / 9.,
method="dSPM", fmin=0., fmax=200.,
- pick_normal=False, label=None, nave=1,
+ pick_ori=None, label=None, nave=1,
pca=True, inv_split=None, bandwidth=4.,
adaptive=False, low_bias=True, n_jobs=1,
verbose=None):
@@ -486,7 +491,7 @@ def _compute_source_psd_epochs(epochs, inverse_operator, lambda2=1. / 9.,
# This does all the data transformations to compute the weights for the
# eigenleads
#
- K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_normal)
+ K, noise_norm, vertno = _assemble_kernel(inv, label, method, pick_ori)
if pca:
U, s, Vh = linalg.svd(K, full_matrices=False)
@@ -573,14 +578,14 @@ def _compute_source_psd_epochs(epochs, inverse_operator, lambda2=1. / 9.,
pos += K_part.shape[0]
# combine orientations
- if is_free_ori and not pick_normal:
+ if is_free_ori and pick_ori == None:
psd = combine_xyz(psd, square=False)
if method != "MNE":
psd *= noise_norm ** 2
- stc = SourceEstimate(psd, tmin=fmin, tstep=fstep, vertices=vertno,
- subject=subject)
+ stc = _make_stc(psd, tmin=fmin, tstep=fstep, vertices=vertno,
+ subject=subject)
# we return a generator object for "stream processing"
yield stc
@@ -589,11 +594,11 @@ def _compute_source_psd_epochs(epochs, inverse_operator, lambda2=1. / 9.,
@verbose
def compute_source_psd_epochs(epochs, inverse_operator, lambda2=1. / 9.,
method="dSPM", fmin=0., fmax=200.,
- pick_normal=False, label=None, nave=1,
+ pick_ori=None, label=None, nave=1,
pca=True, inv_split=None, bandwidth=4.,
adaptive=False, low_bias=True,
return_generator=False, n_jobs=1,
- verbose=None):
+ verbose=None, pick_normal=None):
"""Compute source power spectrum density (PSD) from Epochs using
multi-taper method
@@ -611,8 +616,8 @@ def compute_source_psd_epochs(epochs, inverse_operator, lambda2=1. / 9.,
The lower frequency of interest.
fmax : float
The upper frequency of interest.
- pick_normal : bool
- If True, rather than pooling the orientations by taking the norm,
+ pick_ori : None | "normal"
+ If "normal", rather than pooling the orientations by taking the norm,
only the radial component is kept. This is only implemented
when working with loose orientations.
label : Label
@@ -643,14 +648,14 @@ def compute_source_psd_epochs(epochs, inverse_operator, lambda2=1. / 9.,
Returns
-------
- stcs : list (or generator object) of SourceEstimate
+ stcs : list (or generator object) of SourceEstimate | VolSourceEstimate
The source space PSDs for each epoch.
"""
# use an auxiliary function so we can either return a generator or a list
stcs_gen = _compute_source_psd_epochs(epochs, inverse_operator,
lambda2=lambda2, method=method, fmin=fmin,
- fmax=fmax, pick_normal=pick_normal, label=label,
+ fmax=fmax, pick_ori=pick_ori, label=label,
nave=nave, pca=pca, inv_split=inv_split,
bandwidth=bandwidth, adaptive=adaptive,
low_bias=low_bias, n_jobs=n_jobs)
diff --git a/mne/parallel.py b/mne/parallel.py
index eea73cd..37415e4 100644
--- a/mne/parallel.py
+++ b/mne/parallel.py
@@ -5,14 +5,20 @@
#
# License: Simplified BSD
+import inspect
import logging
-logger = logging.getLogger('mne')
+import os
-from . import verbose
+from . import get_config
+from .utils import logger, verbose
+if 'MNE_FORCE_SERIAL' in os.environ:
+ _force_serial = True
+else:
+ _force_serial = None
@verbose
-def parallel_func(func, n_jobs, verbose=None):
+def parallel_func(func, n_jobs, verbose=None, max_nbytes='auto'):
"""Return parallel instance with delayed function
Util function to use joblib only if available
@@ -26,6 +32,12 @@ def parallel_func(func, n_jobs, verbose=None):
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
INFO or DEBUG will print parallel status, others will not.
+ max_nbytes int, str, or None
+ Threshold on the minimum size of arrays passed to the workers that
+ triggers automated memmory mapping. Can be an int in Bytes,
+ or a human-readable string, e.g., '1M' for 1 megabyte.
+ Use None to disable memmaping of large arrays. Use 'auto' to
+ use the value set using mne.set_memmap_min_size.
Returns
-------
@@ -36,22 +48,56 @@ def parallel_func(func, n_jobs, verbose=None):
n_jobs: int
Number of jobs >= 0
"""
+ # for a single job, we don't need joblib
+ if n_jobs == 1:
+ n_jobs = 1
+ my_func = func
+ parallel = list
+ return parallel, my_func, n_jobs
+
try:
- from sklearn.externals.joblib import Parallel, delayed
+ from joblib import Parallel, delayed
except ImportError:
try:
- from joblib import Parallel, delayed
+ from sklearn.externals.joblib import Parallel, delayed
except ImportError:
- logger.warn("joblib not installed. Cannot run in parallel.")
+ logger.warn('joblib not installed. Cannot run in parallel.')
n_jobs = 1
my_func = func
parallel = list
return parallel, my_func, n_jobs
- parallel_verbose = 5 if logger.level <= logging.INFO else 0
- parallel = Parallel(n_jobs, verbose=parallel_verbose)
- my_func = delayed(func)
+ # check if joblib is recent enough to support memmaping
+ aspec = inspect.getargspec(Parallel.__init__)
+ joblib_mmap = ('temp_folder' in aspec.args and 'max_nbytes' in aspec.args)
+
+ cache_dir = get_config('MNE_CACHE_DIR', None)
+ if isinstance(max_nbytes, basestring) and max_nbytes == 'auto':
+ max_nbytes = get_config('MNE_MEMMAP_MIN_SIZE', None)
+
+ if max_nbytes is not None:
+ if not joblib_mmap and cache_dir is not None:
+ logger.warn('"MNE_CACHE_DIR" is set but a newer version of joblib '
+ 'is needed to use the memmapping pool.')
+ if joblib_mmap and cache_dir is None:
+ logger.info('joblib supports memapping pool but "MNE_CACHE_DIR" '
+ 'is not set in MNE-Python config. To enable it, use, '
+ 'e.g., mne.set_cache_dir(\'/tmp/shm\'). This will '
+ 'store temporary files under /dev/shm and can result '
+ 'in large memory savings.')
+
+ # create keyword arguments for Parallel
+ kwargs = {'verbose': 5 if logger.level <= logging.INFO else 0}
+
+ if joblib_mmap:
+ if cache_dir is None:
+ max_nbytes = None # disable memmaping
+ kwargs['temp_folder'] = cache_dir
+ kwargs['max_nbytes'] = max_nbytes
+
n_jobs = check_n_jobs(n_jobs)
+ parallel = Parallel(n_jobs, **kwargs)
+ my_func = delayed(func)
return parallel, my_func, n_jobs
@@ -71,7 +117,11 @@ def check_n_jobs(n_jobs, allow_cuda=False):
The checked number of jobs. Always positive (or 'cuda' if
applicable.)
"""
- if not isinstance(n_jobs, int):
+ if _force_serial:
+ n_jobs = 1
+ logger.info('... MNE_FORCE_SERIAL set. Processing in forced serial mode.')
+
+ elif not isinstance(n_jobs, int):
if not allow_cuda:
raise ValueError('n_jobs must be an integer')
elif not isinstance(n_jobs, basestring) or n_jobs != 'cuda':
@@ -90,7 +140,7 @@ def check_n_jobs(n_jobs, allow_cuda=False):
# only warn if they tried to use something other than 1 job
if n_jobs != 1:
logger.warn('multiprocessing not installed. Cannot run in '
- 'parallel.')
+ 'parallel.')
n_jobs = 1
return n_jobs
diff --git a/mne/preprocessing/__init__.py b/mne/preprocessing/__init__.py
index 30c6f41..787a56c 100644
--- a/mne/preprocessing/__init__.py
+++ b/mne/preprocessing/__init__.py
@@ -11,5 +11,5 @@ from .maxfilter import apply_maxfilter
from .ssp import compute_proj_ecg, compute_proj_eog
from .eog import find_eog_events
from .ecg import find_ecg_events
-from .ica import ICA, ica_find_eog_events, ica_find_ecg_events, score_funcs, \
- read_ica, run_ica
+from .ica import (ICA, ica_find_eog_events, ica_find_ecg_events, score_funcs,
+ read_ica, run_ica)
diff --git a/mne/preprocessing/ecg.py b/mne/preprocessing/ecg.py
index 871cbbb..2f3dd63 100644
--- a/mne/preprocessing/ecg.py
+++ b/mne/preprocessing/ecg.py
@@ -1,9 +1,7 @@
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-
-from .. import fiff, verbose
+from ..fiff import pick_types, pick_channels
+from ..utils import logger, verbose, sum_squared
from ..filter import band_pass_filter
@@ -19,8 +17,9 @@ def qrs_detector(sfreq, ecg, thresh_value=0.6, levels=2.5, n_thresh=3,
Sampling rate
ecg : array
ECG signal
- thresh_value : float
- qrs detection threshold
+ thresh_value : float | str
+ qrs detection threshold. Can also be "auto" for automatic
+ selection of threshold.
levels : float
number of std from mean to include for detection
n_thresh : int
@@ -44,55 +43,80 @@ def qrs_detector(sfreq, ecg, thresh_value=0.6, levels=2.5, n_thresh=3,
filtecg = band_pass_filter(ecg, sfreq, l_freq, h_freq,
filter_length=filter_length)
- absecg = np.abs(filtecg)
+ ecg_abs = np.abs(filtecg)
init = int(sfreq)
- n_samples_start = int(init * tstart)
- absecg = absecg[n_samples_start:]
+ n_samples_start = int(sfreq * tstart)
+ ecg_abs = ecg_abs[n_samples_start:]
- n_points = len(absecg)
+ n_points = len(ecg_abs)
maxpt = np.empty(3)
- maxpt[0] = np.max(absecg[:init])
- maxpt[1] = np.max(absecg[init:init * 2])
- maxpt[2] = np.max(absecg[init * 2:init * 3])
+ maxpt[0] = np.max(ecg_abs[:init])
+ maxpt[1] = np.max(ecg_abs[init:init * 2])
+ maxpt[2] = np.max(ecg_abs[init * 2:init * 3])
init_max = np.mean(maxpt)
- thresh1 = init_max * thresh_value
-
- numcross = []
- time = []
- rms = []
- i = 0
- while i < (n_points - win_size):
- window = absecg[i:i + win_size]
- if window[0] > thresh1:
- maxTime = np.argmax(window)
- time.append(i + maxTime)
- numcross.append(np.sum(np.diff((window > thresh1).astype(np.int)
- == 1)))
- rms.append(np.sqrt(np.mean(window ** 2)))
- i += win_size
- else:
- i += 1
-
- time = np.array(time)
- rms_mean = np.mean(rms)
- rms_std = np.std(rms)
- rms_thresh = rms_mean + (rms_std * levels)
- b = np.where(rms < rms_thresh)[0]
- a = np.array(numcross)[b]
- clean_events = time[b[a < n_thresh]]
-
- clean_events += n_samples_start
-
+ if thresh_value == 'auto':
+ thresh_runs = np.arange(0.3, 1.1, 0.05)
+ elif isinstance(thresh_value, basestring):
+ raise ValueError('threshold value must be "auto" or a float')
+ else:
+ thresh_runs = [thresh_value]
+
+ # Try a few thresholds (or just one)
+ clean_events = list()
+ for thresh_value in thresh_runs:
+ thresh1 = init_max * thresh_value
+ numcross = list()
+ time = list()
+ rms = list()
+ ii = 0
+ while ii < (n_points - win_size):
+ window = ecg_abs[ii:ii + win_size]
+ if window[0] > thresh1:
+ max_time = np.argmax(window)
+ time.append(ii + max_time)
+ nx = np.sum(np.diff((window > thresh1).astype(np.int) == 1))
+ numcross.append(nx)
+ rms.append(np.sqrt(sum_squared(window) / window.size))
+ ii += win_size
+ else:
+ ii += 1
+
+ if len(rms) == 0:
+ rms.append(0.0)
+ time.append(0.0)
+ time = np.array(time)
+ rms_mean = np.mean(rms)
+ rms_std = np.std(rms)
+ rms_thresh = rms_mean + (rms_std * levels)
+ b = np.where(rms < rms_thresh)[0]
+ a = np.array(numcross)[b]
+ ce = time[b[a < n_thresh]]
+
+ ce += n_samples_start
+ clean_events.append(ce)
+
+ # pick the best threshold; first get effective heart rates
+ rates = np.array([60. * len(ce) / (len(ecg) / float(sfreq))
+ for ce in clean_events])
+
+ # now find heart rates that seem reasonable (infant thru adult athlete)
+ idx = np.where(np.logical_and(rates <= 160., rates >= 40.))[0]
+ if len(idx) > 0:
+ ideal_rate = np.median(rates[idx]) # get close to the median
+ else:
+ ideal_rate = 80. # get close to a reasonable default
+ idx = np.argmin(np.abs(rates - ideal_rate))
+ clean_events = clean_events[idx]
return clean_events
@verbose
def find_ecg_events(raw, event_id=999, ch_name=None, tstart=0.0,
- l_freq=5, h_freq=35, qrs_threshold=0.6,
+ l_freq=5, h_freq=35, qrs_threshold='auto',
filter_length='10s', verbose=None):
"""Find ECG peaks
@@ -113,8 +137,10 @@ def find_ecg_events(raw, event_id=999, ch_name=None, tstart=0.0,
Low pass frequency.
h_freq : float
High pass frequency.
- qrs_threshold : float
- Between 0 and 1. qrs detection threshold.
+ qrs_threshold : float | str
+ Between 0 and 1. qrs detection threshold. Can also be "auto" to
+ automatically choose the threshold that generates a reasonable
+ number of heartbeats (40-160 beats / min).
filter_length : str | int | None
Number of taps to use for filtering.
verbose : bool, str, int, or None
@@ -133,11 +159,11 @@ def find_ecg_events(raw, event_id=999, ch_name=None, tstart=0.0,
# Geting ECG Channel
if ch_name is None:
- ch_ECG = fiff.pick_types(info, meg=False, eeg=False, stim=False,
- eog=False, ecg=True, emg=False,
- exclude='bads')
+ ch_ECG = pick_types(info, meg=False, eeg=False, stim=False,
+ eog=False, ecg=True, emg=False, ref_meg=False,
+ exclude='bads')
else:
- ch_ECG = fiff.pick_channels(raw.ch_names, include=[ch_name])
+ ch_ECG = pick_channels(raw.ch_names, include=[ch_name])
if len(ch_ECG) == 0:
raise ValueError('%s not in channel list (%s)' %
(ch_name, raw.ch_names))
diff --git a/mne/preprocessing/eog.py b/mne/preprocessing/eog.py
index 80e603d..7da7158 100644
--- a/mne/preprocessing/eog.py
+++ b/mne/preprocessing/eog.py
@@ -1,10 +1,8 @@
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-
from .peak_finder import peak_finder
-from .. import fiff, verbose
+from ..fiff import pick_types, pick_channels
+from ..utils import logger, verbose
from ..filter import band_pass_filter
@@ -43,14 +41,14 @@ def find_eog_events(raw, event_id=998, l_freq=1, h_freq=10,
# Getting EOG Channel
if ch_name is None:
- ch_eog = fiff.pick_types(info, meg=False, eeg=False, stim=False,
- eog=True, ecg=False, emg=False,
- exclude='bads')
+ ch_eog = pick_types(info, meg=False, eeg=False, stim=False,
+ eog=True, ecg=False, emg=False, ref_meg=False,
+ exclude='bads')
if len(ch_eog) == 0:
logger.info('No EOG channels found')
logger.info('Trying with EEG 061 and EEG 062')
- ch_eog = fiff.pick_channels(raw.ch_names,
- include=['EEG 061', 'EEG 062'])
+ ch_eog = pick_channels(raw.ch_names,
+ include=['EEG 061', 'EEG 062'])
if len(ch_eog) != 2:
raise ValueError('EEG 61 or EEG 62 channel not found !!')
@@ -62,13 +60,13 @@ def find_eog_events(raw, event_id=998, l_freq=1, h_freq=10,
else:
ch_name = [ch_name]
- ch_eog = fiff.pick_channels(raw.ch_names, include=ch_name)
+ ch_eog = pick_channels(raw.ch_names, include=ch_name)
if len(ch_eog) == 0:
raise ValueError('%s not in channel list' % ch_name)
else:
logger.info('Using channel %s as EOG channel%s' % (
- " and ".join(ch_name), '' if len(ch_eog) < 2 else 's'))
+ " and ".join(ch_name), '' if len(ch_eog) < 2 else 's'))
logger.info('EOG channel index for this subject is: %s' % ch_eog)
@@ -92,7 +90,8 @@ def _find_eog_events(eog, event_id, l_freq, h_freq, sampling_rate, first_samp,
'distinguish blinks from saccades')
# filtering to remove dc offset so that we know which is blink and saccades
- filteog = np.array([band_pass_filter(x, sampling_rate, 2, 45,
+ fmax = np.minimum(45, sampling_rate / 2.0 - 0.75) # protect Nyquist
+ filteog = np.array([band_pass_filter(x, sampling_rate, 2, fmax,
filter_length=filter_length)
for x in eog])
temp = np.sqrt(np.sum(filteog ** 2, axis=1))
@@ -120,4 +119,4 @@ def _find_eog_events(eog, event_id, l_freq, h_freq, sampling_rate, first_samp,
eog_events = np.c_[eog_events + first_samp, np.zeros(n_events),
event_id * np.ones(n_events)]
- return eog_events
\ No newline at end of file
+ return eog_events
diff --git a/mne/preprocessing/ica.py b/mne/preprocessing/ica.py
index 41deb11..8f904a6 100644
--- a/mne/preprocessing/ica.py
+++ b/mne/preprocessing/ica.py
@@ -4,16 +4,14 @@
#
# License: BSD (3-clause)
-from copy import deepcopy
-import inspect
import warnings
+from copy import deepcopy
from inspect import getargspec, isfunction
from collections import namedtuple
+from math import ceil
import os
import json
-import logging
-logger = logging.getLogger('mne')
import numpy as np
from scipy import stats
@@ -25,17 +23,25 @@ from .eog import _find_eog_events
from ..cov import compute_whitener
from .. import Covariance
-from ..fiff.pick import pick_types, pick_channels
-from ..fiff.write import write_double_matrix, write_string, \
- write_name_list, write_int, start_block, \
- end_block
+from ..fiff.pick import (pick_types, pick_channels, pick_info,
+ channel_indices_by_type)
+from ..fiff.write import (write_double_matrix, write_string,
+ write_name_list, write_int, start_block,
+ end_block)
from ..fiff.tree import dir_tree_find
from ..fiff.open import fiff_open
from ..fiff.tag import read_tag
+from ..fiff.meas_info import write_meas_info, read_meas_info
from ..fiff.constants import Bunch, FIFF
-from ..viz import plot_ica_panel
-from .. import verbose
-from ..fiff.write import start_file, end_file
+from ..viz import plot_ica_panel, plot_ica_topomap
+from ..fiff.write import start_file, end_file, write_id
+from ..epochs import _is_good
+from ..utils import check_sklearn_version, logger, verbose
+
+try:
+ from sklearn.utils.extmath import fast_dot
+except ImportError:
+ fast_dot = np.dot
def _make_xy_sfunc(func, ndim_output=False):
@@ -96,7 +102,7 @@ class ICA(object):
The number of components used for PCA decomposition. If None, no
dimension reduction will be applied and max_pca_components will equal
the number of channels supplied on decomposing data.
- n_pca_components : int
+ n_pca_components : int | float
The number of PCA components used after ICA recomposition. The ensuing
attribute allows to balance noise reduction against potential loss of
features due to dimensionality reduction. If greater than
@@ -104,6 +110,9 @@ class ICA(object):
`n_components_` PCA components will be added before restoring the
sensor space data. The attribute gets updated each time the according
parameter for in .pick_sources_raw or .pick_sources_epochs is changed.
+ If float, the number of components selected matches the number of
+ components with a cumulative explained variance below
+ `n_pca_components`.
noise_cov : None | instance of mne.cov.Covariance
Noise covariance used for whitening. If None, channels are just
z-scored.
@@ -161,13 +170,21 @@ class ICA(object):
.exclude attribute. When saving the ICA also the indices are restored.
Hence, artifact components once identified don't have to be added
again. To dump this 'artifact memory' say: ica.exclude = []
-
+ info : None | instance of mne.fiff.meas_info.Info
+ The measurement info copied from the object fitted.
+ `n_samples_` : int
+ the number of samples used on fit.
"""
@verbose
def __init__(self, n_components, max_pca_components=100,
n_pca_components=64, noise_cov=None, random_state=None,
algorithm='parallel', fun='logcosh', fun_args=None,
verbose=None):
+
+ if not check_sklearn_version(min_version='0.12'):
+ raise RuntimeError('the scikit-learn package (version >= 0.12)'
+ 'is required for ICA')
+
self.noise_cov = noise_cov
if max_pca_components is not None and \
@@ -186,11 +203,12 @@ class ICA(object):
self.max_pca_components = max_pca_components
self.n_pca_components = n_pca_components
self.ch_names = None
- self.random_state = random_state
+ self.random_state = random_state if random_state is not None else 0
self.algorithm = algorithm
self.fun = fun
self.fun_args = fun_args
self.exclude = []
+ self.info = None
def __repr__(self):
"""ICA fit information"""
@@ -201,6 +219,7 @@ class ICA(object):
else:
s = 'epochs'
s += ' decomposition, '
+ s += 'fit: %s samples, ' % str(getattr(self, 'n_samples_', ''))
s += ('%s components' % str(self.n_components_) if
hasattr(self, 'n_components_') else
'no dimension reduction')
@@ -211,6 +230,7 @@ class ICA(object):
@verbose
def decompose_raw(self, raw, picks=None, start=None, stop=None,
+ decim=None, reject=None, flat=None, tstep=2.0,
verbose=None):
"""Run the ICA decomposition on raw data
@@ -232,6 +252,21 @@ class ICA(object):
stop : int | float | None
Last sample to not include. If float, data will be interpreted as
time in seconds. If None, data will be used to the last sample.
+ decim : int | None
+ Increment for selecting each nth time slice. If None, all samples
+ within ``start`` and ``stop`` are used.
+ reject : dict | None
+ Rejection parameters based on peak to peak amplitude.
+ Valid keys are 'grad' | 'mag' | 'eeg' | 'eog' | 'ecg'.
+ If reject is None then no rejection is done. You should
+ use such parameters to reject big measurement artifacts
+ and not EOG for example.
+ flat : dict | None
+ Rejection parameters based on flatness of signal
+ Valid keys are 'grad' | 'mag' | 'eeg' | 'eog' | 'ecg'
+ If flat is None then no rejection is done.
+ tstep : float
+ Length of data chunks for artefact rejection in seconds.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
Defaults to self.verbose.
@@ -257,9 +292,46 @@ class ICA(object):
self.max_pca_components = len(picks)
logger.info('Inferring max_pca_components from picks.')
- self.ch_names = [raw.ch_names[k] for k in picks]
+ self.info = pick_info(raw.info, picks)
+ if self.info['comps']:
+ self.info['comps'] = []
+ self.ch_names = self.info['ch_names']
start, stop = _check_start_stop(raw, start, stop)
- data, self._pre_whitener = self._pre_whiten(raw[picks, start:stop][0],
+
+ data = raw[picks, start:stop][0]
+ if decim is not None:
+ data = data[:, ::decim].copy()
+
+ if (reject is not None) or (flat is not None):
+ info = self.info
+ data_clean = np.empty_like(data)
+ idx_by_type = channel_indices_by_type(info)
+ step = int(ceil(tstep * info['sfreq']))
+ if decim is not None:
+ step = int(ceil(step / float(decim)))
+ this_start = 0
+ this_stop = 0
+ for first in xrange(0, data.shape[1], step):
+ last = first + step
+ data_buffer = data[:, first:last]
+ if data_buffer.shape[1] < (last - first):
+ break # end of the time segment
+ if _is_good(data_buffer, info['ch_names'], idx_by_type, reject,
+ flat, ignore_chs=info['bads']):
+ this_stop = this_start + data_buffer.shape[1]
+ data_clean[:, this_start:this_stop] = data_buffer
+ this_start += data_buffer.shape[1]
+ else:
+ logger.info("Artifact detected in [%d, %d]" % (first,
+ last))
+ data = data_clean[:, :this_stop]
+ self.n_samples_ = data.shape[1]
+ if not data.any():
+ raise RuntimeError('No clean segment found. Please '
+ 'consider updating your rejection '
+ 'thresholds.')
+
+ data, self._pre_whitener = self._pre_whiten(data,
raw.info, picks)
self._decompose(data, self.max_pca_components, 'raw')
@@ -267,7 +339,7 @@ class ICA(object):
return self
@verbose
- def decompose_epochs(self, epochs, picks=None, verbose=None):
+ def decompose_epochs(self, epochs, picks=None, decim=None, verbose=None):
"""Run the ICA decomposition on epochs
Caveat! If supplying a noise covariance keep track of the projections
@@ -283,6 +355,9 @@ class ICA(object):
Channels to be included relative to the channels already picked on
epochs-initialization. This selection remains throughout the
initialized ICA session.
+ decim : int | None
+ Increment for selecting each nth time slice. If None, all samples
+ within ``start`` and ``stop`` are used.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
Defaults to self.verbose.
@@ -300,31 +375,43 @@ class ICA(object):
'Please be patient, this may take some time')
if picks is None:
- # just use epochs good data channels and avoid double picking
- picks = pick_types(epochs.info, include=epochs.ch_names,
- exclude='bads')
-
- meeg_picks = pick_types(epochs.info, meg=True, eeg=True, eog=False,
- ecg=False, misc=False, stim=False,
- exclude='bads')
+ picks = pick_types(epochs.info, meg=True, eeg=True, eog=False,
+ ecg=False, misc=False, stim=False,
+ ref_meg=False, exclude='bads')
# filter out all the channels the raw wouldn't have initialized
- picks = np.intersect1d(meeg_picks, picks)
-
- self.ch_names = [epochs.ch_names[k] for k in picks]
+ self.info = pick_info(epochs.info, picks)
+ if self.info['comps']:
+ self.info['comps'] = []
+ self.ch_names = self.info['ch_names']
if self.max_pca_components is None:
self.max_pca_components = len(picks)
logger.info('Inferring max_pca_components from picks.')
+ data = epochs.get_data()[:, picks]
+ if decim is not None:
+ data = data[:, :, ::decim].copy()
+ self.n_samples_ = np.prod(data.shape[1:])
+
data, self._pre_whitener = \
- self._pre_whiten(np.hstack(epochs.get_data()[:, picks]),
- epochs.info, picks)
+ self._pre_whiten(np.hstack(data), epochs.info, picks)
self._decompose(data, self.max_pca_components, 'epochs')
return self
+ def _get_sources(self, data):
+ """Compute sources from data (operates inplace)"""
+ if self.pca_mean_ is not None:
+ data -= self.pca_mean_[:, None]
+
+ # Apply first PCA
+ pca_data = fast_dot(self.pca_components_[:self.n_components_], data)
+ # Apply unmixing to low dimension PCA
+ sources = fast_dot(self.unmixing_matrix_, pca_data)
+ return sources
+
def get_sources_raw(self, raw, start=None, stop=None):
"""Estimate raw sources given the unmixing matrix
@@ -348,17 +435,10 @@ class ICA(object):
raise RuntimeError('No fit available. Please first fit ICA '
'decomposition.')
start, stop = _check_start_stop(raw, start, stop)
- return self._get_sources_raw(raw, start, stop)[0]
-
- def _get_sources_raw(self, raw, start, stop):
- """Aux function"""
picks = [raw.ch_names.index(k) for k in self.ch_names]
data, _ = self._pre_whiten(raw[picks, start:stop][0], raw.info, picks)
- pca_data = self._transform_pca(data.T)
- n_components = self.n_components_
- raw_sources = self._transform_ica(pca_data[:, :n_components]).T
- return raw_sources, pca_data
+ return self._get_sources(data)
def get_sources_epochs(self, epochs, concatenate=False):
"""Estimate epochs sources given the unmixing matrix
@@ -379,11 +459,8 @@ class ICA(object):
raise RuntimeError('No fit available. Please first fit ICA '
'decomposition.')
- return self._get_sources_epochs(epochs, concatenate)[0]
-
- def _get_sources_epochs(self, epochs, concatenate):
-
- picks = pick_types(epochs.info, include=self.ch_names, exclude=[])
+ picks = pick_types(epochs.info, include=self.ch_names, exclude=[],
+ ref_meg=False)
# special case where epochs come picked but fit was 'unpicked'.
if len(picks) != len(self.ch_names):
@@ -393,17 +470,15 @@ class ICA(object):
'ica.ch_names' % (len(self.ch_names),
len(picks)))
- data, _ = self._pre_whiten(np.hstack(epochs.get_data()[:, picks]),
- epochs.info, picks)
+ data = np.hstack(epochs.get_data()[:, picks])
+ data, _ = self._pre_whiten(data, epochs.info, picks)
+ sources = self._get_sources(data)
- pca_data = self._transform_pca(data.T)
- sources = self._transform_ica(pca_data[:, :self.n_components_]).T
- sources = np.array(np.split(sources, len(epochs.events), 1))
+ if not concatenate:
+ # Put the data back in 3D
+ sources = np.array(np.split(sources, len(epochs.events), 1))
- if concatenate:
- sources = np.hstack(sources)
-
- return sources, pca_data
+ return sources
@verbose
def save(self, fname):
@@ -458,21 +533,19 @@ class ICA(object):
ecg=True, eog=True, stim=True, exclude='bads')
# merge copied instance and picked data with sources
-
start, stop = _check_start_stop(raw, start, stop)
sources = self.get_sources_raw(raw, start=start, stop=stop)
- if raw._preloaded:
+ if raw._preloaded: # get data and temporarily delete
data, times = raw._data, raw._times
- del raw._data
- del raw._times
+ del raw._data, raw._times
- out = raw.copy()
+ out = raw.copy() # copy and reappend
if raw._preloaded:
raw._data, raw._times = data, times
+ # populate copied raw.
out.fids = []
data_, times_ = raw[picks, start:stop]
-
out._data = np.r_[sources, data_]
out._times = times_
out._preloaded = True
@@ -481,6 +554,7 @@ class ICA(object):
out.first_samp = raw.first_samp + (start if start else 0)
out.last_samp = out.first_samp + stop if stop else raw.last_samp
+ # XXX use self.info later, for now this is better
self._export_info(out.info, raw, picks)
out._projector = None
@@ -496,11 +570,13 @@ class ICA(object):
this_source = 'ICA %03d' % (ii + 1)
ch_names.append(this_source)
ch_info.append(dict(ch_name=this_source, cal=1,
- logno=ii + 1, coil_type=FIFF.FIFFV_COIL_NONE,
- kind=FIFF.FIFFV_MISC_CH, coord_Frame=FIFF.FIFFV_COORD_UNKNOWN,
- loc=np.array([0., 0., 0., 1.] * 3, dtype='f4'),
- unit=FIFF.FIFF_UNIT_NONE, eeg_loc=None, range=1.0,
- scanno=ii + 1, unit_mul=0, coil_trans=None))
+ logno=ii + 1, coil_type=FIFF.FIFFV_COIL_NONE,
+ kind=FIFF.FIFFV_MISC_CH,
+ coord_Frame=FIFF.FIFFV_COORD_UNKNOWN,
+ loc=np.array([0., 0., 0., 1.] * 3, dtype='f4'),
+ unit=FIFF.FIFF_UNIT_NONE, eeg_loc=None,
+ range=1.0, scanno=ii + 1, unit_mul=0,
+ coil_trans=None))
# re-append additionally picked ch_names
ch_names += [container.ch_names[k] for k in picks]
@@ -537,7 +613,7 @@ class ICA(object):
ecg=True, eog=True, stim=True, exclude='bads')
out._data = np.concatenate([sources, epochs.get_data()[:, picks]],
- axis=1) if len(picks) > 0 else sources
+ axis=1) if len(picks) > 0 else sources
self._export_info(out.info, epochs, picks)
out.preload = True
@@ -547,7 +623,7 @@ class ICA(object):
return out
def plot_sources_raw(self, raw, order=None, start=None, stop=None,
- n_components=None, source_idx=None, ncol=3, nrow=10,
+ n_components=None, source_idx=None, ncol=3, nrow=None,
title=None, show=True):
"""Create panel plots of ICA sources. Wrapper around viz.plot_ica_panel
@@ -556,8 +632,8 @@ class ICA(object):
raw : instance of mne.fiff.Raw
Raw object to plot the sources from.
order : ndarray | None.
- Index of length `n_components_`. If None, plot will show the sources
- in the order as fitted.
+ Index of length `n_components_`. If None, plot will show the
+ sources in the order as fitted.
Example::
arg_sort = np.argsort(np.var(sources)).
@@ -574,7 +650,7 @@ class ICA(object):
Number of panel-columns. If None, the entire data will be plotted.
nrow : int | None
Number of panel-rows. If None, the entire data will be plotted.
- title : str
+ title : str | None
The figure title. If None a default is provided.
show : bool
If True, plot will be shown, else just the figure is returned.
@@ -587,41 +663,38 @@ class ICA(object):
sources = self.get_sources_raw(raw, start=start, stop=stop)
if order is not None:
- if len(order) != sources.shape[0]:
- raise ValueError('order and sources have to be of the '
- 'same length.')
- else:
- sources = sources[order]
-
- fig = plot_ica_panel(sources, start=0 if start is not None else start,
- stop=(stop - start) if stop is not None else stop,
- n_components=n_components, source_idx=source_idx,
- ncol=ncol, nrow=nrow, title=title)
+ if np.isscalar(order):
+ order = [order]
+ sources = sources[order]
+ fig = plot_ica_panel(sources, n_components=n_components,
+ source_idx=source_idx, ncol=ncol, nrow=nrow,
+ title=title)
if show:
- import matplotlib.pylab as pl
- pl.show()
+ import matplotlib.pyplot as plt
+ plt.show()
return fig
- def plot_sources_epochs(self, epochs, epoch_idx=None, order=None,
+ def plot_sources_epochs(self, epochs, order=None, epoch_idx=None,
start=None, stop=None, n_components=None,
- source_idx=None, ncol=3, nrow=10, show=True):
+ source_idx=None, ncol=3, nrow=None, title=None,
+ show=True):
"""Create panel plots of ICA sources. Wrapper around viz.plot_ica_panel
Parameters
----------
epochs : instance of mne.Epochs
Epochs object to plot the sources from.
- epoch_idx : int
- Index to plot particular epoch.
order : ndarray | None.
Index of length n_components. If None, plot will show the sources
in the order as fitted.
Example: arg_sort = np.argsort(np.var(sources)).
- start : int | None
+ epoch_idx : int
+ Index to plot particular epoch.
+ start : int | float | None
First sample to include. If None, data will be shown from the first
sample.
- stop : int | None
+ stop : int | float | None
Last sample to not include. If None, data will be shown to the last
sample.
n_components : int
@@ -632,6 +705,8 @@ class ICA(object):
Number of panel-columns.
nrow : int
Number of panel-rows.
+ title : str | None
+ The figure title. If None a default is provided.
show : bool
If True, plot will be shown, else just the figure is returned.
@@ -639,20 +714,18 @@ class ICA(object):
-------
fig : instance of pyplot.Figure
"""
- sources = self.get_sources_epochs(epochs, concatenate=True if epoch_idx
- is None else False)
- source_dim = 1 if sources.ndim > 2 else 0
+ sources = self.get_sources_epochs(epochs, concatenate=True)
if order is not None:
- if len(order) != sources.shape[source_dim]:
- raise ValueError('order and sources have to be of the '
- 'same length.')
- else:
- sources = (sources[:, order] if source_dim
- else sources[order])
-
- fig = plot_ica_panel(sources[epoch_idx], start=start, stop=stop,
+ if np.isscalar(order):
+ order = [order]
+ sources = np.atleast_2d(sources[order])
+ if epoch_idx is not None:
+ warnings.warn('`epochs_idx` is deprecated and will be removed in '
+ 'MNE-Python 0.8. Instead plass indexed epochs.')
+
+ fig = plot_ica_panel(sources, start=start, stop=stop,
n_components=n_components, source_idx=source_idx,
- ncol=ncol, nrow=nrow, show=show)
+ ncol=ncol, nrow=nrow, title=title, show=show)
return fig
@@ -769,13 +842,15 @@ class ICA(object):
The source indices to use. If None all are used.
exclude : list-like | None
The source indices to remove. If None all are used.
- n_pca_components : int
+ n_pca_components : int | float
The number of PCA components to be unwhitened, where
`n_components_` is the lower bound and max_pca_components
the upper bound. If greater than `self.n_components_`, the next
`n_pca_components` minus 'n_components' PCA components will
be added before restoring the sensor space data. This can be used
- to take back the PCA dimension reduction.
+ to take back the PCA dimension reduction. If float, the number of
+ components selected matches the number of components with a
+ cumulative explained variance below `n_pca_components`.
start : int | float | None
First sample to include. If float, data will be interpreted as
time in seconds. If None, data will be used from the first sample.
@@ -810,15 +885,19 @@ class ICA(object):
self.n_pca_components = n_pca_components
start, stop = _check_start_stop(raw, start, stop)
- sources, pca_data = self._get_sources_raw(raw, start=start, stop=stop)
- recomposed = self._pick_sources(sources, pca_data, include,
- self.exclude)
+
+ picks = pick_types(raw.info, meg=False, include=self.ch_names,
+ exclude='bads')
+
+ data = raw[picks, start:stop][0]
+ data, _ = self._pre_whiten(data, raw.info, picks)
+
+ data = self._pick_sources(data, include, self.exclude)
if copy is True:
raw = raw.copy()
- picks = [raw.ch_names.index(k) for k in self.ch_names]
- raw[picks, start:stop] = recomposed
+ raw[picks, start:stop] = data
return raw
def pick_sources_epochs(self, epochs, include=None, exclude=None,
@@ -834,13 +913,15 @@ class ICA(object):
The source indices to use. If None all are used.
exclude : list-like | None
The source indices to remove. If None all are used.
- n_pca_components : int
+ n_pca_components : int | float
The number of PCA components to be unwhitened, where
`n_components_` is the lower bound and max_pca_components
the upper bound. If greater than `self.n_components_`, the next
`n_pca_components` minus `n_components_` PCA components will
be added before restoring the sensor space data. This can be used
- to take back the PCA dimension reduction.
+ to take back the PCA dimension reduction. If float, the number of
+ components selected matches the number of components with a
+ cumulative explained variance below `n_pca_components`.
copy : bool
Modify Epochs instance in place or return modified copy.
@@ -854,39 +935,78 @@ class ICA(object):
'working. Please read raw data with '
'preload=True.')
- sources, pca_data = self._get_sources_epochs(epochs, True)
- picks = pick_types(epochs.info, include=self.ch_names,
+ picks = pick_types(epochs.info, meg=False, ref_meg=False,
+ include=self.ch_names,
exclude='bads')
- if copy is True:
- epochs = epochs.copy()
-
- if exclude is None:
- self.exclude = list(set(self.exclude))
- else:
- self.exclude = list(set(self.exclude + exclude))
- logger.info('Adding sources %s to .exclude' % ', '.join(
- [str(i) for i in exclude if i not in self.exclude]))
+ # special case where epochs come picked but fit was 'unpicked'.
+ if len(picks) != len(self.ch_names):
+ raise RuntimeError('Epochs don\'t match fitted data: %i channels '
+ 'fitted but %i channels supplied. \nPlease '
+ 'provide Epochs compatible with '
+ 'ica.ch_names' % (len(self.ch_names),
+ len(picks)))
if n_pca_components is not None:
self.n_pca_components = n_pca_components
- # put sources-dimension first for selection
- recomposed = self._pick_sources(sources, pca_data, include,
- self.exclude)
+ data = np.hstack(epochs.get_data()[:, picks])
+ data, _ = self._pre_whiten(data, epochs.info, picks)
+ data = self._pick_sources(data, include=include,
+ exclude=exclude)
+
+ if copy is True:
+ epochs = epochs.copy()
# restore epochs, channels, tsl order
- epochs._data[:, picks] = np.array(np.split(recomposed,
+ epochs._data[:, picks] = np.array(np.split(data,
len(epochs.events), 1))
epochs.preload = True
return epochs
+ def plot_topomap(self, source_idx, ch_type='mag', res=500, layout=None,
+ vmax=None, cmap='RdBu_r', sensors='k,', colorbar=True,
+ show=True):
+ """Plot topographic map of ICA source
+
+ Parameters
+ ----------
+ source_idx : int | array-like
+ The indices of the sources to be plotted.
+ ch_type : 'mag' | 'grad' | 'planar1' | 'planar2' | 'eeg'
+ The channel type to plot. For 'grad', the gradiometers are
+ collected in pairs and the RMS for each pair is plotted.
+ layout : None | Layout
+ Layout instance specifying sensor positions (does not need to
+ be specified for Neuromag data). If possible, the correct layout is
+ inferred from the data.
+ vmax : scalar
+ The value specfying the range of the color scale (-vmax to +vmax).
+ If None, the largest absolute value in the data is used.
+ cmap : matplotlib colormap
+ Colormap.
+ sensors : bool | str
+ Add markers for sensor locations to the plot. Accepts matplotlib
+ plot format string (e.g., 'r+' for red plusses).
+ colorbar : bool
+ Plot a colorbar.
+ res : int
+ The resolution of the topomap image (n pixels along each side).
+ show : bool
+ Call pyplot.show() at the end.
+ """
+ return plot_ica_topomap(self, source_idx=source_idx, ch_type=ch_type,
+ res=res, layout=layout, vmax=vmax, cmap=cmap,
+ sensors=sensors, colorbar=colorbar, show=show)
+
def detect_artifacts(self, raw, start_find=None, stop_find=None,
- ecg_ch=None, ecg_score_func='pearsonr', ecg_criterion=0.1,
- eog_ch=None, eog_score_func='pearsonr', eog_criterion=0.1,
- skew_criterion=-1, kurt_criterion=-1, var_criterion=0,
- add_nodes=None):
+ ecg_ch=None, ecg_score_func='pearsonr',
+ ecg_criterion=0.1, eog_ch=None,
+ eog_score_func='pearsonr',
+ eog_criterion=0.1, skew_criterion=-1,
+ kurt_criterion=-1, var_criterion=0,
+ add_nodes=None):
"""Run ICA artifacts detection workflow.
Hints and caveats:
@@ -972,15 +1092,17 @@ class ICA(object):
The ica object with the detected artifact indices marked for
exclusion
"""
-
logger.info(' Searching for artifacts...')
_detect_artifacts(self, raw=raw, start_find=start_find,
- stop_find=stop_find, ecg_ch=ecg_ch,
- ecg_score_func=ecg_score_func, ecg_criterion=ecg_criterion,
- eog_ch=eog_ch, eog_score_func=eog_score_func,
- eog_criterion=eog_criterion, skew_criterion=skew_criterion,
- kurt_criterion=kurt_criterion, var_criterion=var_criterion,
- add_nodes=add_nodes)
+ stop_find=stop_find, ecg_ch=ecg_ch,
+ ecg_score_func=ecg_score_func,
+ ecg_criterion=ecg_criterion,
+ eog_ch=eog_ch, eog_score_func=eog_score_func,
+ eog_criterion=eog_criterion,
+ skew_criterion=skew_criterion,
+ kurt_criterion=kurt_criterion,
+ var_criterion=var_criterion,
+ add_nodes=add_nodes)
return self
@@ -996,9 +1118,9 @@ class ICA(object):
assert data.shape[0] == ncov['data'].shape[0]
pre_whitener, _ = compute_whitener(ncov, info, picks)
- data = np.dot(pre_whitener, data)
+ data = fast_dot(pre_whitener, data)
else:
- data = np.dot(self._pre_whitener, data)
+ data = fast_dot(self._pre_whitener, data)
pre_whitener = self._pre_whitener
return data, pre_whitener
@@ -1007,129 +1129,112 @@ class ICA(object):
"""Aux function """
from sklearn.decomposition import RandomizedPCA
- # sklearn < 0.11 does not support random_state argument
- kwargs = {'n_components': max_pca_components, 'whiten': False}
-
- aspec = inspect.getargspec(RandomizedPCA.__init__)
- if 'random_state' not in aspec.args:
- warnings.warn('RandomizedPCA does not support random_state '
- 'argument. Use scikit-learn to version 0.11 '
- 'or newer to get reproducible results.')
- else:
- kwargs['random_state'] = 0
-
- pca = RandomizedPCA(**kwargs)
- pca_data = pca.fit_transform(data.T)
+ # XXX fix copy==True later. Bug in sklearn, see PR #2273
+ pca = RandomizedPCA(n_components=max_pca_components, whiten=True,
+ copy=True)
+ data = pca.fit_transform(data.T)
if isinstance(self.n_components, float):
logger.info('Selecting PCA components by explained variance.')
n_components_ = np.sum(pca.explained_variance_ratio_.cumsum()
- < self.n_components)
- to_ica = pca_data[:, :n_components_]
+ <= self.n_components)
+ sel = slice(n_components_)
else:
logger.info('Selecting PCA components by number.')
if self.n_components is not None: # normal n case
- to_ica = pca_data[:, :self.n_components]
+ sel = slice(self.n_components)
else: # None case
logger.info('Using all PCA components.')
- to_ica = pca_data
+ sel = slice(len(pca.components_))
# the things to store for PCA
- self.pca_components_ = pca.components_
self.pca_mean_ = pca.mean_
- self.pca_explained_variance_ = pca.explained_variance_
- # and store number of components as it may be smaller than
- # pca.components_.shape[1]
- self.n_components_ = to_ica.shape[1]
+ self.pca_components_ = pca.components_
+ # unwhiten pca components and put scaling in unmixintg matrix later.
+ self.pca_explained_variance_ = exp_var = pca.explained_variance_
+ self.pca_components_ *= np.sqrt(exp_var[:, None])
+ del pca
+ # update number of components
+ self.n_components_ = sel.stop
+ if self.n_pca_components > len(self.pca_components_):
+ self.n_pca_components = len(self.pca_components_)
# Take care of ICA
- try:
- from sklearn.decomposition import FastICA # to avoid strong dep.
- except ImportError:
- raise Exception('the scikit-learn package is missing and '
- 'required for ICA')
-
- # sklearn < 0.11 does not support random_state argument for FastICA
- kwargs = {'algorithm': self.algorithm, 'fun': self.fun,
- 'fun_args': self.fun_args}
-
- if self.random_state is not None:
- aspec = inspect.getargspec(FastICA.__init__)
- if 'random_state' not in aspec.args:
- warnings.warn('random_state argument ignored, update '
- 'scikit-learn to version 0.11 or newer')
- else:
- kwargs['random_state'] = self.random_state
-
- ica = FastICA(**kwargs)
- ica.fit(to_ica)
-
- # For ICA the only thing to store is the unmixing matrix
- if not hasattr(ica, 'sources_'):
- self.unmixing_matrix_ = ica.unmixing_matrix_
- else:
- self.unmixing_matrix_ = ica.components_
-
- self.mixing_matrix_ = linalg.pinv(self.unmixing_matrix_).T
+ from sklearn.decomposition import FastICA # to avoid strong dep.
+ ica = FastICA(algorithm=self.algorithm, fun=self.fun,
+ fun_args=self.fun_args, whiten=False,
+ random_state=self.random_state)
+ ica.fit(data[:, sel])
+
+ # get unmixing and add scaling
+ self.unmixing_matrix_ = getattr(ica, 'components_', 'unmixing_matrix_')
+ self.unmixing_matrix_ /= np.sqrt(exp_var[sel])[None, :]
+ self.mixing_matrix_ = linalg.pinv(self.unmixing_matrix_)
self.current_fit = fit_type
- def _pick_sources(self, sources, pca_data, include, exclude):
+ def _pick_sources(self, data, include, exclude):
"""Aux function"""
+ if exclude is None:
+ exclude = self.exclude
+ else:
+ exclude = self.exclude = list(set(self.exclude + list(exclude)))
+
+ _n_pca_comp = _check_n_pca_components(self, self.n_pca_components,
+ self.verbose)
- _n_pca_comp = self.n_pca_components
if not(self.n_components_ <= _n_pca_comp <= self.max_pca_components):
- raise ValueError('n_pca_components must be between n_comp'
- 'onents and max_pca_components.')
+ raise ValueError('n_pca_components must be between '
+ 'n_components and max_pca_components.')
+
+ n_components = self.n_components_
+ n_pca_components = self.n_pca_components
+
+ # Apply first PCA
+ if self.pca_mean_ is not None:
+ data -= self.pca_mean_[:, None]
+
+ pca_data = fast_dot(self.pca_components_, data)
+ # Apply unmixing to low dimension PCA
+ sources = fast_dot(self.unmixing_matrix_, pca_data[:n_components])
if include not in (None, []):
- mute = [i for i in xrange(len(sources)) if i not in include]
- sources[mute, :] = 0. # include via exclusion
+ mask = np.ones(len(data), dtype=np.bool)
+ mask[np.unique(include)] = False
+ sources[mask] = 0.
elif exclude not in (None, []):
- sources[exclude, :] = 0. # just exclude
-
- # restore pca data
- pca_restored = np.dot(sources.T, self.mixing_matrix_)
+ sources[np.unique(exclude)] = 0.
- # re-append deselected pca dimension if desired
- if _n_pca_comp > self.n_components_:
- pca_reappend = pca_data[:, self.n_components_:_n_pca_comp]
- pca_restored = np.c_[pca_restored, pca_reappend]
+ pca_data[:n_components] = fast_dot(self.mixing_matrix_, sources)
+ data = fast_dot(self.pca_components_[:n_components].T,
+ pca_data[:n_components])
+ if n_pca_components > n_components:
+ data += fast_dot(self.pca_components_[n_components:_n_pca_comp].T,
+ pca_data[n_components:_n_pca_comp])
- # restore sensor space data
- out = self._inverse_transform_pca(pca_restored)
+ if self.pca_mean_ is not None:
+ data += self.pca_mean_[:, None]
# restore scaling
if self.noise_cov is None: # revert standardization
- out /= self._pre_whitener
+ data /= self._pre_whitener[:, None]
else:
- out = np.dot(out, linalg.pinv(self._pre_whitener))
+ data = fast_dot(linalg.pinv(self._pre_whitener), data)
- return out.T
+ return data
- def _transform_pca(self, data):
- """Apply decorrelation / dimensionality reduction on MEEG data.
- """
- X = np.atleast_2d(data)
- if self.pca_mean_ is not None:
- X = X - self.pca_mean_
-
- X = np.dot(X, self.pca_components_.T)
- return X
- def _transform_ica(self, data):
- """Apply ICA unmixing matrix to recover the latent sources.
- """
- return np.dot(np.atleast_2d(data), self.unmixing_matrix_.T)
-
- def _inverse_transform_pca(self, X):
- """Aux function"""
- components = self.pca_components_[:X.shape[1]]
- X_orig = np.dot(X, components)
-
- if self.pca_mean_ is not None:
- X_orig += self.pca_mean_
-
- return X_orig
+ at verbose
+def _check_n_pca_components(ica, _n_pca_comp, verbose=None):
+ """Aux function"""
+ if isinstance(_n_pca_comp, float):
+ _n_pca_comp = ((ica.pca_explained_variance_ /
+ ica.pca_explained_variance_.sum()).cumsum()
+ <= _n_pca_comp).sum()
+ logger.info('Selected %i PCA components by explained '
+ 'variance' % _n_pca_comp)
+ elif _n_pca_comp is None:
+ _n_pca_comp = ica.n_components_
+ return _n_pca_comp
def _check_start_stop(raw, start, stop):
@@ -1140,7 +1245,7 @@ def _check_start_stop(raw, start, stop):
@verbose
def ica_find_ecg_events(raw, ecg_source, event_id=999,
- tstart=0.0, l_freq=5, h_freq=35, qrs_threshold=0.6,
+ tstart=0.0, l_freq=5, h_freq=35, qrs_threshold='auto',
verbose=None):
"""Find ECG peaks from one selected ICA source
@@ -1159,8 +1264,10 @@ def ica_find_ecg_events(raw, ecg_source, event_id=999,
Low pass frequency.
h_freq : float
High pass frequency.
- qrs_threshold : float
- Between 0 and 1. qrs detection threshold.
+ qrs_threshold : float | str
+ Between 0 and 1. qrs detection threshold. Can also be "auto" to
+ automatically choose the threshold that generates a reasonable
+ number of heartbeats (40-160 beats / min).
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
@@ -1222,12 +1329,17 @@ def ica_find_eog_events(raw, eog_source=None, event_id=998, l_freq=1,
def _get_target_ch(container, target):
"""Aux function"""
+
# auto target selection
- pick = pick_channels(container.ch_names, include=[target])
- if len(pick) == 0:
+ picks = pick_channels(container.ch_names, include=[target])
+ ref_picks = pick_types(container.info, meg=False, eeg=False, ref_meg=True)
+ if len(ref_picks) > 0:
+ picks = list(set(picks) - set(ref_picks))
+
+ if len(picks) == 0:
raise ValueError('%s not in channel list (%s)' %
(target, container.ch_names))
- return pick
+ return picks
def _find_sources(sources, target, score_func):
@@ -1246,11 +1358,12 @@ def _find_sources(sources, target, score_func):
def _serialize(dict_, outer_sep=';', inner_sep=':'):
"""Aux function"""
-
s = []
for k, v in dict_.items():
if callable(v):
v = v.__name__
+ elif isinstance(v, int):
+ v = int(v)
for cls in (np.random.RandomState, Covariance):
if isinstance(v, cls):
v = cls.__name__
@@ -1281,25 +1394,45 @@ def _write_ica(fid, ica):
ica:
The instance of ICA to write
"""
- ica_interface = dict(noise_cov=ica.noise_cov,
- n_components=ica.n_components,
- n_pca_components=ica.n_pca_components,
- max_pca_components=ica.max_pca_components,
- current_fit=ica.current_fit,
- algorithm=ica.algorithm,
- fun=ica.fun,
- fun_args=ica.fun_args)
+ ica_init = dict(noise_cov=ica.noise_cov,
+ n_components=ica.n_components,
+ n_pca_components=ica.n_pca_components,
+ max_pca_components=ica.max_pca_components,
+ current_fit=ica.current_fit,
+ algorithm=ica.algorithm,
+ fun=ica.fun,
+ fun_args=ica.fun_args)
+
+ if ica.info is not None:
+ start_block(fid, FIFF.FIFFB_MEAS)
+ write_id(fid, FIFF.FIFF_BLOCK_ID)
+ if ica.info['meas_id'] is not None:
+ write_id(fid, FIFF.FIFF_PARENT_BLOCK_ID, ica.info['meas_id'])
+
+ # Write measurement info
+ write_meas_info(fid, ica.info)
+ end_block(fid, FIFF.FIFFB_MEAS)
start_block(fid, FIFF.FIFFB_ICA)
# ICA interface params
write_string(fid, FIFF.FIFF_MNE_ICA_INTERFACE_PARAMS,
- _serialize(ica_interface))
+ _serialize(ica_init))
# Channel names
if ica.ch_names is not None:
write_name_list(fid, FIFF.FIFF_MNE_ROW_NAMES, ica.ch_names)
+ # samples on fit
+ ica_misc = {'n_samples_': getattr(ica, 'n_samples_', None)}
+ # ICA init params
+ write_string(fid, FIFF.FIFF_MNE_ICA_INTERFACE_PARAMS,
+ _serialize(ica_init))
+
+ # ICA misct params
+ write_string(fid, FIFF.FIFF_MNE_ICA_MISC_PARAMS,
+ _serialize(ica_misc))
+
# Whitener
write_double_matrix(fid, FIFF.FIFF_MNE_ICA_WHITENER, ica._pre_whitener)
@@ -1342,8 +1475,17 @@ def read_ica(fname):
logger.info('Reading %s ...' % fname)
fid, tree, _ = fiff_open(fname)
- ica_data = dir_tree_find(tree, FIFF.FIFFB_ICA)
+ try:
+ info, meas = read_meas_info(fid, tree)
+ info['filename'] = fname
+ except ValueError:
+ logger.info('Could not find the measurement info. \n'
+ 'Functionality requiring the info won\'t be'
+ ' available.')
+ info = None
+
+ ica_data = dir_tree_find(tree, FIFF.FIFFB_ICA)
if len(ica_data) == 0:
fid.close()
raise ValueError('Could not find ICA data')
@@ -1354,7 +1496,7 @@ def read_ica(fname):
pos = d.pos
if kind == FIFF.FIFF_MNE_ICA_INTERFACE_PARAMS:
tag = read_tag(fid, pos)
- ica_interface = tag.data
+ ica_init = tag.data
elif kind == FIFF.FIFF_MNE_ROW_NAMES:
tag = read_tag(fid, pos)
ch_names = tag.data
@@ -1376,26 +1518,35 @@ def read_ica(fname):
elif kind == FIFF.FIFF_MNE_ICA_BADS:
tag = read_tag(fid, pos)
exclude = tag.data
+ elif kind == FIFF.FIFF_MNE_ICA_MISC_PARAMS:
+ tag = read_tag(fid, pos)
+ ica_misc = tag.data
fid.close()
- interface = _deserialize(ica_interface)
- current_fit = interface.pop('current_fit')
- if interface['noise_cov'] == Covariance.__name__:
+ ica_init, ica_misc = [_deserialize(k) for k in ica_init, ica_misc]
+ current_fit = ica_init.pop('current_fit')
+ if ica_init['noise_cov'] == Covariance.__name__:
logger.info('Reading whitener drawn from noise covariance ...')
logger.info('Now restoring ICA session ...')
- ica = ICA(**interface)
+ # make sure dtypes are np.float64 to satisfy fast_dot
+ f = lambda x: x.astype(np.float64)
+ ica = ICA(**ica_init)
ica.current_fit = current_fit
ica.ch_names = ch_names.split(':')
- ica._pre_whitener = pre_whitener
- ica.pca_mean_ = pca_mean
- ica.pca_components_ = pca_components
+ ica._pre_whitener = f(pre_whitener)
+ ica.pca_mean_ = f(pca_mean)
+ ica.pca_components_ = f(pca_components)
ica.n_components_ = unmixing_matrix.shape[0]
- ica.pca_explained_variance_ = pca_explained_variance
- ica.unmixing_matrix_ = unmixing_matrix
- ica.mixing_matrix_ = linalg.pinv(ica.unmixing_matrix_).T
+ ica.pca_explained_variance_ = f(pca_explained_variance)
+ ica.unmixing_matrix_ = f(unmixing_matrix)
+ ica.mixing_matrix_ = linalg.pinv(ica.unmixing_matrix_)
ica.exclude = [] if exclude is None else list(exclude)
+ ica.info = info
+ if 'n_samples_' in ica_misc:
+ ica.n_samples_ = ica_misc['n_samples_']
+
logger.info('Ready.')
return ica
@@ -1620,5 +1771,4 @@ def run_ica(raw, n_components, max_pca_components=100,
kurt_criterion=kurt_criterion,
var_criterion=var_criterion,
add_nodes=add_nodes)
-
return ica
diff --git a/mne/preprocessing/maxfilter.py b/mne/preprocessing/maxfilter.py
index cee2f69..5545678 100644
--- a/mne/preprocessing/maxfilter.py
+++ b/mne/preprocessing/maxfilter.py
@@ -6,16 +6,14 @@
import os
from warnings import warn
+import logging
import numpy as np
from scipy import optimize, linalg
-import logging
-logger = logging.getLogger('mne')
-
from ..fiff import Raw
from ..fiff.constants import FIFF
-from .. import verbose
+from ..utils import logger, verbose
@verbose
@@ -88,7 +86,7 @@ def fit_sphere_to_headshape(info, verbose=None):
def _mxwarn(msg):
warn('Possible MaxFilter bug: %s, more info: '
- 'http://imaging.mrc-cbu.cam.ac.uk/meg/maxbugs' % msg)
+ 'http://imaging.mrc-cbu.cam.ac.uk/meg/maxbugs' % msg)
@verbose
@@ -97,8 +95,8 @@ def apply_maxfilter(in_fname, out_fname, origin=None, frame='device',
st=False, st_buflen=16.0, st_corr=0.96, mv_trans=None,
mv_comp=False, mv_headpos=False, mv_hp=None,
mv_hpistep=None, mv_hpisubt=None, mv_hpicons=True,
- linefreq=None, mx_args='', overwrite=True,
- verbose=None):
+ linefreq=None, cal=None, ctc=None, mx_args='',
+ overwrite=True, verbose=None):
""" Apply NeuroMag MaxFilter to raw data.
@@ -171,6 +169,12 @@ def apply_maxfilter(in_fname, out_fname, origin=None, frame='device',
Sets the basic line interference frequency (50 or 60 Hz)
(None: do not use line filter)
+ cal : string
+ Path to calibration file
+
+ ctc : string
+ Path to Cross-talk compensation file
+
mx_args : string
Additional command line arguments to pass to MaxFilter
@@ -180,6 +184,7 @@ def apply_maxfilter(in_fname, out_fname, origin=None, frame='device',
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
+
Returns
-------
origin: string
@@ -256,7 +261,7 @@ def apply_maxfilter(in_fname, out_fname, origin=None, frame='device',
cmd += '-headpos '
if mv_hp is not None:
- cmd += '-hp %s' % mv_hp
+ cmd += '-hp %s ' % mv_hp
if mv_hpisubt is not None:
cmd += 'hpisubt %s ' % mv_hpisubt
@@ -267,6 +272,12 @@ def apply_maxfilter(in_fname, out_fname, origin=None, frame='device',
if linefreq is not None:
cmd += '-linefreq %d ' % linefreq
+ if cal is not None:
+ cmd += '-cal %s ' % cal
+
+ if ctc is not None:
+ cmd += '-ctc %s ' % ctc
+
cmd += mx_args
if overwrite and os.path.exists(out_fname):
diff --git a/mne/preprocessing/peak_finder.py b/mne/preprocessing/peak_finder.py
index 9235197..052b3bf 100644
--- a/mne/preprocessing/peak_finder.py
+++ b/mne/preprocessing/peak_finder.py
@@ -1,11 +1,7 @@
import numpy as np
from math import ceil
-import logging
-logger = logging.getLogger('mne')
-
-from .. import verbose
-from .. utils import deprecated
+from .. utils import logger, verbose
@verbose
@@ -102,7 +98,7 @@ def peak_finder(x0, thresh=None, extrema=1, verbose=None):
length -= 1
# Preallocate max number of maxima
- maxPeaks = ceil(length / 2.0)
+ maxPeaks = int(ceil(length / 2.0))
peak_loc = np.zeros(maxPeaks, dtype=np.int)
peak_mag = np.zeros(maxPeaks)
c_ind = 0
@@ -112,7 +108,7 @@ def peak_finder(x0, thresh=None, extrema=1, verbose=None):
# Reset peak finding if we had a peak and the next peak is bigger
# than the last or the left min was small enough to reset.
if found_peak and ((x[ii] > peak_mag[-1])
- or (left_min < peak_mag[-1] - thresh)):
+ or (left_min < peak_mag[-1] - thresh)):
temp_mag = min_mag
found_peak = False
diff --git a/mne/preprocessing/ssp.py b/mne/preprocessing/ssp.py
index 56a3301..f1f77bf 100644
--- a/mne/preprocessing/ssp.py
+++ b/mne/preprocessing/ssp.py
@@ -8,10 +8,8 @@ import copy as cp
from warnings import warn
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-
-from .. import Epochs, compute_proj_evoked, compute_proj_epochs, verbose
+from .. import Epochs, compute_proj_evoked, compute_proj_epochs
+from ..utils import logger, verbose
from ..fiff import pick_types, make_eeg_average_ref_proj
from .ecg import find_ecg_events
from .eog import find_eog_events
@@ -88,8 +86,10 @@ def _compute_exg_proj(mode, raw, raw_event, tmin, tmax,
High pass frequency applied for filtering EXG channel.
tstart : float
Start artifact detection after tstart seconds.
- qrs_threshold : float
- Between 0 and 1. qrs detection threshold (only for ECG).
+ qrs_threshold : float | str
+ Between 0 and 1. qrs detection threshold. Can also be "auto" to
+ automatically choose the threshold that generates a reasonable
+ number of heartbeats (40-160 beats / min). Only for ECG.
filter_method : str
Method for filtering ('iir' or 'fft').
iir_params : dict
@@ -133,9 +133,9 @@ def _compute_exg_proj(mode, raw, raw_event, tmin, tmax,
elif mode == 'EOG':
logger.info('Running EOG SSP computation')
events = find_eog_events(raw_event, event_id=event_id,
- l_freq=exg_l_freq, h_freq=exg_h_freq,
- filter_length=filter_length, ch_name=ch_name,
- tstart=tstart)
+ l_freq=exg_l_freq, h_freq=exg_h_freq,
+ filter_length=filter_length, ch_name=ch_name,
+ tstart=tstart)
else:
raise ValueError("mode must be 'ECG' or 'EOG'")
@@ -151,33 +151,34 @@ def _compute_exg_proj(mode, raw, raw_event, tmin, tmax,
# Handler rejection parameters
if reject is not None: # make sure they didn't pass None
if len(pick_types(my_info, meg='grad', eeg=False, eog=False,
- exclude='bads')) == 0:
+ ref_meg=False, exclude='bads')) == 0:
_safe_del_key(reject, 'grad')
if len(pick_types(my_info, meg='mag', eeg=False, eog=False,
- exclude='bads')) == 0:
+ ref_meg=False, exclude='bads')) == 0:
_safe_del_key(reject, 'mag')
if len(pick_types(my_info, meg=False, eeg=True, eog=False,
- exclude='bads')) == 0:
+ ref_meg=False, exclude='bads')) == 0:
_safe_del_key(reject, 'eeg')
if len(pick_types(my_info, meg=False, eeg=False, eog=True,
- exclude='bads')) == 0:
+ ref_meg=False, exclude='bads')) == 0:
_safe_del_key(reject, 'eog')
if flat is not None: # make sure they didn't pass None
if len(pick_types(my_info, meg='grad', eeg=False, eog=False,
- exclude='bads')) == 0:
+ ref_meg=False, exclude='bads')) == 0:
_safe_del_key(flat, 'grad')
if len(pick_types(my_info, meg='mag', eeg=False, eog=False,
- exclude='bads')) == 0:
+ ref_meg=False, exclude='bads')) == 0:
_safe_del_key(flat, 'mag')
if len(pick_types(my_info, meg=False, eeg=True, eog=False,
- exclude='bads')) == 0:
+ ref_meg=False, exclude='bads')) == 0:
_safe_del_key(flat, 'eeg')
if len(pick_types(my_info, meg=False, eeg=False, eog=True,
- exclude='bads')) == 0:
+ ref_meg=False, exclude='bads')) == 0:
_safe_del_key(flat, 'eog')
# exclude bad channels from projection
- picks = pick_types(my_info, meg=True, eeg=True, eog=True, exclude='bads')
+ picks = pick_types(my_info, meg=True, eeg=True, eog=True, ref_meg=False,
+ exclude='bads')
raw.filter(l_freq, h_freq, picks=picks, filter_length=filter_length,
n_jobs=n_jobs, method=filter_method, iir_params=iir_params)
@@ -210,12 +211,14 @@ def _compute_exg_proj(mode, raw, raw_event, tmin, tmax,
@verbose
def compute_proj_ecg(raw, raw_event=None, tmin=-0.2, tmax=0.4,
n_grad=2, n_mag=2, n_eeg=2, l_freq=1.0, h_freq=35.0,
- average=False, filter_length='10s', n_jobs=1, ch_name=None,
- reject=dict(grad=2000e-13, mag=3000e-15, eeg=50e-6,
- eog=250e-6), flat=None, bads=[], avg_ref=False,
+ average=False, filter_length='10s', n_jobs=1,
+ ch_name=None, reject=dict(grad=2000e-13, mag=3000e-15,
+ eeg=50e-6, eog=250e-6),
+ flat=None, bads=[], avg_ref=False,
no_proj=False, event_id=999, ecg_l_freq=5, ecg_h_freq=35,
- tstart=0., qrs_threshold=0.6, filter_method='fft',
- iir_params=dict(order=4, ftype='butter'), verbose=None):
+ tstart=0., qrs_threshold='auto', filter_method='fft',
+ iir_params=dict(order=4, ftype='butter'),
+ copy=True, verbose=None):
"""Compute SSP/PCA projections for ECG artifacts
Note: raw has to be constructed with preload=True (or string)
@@ -267,13 +270,17 @@ def compute_proj_ecg(raw, raw_event=None, tmin=-0.2, tmax=0.4,
High pass frequency applied for filtering ECG channel.
tstart : float
Start artifact detection after tstart seconds.
- qrs_threshold : float
- Between 0 and 1. qrs detection threshold.
+ qrs_threshold : float | str
+ Between 0 and 1. qrs detection threshold. Can also be "auto" to
+ automatically choose the threshold that generates a reasonable
+ number of heartbeats (40-160 beats / min).
filter_method : str
Method for filtering ('iir' or 'fft').
iir_params : dict
Dictionary of parameters to use for IIR filtering.
See mne.filter.construct_iir_filter for details.
+ copy : bool
+ If False, filtering raw data is done in place. Defaults to True.
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
@@ -284,13 +291,16 @@ def compute_proj_ecg(raw, raw_event=None, tmin=-0.2, tmax=0.4,
ecg_events : ndarray
Detected ECG events.
"""
+ if copy is True:
+ raw = raw.copy()
projs, ecg_events = _compute_exg_proj('ECG', raw, raw_event, tmin, tmax,
- n_grad, n_mag, n_eeg, l_freq, h_freq,
- average, filter_length, n_jobs, ch_name,
- reject, flat, bads, avg_ref, no_proj, event_id,
- ecg_l_freq, ecg_h_freq, tstart, qrs_threshold,
- filter_method, iir_params)
+ n_grad, n_mag, n_eeg, l_freq, h_freq,
+ average, filter_length, n_jobs,
+ ch_name, reject, flat, bads, avg_ref,
+ no_proj, event_id, ecg_l_freq,
+ ecg_h_freq, tstart, qrs_threshold,
+ filter_method, iir_params)
return projs, ecg_events
@@ -300,11 +310,11 @@ def compute_proj_eog(raw, raw_event=None, tmin=-0.2, tmax=0.2,
n_grad=2, n_mag=2, n_eeg=2, l_freq=1.0, h_freq=35.0,
average=False, filter_length='10s', n_jobs=1,
reject=dict(grad=2000e-13, mag=3000e-15, eeg=500e-6,
- eog=np.inf), flat=None, bads=[], avg_ref=False,
- no_proj=False, event_id=998, eog_l_freq=1, eog_h_freq=10,
- tstart=0., filter_method='fft',
+ eog=np.inf), flat=None, bads=[],
+ avg_ref=False, no_proj=False, event_id=998, eog_l_freq=1,
+ eog_h_freq=10, tstart=0., filter_method='fft',
iir_params=dict(order=4, ftype='butter'), ch_name=None,
- verbose=None):
+ copy=True, verbose=None):
"""Compute SSP/PCA projections for EOG artifacts
Note: raw has to be constructed with preload=True (or string)
@@ -358,10 +368,12 @@ def compute_proj_eog(raw, raw_event=None, tmin=-0.2, tmax=0.2,
Start artifact detection after tstart seconds.
filter_method : str
Method for filtering ('iir' or 'fft').
- verbose : bool, str, int, or None
- If not None, override default verbose level (see mne.verbose).
+ copy : bool
+ If False, filtering raw data is done in place. Defaults to True.
ch_name: str | None
If not None, specify EOG channel name.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
Returns
-------
@@ -370,12 +382,16 @@ def compute_proj_eog(raw, raw_event=None, tmin=-0.2, tmax=0.2,
eog_events: ndarray
Detected EOG events.
"""
-
+ if copy is True:
+ raw = raw.copy()
projs, eog_events = _compute_exg_proj('EOG', raw, raw_event, tmin, tmax,
- n_grad, n_mag, n_eeg, l_freq, h_freq,
- average, filter_length, n_jobs, ch_name,
- reject, flat, bads, avg_ref, no_proj, event_id,
- eog_l_freq, eog_h_freq, tstart, qrs_threshold=0.6,
- filter_method=filter_method, iir_params=iir_params)
-
- return projs, eog_events
\ No newline at end of file
+ n_grad, n_mag, n_eeg, l_freq, h_freq,
+ average, filter_length, n_jobs,
+ ch_name, reject, flat, bads, avg_ref,
+ no_proj, event_id, eog_l_freq,
+ eog_h_freq, tstart,
+ qrs_threshold='auto',
+ filter_method=filter_method,
+ iir_params=iir_params)
+
+ return projs, eog_events
diff --git a/mne/preprocessing/stim.py b/mne/preprocessing/stim.py
index eb54afc..4704289 100644
--- a/mne/preprocessing/stim.py
+++ b/mne/preprocessing/stim.py
@@ -23,9 +23,9 @@ def eliminate_stim_artifact(raw, events, event_id, tmin=-0.005,
event_id : int
The id of the events generating the stimulation artifacts.
tmin : float
- Start time before event in seconds.
+ Start time of the interpolation window in seconds.
tmax : float
- End time after event in seconds.
+ End time of the interpolation window in seconds.
mode : 'linear' | 'window'
way to fill the artifacted time interval.
'linear' does linear interpolation
@@ -42,17 +42,20 @@ def eliminate_stim_artifact(raw, events, event_id, tmin=-0.005,
'(or string) in the constructor.')
events_sel = (events[:, 2] == event_id)
event_start = events[events_sel, 0]
- s_start = int(np.ceil(raw.info['sfreq'] * np.abs(tmin)))
+ s_start = int(np.ceil(raw.info['sfreq'] * tmin))
s_end = int(np.ceil(raw.info['sfreq'] * tmax))
- picks = pick_types(raw.info, meg=True, eeg=True, exclude='bads')
+ picks = pick_types(raw.info, meg=True, eeg=True, eog=True, ecg=True,
+ emg=True, ref_meg=True, misc=True, chpi=True,
+ exclude='bads', stim=False, resp=False)
if mode == 'window':
- window = 1 - np.r_[signal.hann(4)[:2], np.ones(s_end + s_start - 4),
+ window = 1 - np.r_[signal.hann(4)[:2],
+ np.ones(np.abs(s_end - s_start) - 4),
signal.hann(4)[-2:]].T
for k in range(len(event_start)):
- first_samp = int(event_start[k]) - raw.first_samp - s_start
+ first_samp = int(event_start[k]) - raw.first_samp + s_start
last_samp = int(event_start[k]) - raw.first_samp + s_end
data, _ = raw[picks, first_samp:last_samp]
if mode == 'linear':
diff --git a/mne/preprocessing/tests/test_ica.py b/mne/preprocessing/tests/test_ica.py
index 30ce0bd..44f4cc0 100644
--- a/mne/preprocessing/tests/test_ica.py
+++ b/mne/preprocessing/tests/test_ica.py
@@ -5,20 +5,26 @@
import os
import os.path as op
+from functools import wraps
import warnings
-from nose.tools import assert_true, assert_raises
+from nose.tools import assert_true, assert_raises, assert_equal
from copy import deepcopy
import numpy as np
-from numpy.testing import assert_array_almost_equal, assert_array_equal
+from numpy.testing import (assert_array_almost_equal, assert_array_equal,
+ assert_allclose)
from scipy import stats
from itertools import product
-from mne import fiff, Epochs, read_events, cov
-from mne.preprocessing import ICA, ica_find_ecg_events, ica_find_eog_events,\
- read_ica, run_ica
-from mne.preprocessing.ica import score_funcs
-from mne.utils import _TempDir, requires_sklearn
+from mne import fiff, Epochs, read_events
+from mne.cov import read_cov
+from mne.preprocessing import (ICA, ica_find_ecg_events, ica_find_eog_events,
+ read_ica, run_ica)
+from mne.preprocessing.ica import score_funcs, _check_n_pca_components
+from mne.fiff.meas_info import Info
+from mne.utils import set_log_file, check_sklearn_version, _TempDir
+
+warnings.simplefilter('always') # enable b/c these tests throw warnings
tempdir = _TempDir()
@@ -28,49 +34,97 @@ event_name = op.join(data_dir, 'test-eve.fif')
evoked_nf_name = op.join(data_dir, 'test-nf-ave.fif')
test_cov_name = op.join(data_dir, 'test-cov.fif')
-event_id, tmin, tmax = 1, -0.2, 0.5
-start, stop = 0, 8 # if stop is too small pca may fail in some cases, but
+event_id, tmin, tmax = 1, -0.2, 0.2
+start, stop = 0, 6 # if stop is too small pca may fail in some cases, but
# we're okay on this file
-raw = fiff.Raw(raw_fname, preload=True).crop(0, stop, False)
-
-events = read_events(event_name)
-picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False, eog=False,
- exclude='bads')
-
-# for testing eog functionality
-picks2 = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False, eog=True,
- exclude='bads')
-reject = dict(grad=1000e-12, mag=4e-12, eeg=80e-6, eog=150e-6)
-flat = dict(grad=1e-15, mag=1e-15)
-
-test_cov = cov.read_cov(test_cov_name)
-epochs = Epochs(raw, events[:4], event_id, tmin, tmax, picks=picks,
- baseline=(None, 0), preload=True)
+score_funcs_unsuited = ['pointbiserialr', 'ansari']
+try:
+ from sklearn.utils.validation import NonBLASDotWarning
+ warnings.simplefilter('error', NonBLASDotWarning)
+except:
+ pass
+
+
+def requires_sklearn(function):
+ """Decorator to skip test if scikit-learn >= 0.12 is not available"""
+ @wraps(function)
+ def dec(*args, **kwargs):
+ if not check_sklearn_version(min_version='0.12'):
+ from nose.plugins.skip import SkipTest
+ raise SkipTest('Test %s skipped, requires scikit-learn >= 0.12'
+ % function.__name__)
+ ret = function(*args, **kwargs)
+ return ret
+ return dec
-epochs_eog = Epochs(raw, events[:4], event_id, tmin, tmax, picks=picks2,
- baseline=(None, 0), preload=True)
-score_funcs_unsuited = ['pointbiserialr', 'ansari']
+ at requires_sklearn
+def test_ica_full_data_recovery():
+ """Test recovery of full data when no source is rejected"""
+ # Most basic recovery
+ raw = fiff.Raw(raw_fname, preload=True).crop(0, stop, False).crop(1.5)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ epochs = Epochs(raw, events[:4], event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
+ n_channels = 5
+ data = raw._data[:n_channels].copy()
+ data_epochs = epochs.get_data()
+ for n_components, n_pca_components, ok in [(2, n_channels, True),
+ (2, n_channels // 2, False)]:
+ ica = ICA(n_components=n_components,
+ max_pca_components=n_pca_components,
+ n_pca_components=n_pca_components)
+ ica.decompose_raw(raw, picks=range(n_channels))
+ raw2 = ica.pick_sources_raw(raw, exclude=[])
+ if ok:
+ assert_allclose(data[:n_channels], raw2._data[:n_channels],
+ rtol=1e-10, atol=1e-15)
+ else:
+ diff = np.abs(data[:n_channels] - raw2._data[:n_channels])
+ assert_true(np.max(diff) > 1e-14)
+
+ ica = ICA(n_components=n_components,
+ max_pca_components=n_pca_components,
+ n_pca_components=n_pca_components)
+ ica.decompose_epochs(epochs, picks=range(n_channels))
+ epochs2 = ica.pick_sources_epochs(epochs, exclude=[])
+ data2 = epochs2.get_data()[:, :n_channels]
+ if ok:
+ assert_allclose(data_epochs[:, :n_channels], data2,
+ rtol=1e-10, atol=1e-15)
+ else:
+ diff = np.abs(data_epochs[:, :n_channels] - data2)
+ assert_true(np.max(diff) > 1e-14)
@requires_sklearn
def test_ica_core():
"""Test ICA on raw and epochs
"""
- # setup parameter
+ raw = fiff.Raw(raw_fname, preload=True).crop(0, stop, False).crop(1.5)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
# XXX. The None cases helped revealing bugs but are time consuming.
+ test_cov = read_cov(test_cov_name)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ epochs = Epochs(raw, events[:4], event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
noise_cov = [None, test_cov]
# removed None cases to speed up...
- n_components = [3, 1.0] # for future dbg add cases
- max_pca_components = [4]
+ n_components = [2, 1.0] # for future dbg add cases
+ max_pca_components = [3]
picks_ = [picks]
iter_ica_params = product(noise_cov, n_components, max_pca_components,
picks_)
# # test init catchers
assert_raises(ValueError, ICA, n_components=3, max_pca_components=2)
- assert_raises(ValueError, ICA, n_components=1.3, max_pca_components=2)
+ assert_raises(ValueError, ICA, n_components=2.3, max_pca_components=2)
# test essential core functionality
for n_cov, n_comp, max_n, pcks in iter_ica_params:
@@ -100,12 +154,6 @@ def test_ica_core():
assert_raises(ValueError, ica.pick_sources_raw, raw3,
include=[1, 2])
- for excl, incl in (([], []), ([], [1, 2]), ([1, 2], [])):
- raw2 = ica.pick_sources_raw(raw, exclude=excl, include=incl,
- copy=True)
-
- assert_array_almost_equal(raw2[:, :][1], raw[:, :][1])
-
#######################################################################
# test epochs decomposition
@@ -132,25 +180,33 @@ def test_ica_core():
assert_raises(ValueError, ica.pick_sources_epochs, epochs3,
include=[1, 2])
- # test source picking
- for excl, incl in (([], []), ([], [1, 2]), ([1, 2], [])):
- epochs2 = ica.pick_sources_epochs(epochs, exclude=excl,
- include=incl, copy=True)
-
- assert_array_almost_equal(epochs2.get_data(),
- epochs.get_data())
-
@requires_sklearn
def test_ica_additional():
- """Test additional functionality
+ """Test additional ICA functionality
"""
stop2 = 500
+ raw = fiff.Raw(raw_fname, preload=True).crop(0, stop, False).crop(1.5)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ test_cov = read_cov(test_cov_name)
+ events = read_events(event_name)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ epochs = Epochs(raw, events[:4], event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True)
+ # for testing eog functionality
+ picks2 = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=True, exclude='bads')
+ epochs_eog = Epochs(raw, events[:4], event_id, tmin, tmax, picks=picks2,
+ baseline=(None, 0), preload=True)
test_cov2 = deepcopy(test_cov)
ica = ICA(noise_cov=test_cov2, n_components=3, max_pca_components=4,
n_pca_components=4)
+ assert_true(ica.info is None)
ica.decompose_raw(raw, picks[:5])
+ assert_true(isinstance(ica.info, Info))
assert_true(ica.n_components_ < 5)
ica = ICA(n_components=3, max_pca_components=4,
@@ -158,16 +214,35 @@ def test_ica_additional():
assert_raises(RuntimeError, ica.save, '')
ica.decompose_raw(raw, picks=None, start=start, stop=stop2)
+ # test decim
+ ica = ICA(n_components=3, max_pca_components=4,
+ n_pca_components=4)
+ raw_ = raw.copy()
+ for _ in range(3):
+ raw_.append(raw_)
+ n_samples = raw_._data.shape[1]
+ ica.decompose_raw(raw, picks=None, decim=3)
+ assert_true(raw_._data.shape[1], n_samples)
+
+ # test expl var
+ ica = ICA(n_components=1.0, max_pca_components=4,
+ n_pca_components=4)
+ ica.decompose_raw(raw, picks=None, decim=3)
+ assert_true(ica.n_components_ == 4)
+
# epochs extraction from raw fit
assert_raises(RuntimeError, ica.get_sources_epochs, epochs)
-
# test reading and writing
test_ica_fname = op.join(op.dirname(tempdir), 'ica_test.fif')
for cov in (None, test_cov):
- ica = ICA(noise_cov=cov, n_components=3, max_pca_components=4,
+ ica = ICA(noise_cov=cov, n_components=2, max_pca_components=4,
n_pca_components=4)
- ica.decompose_raw(raw, picks=picks, start=start, stop=stop2)
+ with warnings.catch_warnings(True): # ICA does not converge
+ ica.decompose_raw(raw, picks=picks, start=start, stop=stop2)
sources = ica.get_sources_epochs(epochs)
+ assert_true(ica.mixing_matrix_.shape == (2, 2))
+ assert_true(ica.unmixing_matrix_.shape == (2, 2))
+ assert_true(ica.pca_components_.shape == (4, len(picks)))
assert_true(sources.shape[1] == ica.n_components_)
for exclude in [[], [0]]:
@@ -191,30 +266,44 @@ def test_ica_additional():
assert_true(ica.exclude == [ica_raw.ch_names.index(e) for e in
ica_raw.info['bads']])
+ # test filtering
+ d1 = ica_raw._data[0].copy()
+ with warnings.catch_warnings(True): # dB warning
+ ica_raw.filter(4, 20)
+ assert_true((d1 != ica_raw._data[0]).any())
+ d1 = ica_raw._data[0].copy()
+ with warnings.catch_warnings(True): # dB warning
+ ica_raw.notch_filter([10])
+ assert_true((d1 != ica_raw._data[0]).any())
+
ica.n_pca_components = 2
ica.save(test_ica_fname)
ica_read = read_ica(test_ica_fname)
- assert_true(ica.n_pca_components ==
- ica_read.n_pca_components)
+ assert_true(ica.n_pca_components == ica_read.n_pca_components)
+
+ # check type consistency
+ attrs = ('mixing_matrix_ unmixing_matrix_ pca_components_ '
+ 'pca_explained_variance_ _pre_whitener')
+ f = lambda x, y: getattr(x, y).dtype
+ for attr in attrs.split():
+ assert_equal(f(ica_read, attr), f(ica, attr))
+
ica.n_pca_components = 4
ica_read.n_pca_components = 4
ica.exclude = []
ica.save(test_ica_fname)
ica_read = read_ica(test_ica_fname)
+ for attr in ['mixing_matrix_', 'unmixing_matrix_', 'pca_components_',
+ 'pca_mean_', 'pca_explained_variance_',
+ '_pre_whitener']:
+ assert_array_almost_equal(getattr(ica, attr),
+ getattr(ica_read, attr))
assert_true(ica.ch_names == ica_read.ch_names)
+ assert_true(isinstance(ica_read.info, Info))
- assert_true(np.allclose(ica.mixing_matrix_, ica_read.mixing_matrix_,
- rtol=1e-16, atol=1e-32))
- assert_array_equal(ica.pca_components_,
- ica_read.pca_components_)
- assert_array_equal(ica.pca_mean_, ica_read.pca_mean_)
- assert_array_equal(ica.pca_explained_variance_,
- ica_read.pca_explained_variance_)
- assert_array_equal(ica._pre_whitener, ica_read._pre_whitener)
-
- # assert_raises(RuntimeError, ica_read.decompose_raw, raw)
+ assert_raises(RuntimeError, ica_read.decompose_raw, raw)
sources = ica.get_sources_raw(raw)
sources2 = ica_read.get_sources_raw(raw)
assert_array_almost_equal(sources, sources2)
@@ -266,26 +355,33 @@ def test_ica_additional():
ecg_scores = ica.find_sources_raw(raw, target='MEG 1531',
score_func='pearsonr')
- ecg_events = ica_find_ecg_events(raw, sources[np.abs(ecg_scores).argmax()])
+ with warnings.catch_warnings(True): # filter attenuation warning
+ ecg_events = ica_find_ecg_events(raw,
+ sources[np.abs(ecg_scores).argmax()])
assert_true(ecg_events.ndim == 2)
# eog functionality
eog_scores = ica.find_sources_raw(raw, target='EOG 061',
score_func='pearsonr')
- eog_events = ica_find_eog_events(raw, sources[np.abs(eog_scores).argmax()])
+ with warnings.catch_warnings(True): # filter attenuation warning
+ eog_events = ica_find_eog_events(raw,
+ sources[np.abs(eog_scores).argmax()])
assert_true(eog_events.ndim == 2)
# Test ica fiff export
ica_raw = ica.sources_as_raw(raw, start=0, stop=100)
assert_true(ica_raw.last_samp - ica_raw.first_samp == 100)
+ assert_true(isinstance(ica_raw.info.get('filenames', None),
+ (list, type(None)))) # API consistency
ica_chans = [ch for ch in ica_raw.ch_names if 'ICA' in ch]
assert_true(ica.n_components_ == len(ica_chans))
test_ica_fname = op.join(op.abspath(op.curdir), 'test_ica.fif')
- ica_raw.save(test_ica_fname)
+ ica.n_components = np.int32(ica.n_components)
+ ica_raw.save(test_ica_fname, overwrite=True)
ica_raw2 = fiff.Raw(test_ica_fname, preload=True)
- assert_array_almost_equal(ica_raw._data, ica_raw2._data)
+ assert_allclose(ica_raw._data, ica_raw2._data, rtol=1e-5, atol=1e-4)
ica_raw2.close()
os.remove(test_ica_fname)
@@ -298,21 +394,40 @@ def test_ica_additional():
assert_true(ica.n_components_ == len(ica_chans))
assert_true(ica.n_components_ == ica_epochs.get_data().shape[1])
assert_true(ica_epochs.raw is None)
- assert_true(ica_epochs.preload == True)
+ assert_true(ica_epochs.preload is True)
- # regression test for plot method
- assert_raises(ValueError, ica.plot_sources_raw, raw,
- order=np.arange(50))
- assert_raises(ValueError, ica.plot_sources_epochs, epochs,
- order=np.arange(50))
+ # test float n pca components
+ ica.pca_explained_variance_ = np.array([0.2] * 5)
+ for ncomps, expected in [[0.3, 1], [0.9, 4], [1, 1]]:
+ ncomps_ = _check_n_pca_components(ica, ncomps)
+ assert_true(ncomps_ == expected)
+ at requires_sklearn
def test_run_ica():
"""Test run_ica function"""
+ raw = fiff.Raw(raw_fname, preload=True).crop(0, stop, False).crop(1.5)
params = []
params += [(None, -1, slice(2), [0, 1])] # varicance, kurtosis idx
params += [(None, 'MEG 1531')] # ECG / EOG channel params
for idx, ch_name in product(*params):
- run_ica(raw, n_components=.9, start=0, stop=100, start_find=0,
- stop_find=50, ecg_ch=ch_name, eog_ch=ch_name,
+ run_ica(raw, n_components=2, start=0, stop=6, start_find=0,
+ stop_find=5, ecg_ch=ch_name, eog_ch=ch_name,
skew_criterion=idx, var_criterion=idx, kurt_criterion=idx)
+
+
+ at requires_sklearn
+def test_ica_reject_buffer():
+ """Test ICA data raw buffer rejection"""
+ raw = fiff.Raw(raw_fname, preload=True).crop(0, stop, False).crop(1.5)
+ picks = fiff.pick_types(raw.info, meg=True, stim=False, ecg=False,
+ eog=False, exclude='bads')
+ ica = ICA(n_components=3, max_pca_components=4, n_pca_components=4)
+ raw._data[2, 1000:1005] = 5e-12
+ drop_log = op.join(op.dirname(tempdir), 'ica_drop.log')
+ set_log_file(drop_log, overwrite=True)
+ ica.decompose_raw(raw, picks[:5], reject=dict(mag=2.5e-12), decim=2,
+ tstep=0.01, verbose=True)
+ assert_true(raw._data[:5, ::2].shape[1] - 4 == ica.n_samples_)
+ log = [l for l in open(drop_log) if 'detected' in l]
+ assert_equal(len(log), 1)
diff --git a/mne/preprocessing/tests/test_ssp.py b/mne/preprocessing/tests/test_ssp.py
index 32758f1..88d22b0 100644
--- a/mne/preprocessing/tests/test_ssp.py
+++ b/mne/preprocessing/tests/test_ssp.py
@@ -9,70 +9,71 @@ from ...fiff import Raw
from ...fiff.proj import make_projector, activate_proj
from ..ssp import compute_proj_ecg, compute_proj_eog
+warnings.simplefilter('always') # enable b/c these tests throw warnings
+
data_path = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data')
raw_fname = op.join(data_path, 'test_raw.fif')
dur_use = 5.0
eog_times = np.array([0.5, 2.3, 3.6, 14.5])
-raw_0 = Raw(raw_fname, preload=True).crop(0, 10, False)
-raw_0.close()
def test_compute_proj_ecg():
"""Test computation of ECG SSP projectors"""
+ raw = Raw(raw_fname, preload=True).crop(0, 10, False)
for average in [False, True]:
- raw = raw_0.copy()
# For speed, let's not filter here (must also not reject then)
projs, events = compute_proj_ecg(raw, n_mag=2, n_grad=2, n_eeg=2,
- ch_name='MEG 1531', bads=['MEG 2443'],
- average=average, avg_ref=True,
- no_proj=True, l_freq=None, h_freq=None,
- reject=None, tmax=dur_use,
- qrs_threshold=0.5)
+ ch_name='MEG 1531', bads=['MEG 2443'],
+ average=average, avg_ref=True,
+ no_proj=True, l_freq=None,
+ h_freq=None, reject=None,
+ tmax=dur_use, qrs_threshold=0.5)
assert_true(len(projs) == 7)
# heart rate at least 0.5 Hz, but less than 3 Hz
assert_true(events.shape[0] > 0.5 * dur_use and
events.shape[0] < 3 * dur_use)
#XXX: better tests
- # without setting a bad channel, this should throw a warning (only
- # thrown once, so it's for average == True)
+ # without setting a bad channel, this should throw a warning
with warnings.catch_warnings(record=True) as w:
projs, events = compute_proj_ecg(raw, n_mag=2, n_grad=2, n_eeg=2,
- ch_name='MEG 1531', bads=[],
- average=average, avg_ref=True,
- no_proj=True, l_freq=None,
- h_freq=None, tmax=dur_use)
- assert_equal(len(w), 0 if average else 1)
+ ch_name='MEG 1531', bads=[],
+ average=average, avg_ref=True,
+ no_proj=True, l_freq=None,
+ h_freq=None, tmax=dur_use)
+ assert_equal(len(w), 1)
assert_equal(projs, None)
def test_compute_proj_eog():
"""Test computation of EOG SSP projectors"""
+ raw = Raw(raw_fname, preload=True).crop(0, 10, False)
for average in [False, True]:
- raw = raw_0.copy()
n_projs_init = len(raw.info['projs'])
projs, events = compute_proj_eog(raw, n_mag=2, n_grad=2, n_eeg=2,
- bads=['MEG 2443'], average=average,
- avg_ref=True, no_proj=False, l_freq=None,
- h_freq=None, reject=None, tmax=dur_use)
+ bads=['MEG 2443'], average=average,
+ avg_ref=True, no_proj=False,
+ l_freq=None, h_freq=None,
+ reject=None, tmax=dur_use)
assert_true(len(projs) == (7 + n_projs_init))
assert_true(np.abs(events.shape[0] -
np.sum(np.less(eog_times, dur_use))) <= 1)
#XXX: better tests
- # This will not throw a warning (?)
+ # This will throw a warning b/c simplefilter('always')
with warnings.catch_warnings(record=True) as w:
projs, events = compute_proj_eog(raw, n_mag=2, n_grad=2, n_eeg=2,
- average=average, bads=[],
- avg_ref=True, no_proj=False,
- l_freq=None, h_freq=None,
- tmax=dur_use)
- assert_equal(len(w), 0)
+ average=average, bads=[],
+ avg_ref=True, no_proj=False,
+ l_freq=None, h_freq=None,
+ tmax=dur_use)
+ assert_equal(len(w), 1)
assert_equal(projs, None)
def test_compute_proj_parallel():
"""Test computation of ExG projectors using parallelization"""
+ raw_0 = Raw(raw_fname, preload=True).crop(0, 10, False)
raw = raw_0.copy()
projs, _ = compute_proj_eog(raw, n_mag=2, n_grad=2, n_eeg=2,
bads=['MEG 2443'], average=False,
diff --git a/mne/preprocessing/tests/test_stim.py b/mne/preprocessing/tests/test_stim.py
index 57ecf5e..2b1a659 100644
--- a/mne/preprocessing/tests/test_stim.py
+++ b/mne/preprocessing/tests/test_stim.py
@@ -22,15 +22,55 @@ def test_stim_elim():
raw = Raw(raw_fname, preload=True)
events = read_events(event_fname)
event_idx = np.where(events[:, 2] == 1)[0][0]
- tidx = events[event_idx, 0] - raw.first_samp
+ tidx = int(events[event_idx, 0] - raw.first_samp)
- raw = eliminate_stim_artifact(raw, events, event_id=1, tmin=-0.005,
- tmax=0.01, mode='linear')
- data, times = raw[:, tidx - 3:tidx + 5]
+ # use window around stimulus
+ tmin = -0.02
+ tmax = 0.02
+ test_tminidx = int(-0.01 * raw.info['sfreq'])
+ test_tmaxidx = int(0.01 * raw.info['sfreq'])
+
+ raw = eliminate_stim_artifact(raw, events, event_id=1, tmin=tmin,
+ tmax=tmax, mode='linear')
+ data, times = raw[:, (tidx + test_tminidx):(tidx + test_tmaxidx)]
+ diff_data0 = np.diff(data[0])
+ diff_data0 -= np.mean(diff_data0)
+ assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0)))
+ raw = eliminate_stim_artifact(raw, events, event_id=1, tmin=tmin,
+ tmax=tmax, mode='window')
+ data, times = raw[:, (tidx + test_tminidx):(tidx + test_tmaxidx)]
+ assert_true(np.all(data) == 0.)
+
+ # use window before stimulus
+ tmin = -0.045
+ tmax = 0.015
+ test_tminidx = int(-0.035 * raw.info['sfreq'])
+ test_tmaxidx = int(-0.015 * raw.info['sfreq'])
+
+ raw = eliminate_stim_artifact(raw, events, event_id=1, tmin=tmin,
+ tmax=tmax, mode='linear')
+ data, times = raw[:, (tidx + test_tminidx):(tidx + test_tmaxidx)]
+ diff_data0 = np.diff(data[0])
+ diff_data0 -= np.mean(diff_data0)
+ assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0)))
+ raw = eliminate_stim_artifact(raw, events, event_id=1, tmin=tmin,
+ tmax=tmax, mode='window')
+ data, times = raw[:, (tidx + test_tminidx):(tidx + test_tmaxidx)]
+ assert_true(np.all(data) == 0.)
+
+ # use window after stimulus
+ tmin = 0.005
+ tmax = 0.045
+ test_tminidx = int(0.015 * raw.info['sfreq'])
+ test_tmaxidx = int(0.035 * raw.info['sfreq'])
+
+ raw = eliminate_stim_artifact(raw, events, event_id=1, tmin=tmin,
+ tmax=tmax, mode='linear')
+ data, times = raw[:, (tidx + test_tminidx):(tidx + test_tmaxidx)]
diff_data0 = np.diff(data[0])
diff_data0 -= np.mean(diff_data0)
assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0)))
- raw = eliminate_stim_artifact(raw, events, event_id=1, tmin=-0.005,
- tmax=0.01, mode='window')
- data, times = raw[:, tidx:tidx + 1]
+ raw = eliminate_stim_artifact(raw, events, event_id=1, tmin=tmin,
+ tmax=tmax, mode='window')
+ data, times = raw[:, (tidx + test_tminidx):(tidx + test_tmaxidx)]
assert_true(np.all(data) == 0.)
diff --git a/mne/proj.py b/mne/proj.py
index 9708f34..76fc5c1 100644
--- a/mne/proj.py
+++ b/mne/proj.py
@@ -5,19 +5,17 @@
import numpy as np
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
-from . import fiff, Epochs, verbose
+from . import fiff, Epochs
+from .utils import logger, verbose
from .fiff.pick import pick_types, pick_types_forward
-from .fiff.proj import Projection
+from .fiff.proj import Projection, _has_eeg_average_ref_proj
from .event import make_fixed_length_events
from .parallel import parallel_func
from .cov import _check_n_samples
-from .forward import is_fixed_orient, _subject_from_forward
+from .forward import (is_fixed_orient, _subject_from_forward,
+ convert_forward_solution)
from .source_estimate import SourceEstimate
from .fiff.proj import make_projector, make_eeg_average_ref_proj
-from .fiff import FIFF
def read_proj(fname):
@@ -56,9 +54,9 @@ def write_proj(fname, projs):
@verbose
def _compute_proj(data, info, n_grad, n_mag, n_eeg, desc_prefix, verbose=None):
- mag_ind = pick_types(info, meg='mag', exclude='bads')
- grad_ind = pick_types(info, meg='grad', exclude='bads')
- eeg_ind = pick_types(info, meg=False, eeg=True, exclude='bads')
+ mag_ind = pick_types(info, meg='mag', ref_meg=False, exclude='bads')
+ grad_ind = pick_types(info, meg='grad', ref_meg=False, exclude='bads')
+ eeg_ind = pick_types(info, meg=False, eeg=True, ref_meg=False, exclude='bads')
if (n_grad > 0) and len(grad_ind) == 0:
logger.info("No gradiometers found. Forcing n_grad to 0")
@@ -72,7 +70,8 @@ def _compute_proj(data, info, n_grad, n_mag, n_eeg, desc_prefix, verbose=None):
ch_names = info['ch_names']
grad_names, mag_names, eeg_names = ([ch_names[k] for k in ind]
- for ind in [grad_ind, mag_ind, eeg_ind])
+ for ind in [grad_ind, mag_ind,
+ eeg_ind])
projs = []
for n, ind, names, desc in zip([n_grad, n_mag, n_eeg],
@@ -89,7 +88,8 @@ def _compute_proj(data, info, n_grad, n_mag, n_eeg, desc_prefix, verbose=None):
data=u[np.newaxis, :], nrow=1, ncol=u.size)
this_desc = "%s-%s-PCA-%02d" % (desc, desc_prefix, k + 1)
logger.info("Adding projection: %s" % this_desc)
- proj = Projection(active=False, data=proj_data, desc=this_desc, kind=1)
+ proj = Projection(active=False, data=proj_data,
+ desc=this_desc, kind=1)
projs.append(proj)
return projs
@@ -107,9 +107,9 @@ def compute_proj_epochs(epochs, n_grad=2, n_mag=2, n_eeg=2, n_jobs=1,
n_grad : int
Number of vectors for gradiometers
n_mag : int
- Number of vectors for gradiometers
+ Number of vectors for magnetometers
n_eeg : int
- Number of vectors for gradiometers
+ Number of vectors for EEG channels
n_jobs : int
Number of jobs to use to compute covariance
verbose : bool, str, int, or None
@@ -158,9 +158,9 @@ def compute_proj_evoked(evoked, n_grad=2, n_mag=2, n_eeg=2, verbose=None):
n_grad : int
Number of vectors for gradiometers
n_mag : int
- Number of vectors for gradiometers
+ Number of vectors for magnetometers
n_eeg : int
- Number of vectors for gradiometers
+ Number of vectors for EEG channels
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
@@ -194,9 +194,9 @@ def compute_proj_raw(raw, start=0, stop=None, duration=1, n_grad=2, n_mag=2,
n_grad : int
Number of vectors for gradiometers
n_mag : int
- Number of vectors for gradiometers
+ Number of vectors for magnetometers
n_eeg : int
- Number of vectors for gradiometers
+ Number of vectors for EEG channels
reject : dict
Epoch rejection configuration (see Epochs)
flat : dict
@@ -250,7 +250,7 @@ def sensitivity_map(fwd, projs=None, ch_type='grad', mode='fixed', exclude=[],
Parameters
----------
fwd : dict
- The forward operator. Must be free- and surface-oriented.
+ The forward operator.
projs : list
List of projection vectors.
ch_type : 'grad' | 'mag' | 'eeg'
@@ -275,16 +275,19 @@ def sensitivity_map(fwd, projs=None, ch_type='grad', mode='fixed', exclude=[],
# check strings
if not ch_type in ['eeg', 'grad', 'mag']:
raise ValueError("ch_type should be 'eeg', 'mag' or 'grad (got %s)"
- % ch_type)
+ % ch_type)
if not mode in ['free', 'fixed', 'ratio', 'radiality', 'angle',
'remaining', 'dampening']:
raise ValueError('Unknown mode type (got %s)' % mode)
# check forward
- if not fwd['surf_ori']:
- raise ValueError('fwd should be surface oriented')
- if is_fixed_orient(fwd):
- raise ValueError('fwd should not have fixed orientation')
+ if is_fixed_orient(fwd, orig=True):
+ raise ValueError('fwd should must be computed with free orientation')
+ fwd = convert_forward_solution(fwd, surf_ori=True, force_fixed=False,
+ verbose=False)
+ if not fwd['surf_ori'] or is_fixed_orient(fwd):
+ raise RuntimeError('Error converting solution, please notify '
+ 'mne-python developers')
# limit forward
if ch_type == 'eeg':
@@ -296,16 +299,16 @@ def sensitivity_map(fwd, projs=None, ch_type='grad', mode='fixed', exclude=[],
# Make sure EEG has average
if ch_type == 'eeg':
- if projs is None or \
- not any([p['kind'] == FIFF.FIFFV_MNE_PROJ_ITEM_EEG_AVREF
- for p in projs]):
+ if projs is None or not _has_eeg_average_ref_proj(projs):
eeg_ave = [make_eeg_average_ref_proj(fwd['info'])]
+ else:
+ eeg_ave = []
projs = eeg_ave if projs is None else projs + eeg_ave
# Construct the projector
if projs is not None:
proj, ncomp, U = make_projector(projs, fwd['sol']['row_names'],
- include_active=True)
+ include_active=True)
# do projection for most types
if mode not in ['angle', 'remaining', 'dampening']:
gain = np.dot(proj, gain)
diff --git a/mne/realtime/__init__.py b/mne/realtime/__init__.py
new file mode 100644
index 0000000..4c794e9
--- /dev/null
+++ b/mne/realtime/__init__.py
@@ -0,0 +1,13 @@
+""" Module for realtime MEG data using mne_rt_server """
+
+# Authors: Christoph Dinh <chdinh at nmr.mgh.harvard.edu>
+# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Mainak Jas <mainak at neuro.hut.fi>
+# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
+#
+# License: BSD (3-clause)
+
+from .client import RtClient
+from .epochs import RtEpochs
+from .mockclient import MockRtClient
+from .stim_server_client import StimServer, StimClient
diff --git a/mne/realtime/client.py b/mne/realtime/client.py
new file mode 100644
index 0000000..3e89e75
--- /dev/null
+++ b/mne/realtime/client.py
@@ -0,0 +1,370 @@
+# Authors: Christoph Dinh <chdinh at nmr.mgh.harvard.edu>
+# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
+#
+# License: BSD (3-clause)
+
+import socket
+import time
+import struct
+import StringIO
+import threading
+
+import numpy as np
+
+from ..utils import logger, verbose
+from ..fiff.constants import FIFF
+from ..fiff.meas_info import read_meas_info
+from ..fiff.tag import Tag, read_tag
+from ..fiff.tree import make_dir_tree
+
+# Constants for fiff realtime fiff messages
+MNE_RT_GET_CLIENT_ID = 1
+MNE_RT_SET_CLIENT_ALIAS = 2
+
+
+def _recv_tag_raw(sock):
+ """Read a tag and the associated data from a socket
+
+ Parameters
+ ----------
+ sock : socket.socket
+ The socket from which to read the tag.
+
+ Returns
+ -------
+ tag : instance of Tag
+ The tag.
+ buff : str
+ The raw data of the tag (including header).
+ """
+ s = sock.recv(4 * 4)
+ if len(s) != 16:
+ raise RuntimeError('Not enough bytes received, something is wrong. '
+ 'Make sure the mne_rt_server is running.')
+ tag = Tag(*struct.unpack(">iiii", s))
+ n_received = 0
+ rec_buff = [s]
+ while n_received < tag.size:
+ n_buffer = min(4096, tag.size - n_received)
+ this_buffer = sock.recv(n_buffer)
+ rec_buff.append(this_buffer)
+ n_received += len(this_buffer)
+
+ if n_received != tag.size:
+ raise RuntimeError('Not enough bytes received, something is wrong. '
+ 'Make sure the mne_rt_server is running.')
+
+ buff = ''.join(rec_buff)
+
+ return tag, buff
+
+
+def _buffer_recv_worker(rt_client, nchan):
+ """Worker thread that constantly receives buffers"""
+ try:
+ for raw_buffer in rt_client.raw_buffers(nchan):
+ rt_client._push_raw_buffer(raw_buffer)
+ except RuntimeError as err:
+ # something is wrong, the server stopped (or something)
+ rt_client._recv_thread = None
+ print 'Buffer receive thread stopped: %s' % err
+
+
+class RtClient(object):
+ """Realtime Client
+
+ Client to communicate with mne_rt_server
+
+ Parameters
+ ----------
+ host : str
+ Hostname (or IP address) of the host where mne_rt_server is running.
+
+ cmd_port : int
+ Port to use for the command connection.
+
+ data_port : int
+ Port to use for the data connection.
+
+ timeout : float
+ Communication timeout in seconds.
+
+ verbose : bool, str, int, or None
+ Log verbosity see mne.verbose.
+ """
+ @verbose
+ def __init__(self, host, cmd_port=4217, data_port=4218, timeout=1.0,
+ verbose=None):
+ self._host = host
+ self._data_port = data_port
+ self._cmd_port = cmd_port
+ self._timeout = timeout
+
+ try:
+ self._cmd_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self._cmd_sock.settimeout(timeout)
+ self._cmd_sock.connect((host, cmd_port))
+ self._cmd_sock.setblocking(0)
+ except Exception:
+ raise RuntimeError('Setting up command connection (host: %s '
+ 'port: %d) failed. Make sure mne_rt_server '
+ 'is running. ' % (host, cmd_port))
+
+ try:
+ self._data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self._data_sock.settimeout(timeout)
+ self._data_sock.connect((host, data_port))
+ self._data_sock.setblocking(1)
+ except Exception:
+ raise RuntimeError('Setting up data connection (host: %s '
+ 'port: %d) failed. Make sure mne_rt_server '
+ 'is running.' % (host, data_port))
+
+ self.verbose = verbose
+
+ # get my client ID
+ self._client_id = self.get_client_id()
+
+ self._recv_thread = None
+ self._recv_callbacks = list()
+
+ def _send_command(self, command):
+ """Send a command to the server
+
+ Parameters
+ ----------
+ command : str
+ The command to send.
+
+ Returns
+ -------
+ resp : str
+ The response from the server.
+ """
+
+ logger.debug('Sending command: %s' % command)
+ command += '\n'
+ self._cmd_sock.sendall(command)
+
+ buf, chunk, begin = [], '', time.time()
+ while True:
+ #if we got some data, then break after wait sec
+ if buf and time.time() - begin > self._timeout:
+ break
+ #if we got no data at all, wait a little longer
+ elif time.time() - begin > self._timeout * 2:
+ break
+ try:
+ chunk = self._cmd_sock.recv(8192)
+ if chunk:
+ buf.append(chunk)
+ begin = time.time()
+ else:
+ time.sleep(0.1)
+ except:
+ pass
+
+ return ''.join(buf)
+
+ def _send_fiff_command(self, command, data=None):
+ """Send a command through the data connection as a fiff tag
+
+ Parameters
+ ----------
+ command : int
+ The command code.
+
+ data : str
+ Additional data to send.
+ """
+ kind = FIFF.FIFF_MNE_RT_COMMAND
+ type = FIFF.FIFFT_VOID
+ size = 4
+ if data is not None:
+ size += len(data) # first 4 bytes are the command code
+ next = 0
+
+ msg = np.array(kind, dtype='>i4').tostring()
+ msg += np.array(type, dtype='>i4').tostring()
+ msg += np.array(size, dtype='>i4').tostring()
+ msg += np.array(next, dtype='>i4').tostring()
+
+ msg += np.array(command, dtype='>i4').tostring()
+ if data is not None:
+ msg += np.array(data, dtype='>c').tostring()
+
+ self._data_sock.sendall(msg)
+
+ def get_measurement_info(self):
+ """Get the measurement information
+
+ Returns
+ -------
+ info : dict
+ The measurement information.
+ """
+ cmd = 'measinfo %d' % self._client_id
+ self._send_command(cmd)
+
+ buff = []
+ directory = []
+ pos = 0
+ while True:
+ tag, this_buff = _recv_tag_raw(self._data_sock)
+ tag.pos = pos
+ pos += 16 + tag.size
+ directory.append(tag)
+ buff.append(this_buff)
+ if tag.kind == FIFF.FIFF_BLOCK_END and tag.type == FIFF.FIFFT_INT:
+ val = np.fromstring(this_buff[-4:], dtype=">i4")
+ if val == FIFF.FIFFB_MEAS_INFO:
+ break
+
+ buff = ''.join(buff)
+
+ fid = StringIO.StringIO(buff)
+ tree, _ = make_dir_tree(fid, directory)
+ info, meas = read_meas_info(fid, tree)
+
+ return info
+
+ def set_client_alias(self, alias):
+ """Set client alias
+
+ Parameters
+ ----------
+ alias : str
+ The client alias.
+ """
+ self._send_fiff_command(MNE_RT_SET_CLIENT_ALIAS, alias)
+
+ def get_client_id(self):
+ """Get the client ID
+
+ Returns
+ -------
+ id : int
+ The client ID.
+ """
+ self._send_fiff_command(MNE_RT_GET_CLIENT_ID)
+
+ # ID is send as answer
+ tag, buff = _recv_tag_raw(self._data_sock)
+ if (tag.kind == FIFF.FIFF_MNE_RT_CLIENT_ID and
+ tag.type == FIFF.FIFFT_INT):
+ client_id = int(np.fromstring(buff[-4:], dtype=">i4"))
+ else:
+ raise RuntimeError('wrong tag received')
+
+ return client_id
+
+ def start_measurement(self):
+ """Start the measurement"""
+ cmd = 'start %d' % self._client_id
+ self._send_command(cmd)
+
+ def stop_measurement(self):
+ """Stop the measurement"""
+ self._send_command('stop-all')
+
+ def start_receive_thread(self, nchan):
+ """Start the receive thread
+
+ If the measurement has not been started, it will also be started.
+
+ Parameters
+ ----------
+ nchan : int
+ The number of channels in the data.
+ """
+
+ if self._recv_thread is None:
+ self.start_measurement()
+
+ self._recv_thread = threading.Thread(target=_buffer_recv_worker,
+ args=(self, nchan))
+ self._recv_thread.start()
+
+ def stop_receive_thread(self, nchan, stop_measurement=False):
+ """Stop the receive thread
+
+ Parameters
+ ----------
+ stop_measurement : bool
+ Also stop the measurement.
+ """
+ if self._recv_thread is not None:
+ self._recv_thread.stop()
+ self._recv_thread = None
+
+ if stop_measurement:
+ self.stop_measurement()
+
+ def register_receive_callback(self, callback):
+ """Register a raw buffer receive callback
+
+ Parameters
+ ----------
+ callback : callable
+ The callback. The raw buffer is passed as the first parameter
+ to callback.
+ """
+ if callback not in self._recv_callbacks:
+ self._recv_callbacks.append(callback)
+
+ def unregister_receive_callback(self, callback):
+ """Unregister a raw buffer receive callback
+ """
+ if callback in self._recv_callbacks:
+ self._recv_callbacks.remove(callback)
+
+ def _push_raw_buffer(self, raw_buffer):
+ """Push raw buffer to clients using callbacks"""
+ for callback in self._recv_callbacks:
+ callback(raw_buffer)
+
+ def read_raw_buffer(self, nchan):
+ """Read a single buffer with raw data
+
+ Parameters
+ ----------
+ nchan : int
+ The number of channels (info['nchan']).
+
+ Returns
+ -------
+ raw_buffer : float array, shape=(nchan, n_times)
+ The raw data.
+ """
+ tag, this_buff = _recv_tag_raw(self._data_sock)
+
+ # skip tags until we get a data buffer
+ while tag.kind != FIFF.FIFF_DATA_BUFFER:
+ tag, this_buff = _recv_tag_raw(self._data_sock)
+
+ buff = StringIO.StringIO(this_buff)
+ tag = read_tag(buff)
+ raw_buffer = tag.data.reshape(-1, nchan).T
+
+ return raw_buffer
+
+ def raw_buffers(self, nchan):
+ """Return an iterator over raw buffers
+
+ Parameters
+ ----------
+ nchan : int
+ The number of channels (info['nchan']).
+
+ Returns
+ -------
+ raw_buffer : generator
+ Generator for iteration over raw buffers.
+ """
+ while True:
+ raw_buffer = self.read_raw_buffer(nchan)
+ if raw_buffer is not None:
+ yield raw_buffer
+ else:
+ break
diff --git a/mne/realtime/epochs.py b/mne/realtime/epochs.py
new file mode 100644
index 0000000..c24725c
--- /dev/null
+++ b/mne/realtime/epochs.py
@@ -0,0 +1,398 @@
+# Authors: Christoph Dinh <chdinh at nmr.mgh.harvard.edu>
+# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
+# Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Denis Engemann <d.engemann at fz-juelich.de>
+#
+# License: BSD (3-clause)
+import time
+import copy
+
+import numpy as np
+
+from ..fiff import pick_channels, pick_types
+from ..utils import logger, verbose
+from ..baseline import rescale
+from ..epochs import _BaseEpochs
+from ..event import _find_events
+from ..filter import detrend
+from ..fiff.proj import setup_proj
+
+
+class RtEpochs(_BaseEpochs):
+ """Realtime Epochs
+
+ Can receive epochs in real time from an RtClient.
+
+ For example, to get some epochs from a running mne_rt_server on
+ 'localhost', you could use:
+
+ client = mne.realtime.RtClient('localhost')
+ event_id, tmin, tmax = 1, -0.2, 0.5
+
+ epochs = mne.realtime.RtEpochs(client, event_id, tmin, tmax)
+ epochs.start() # start the measurement and start receiving epochs
+
+ evoked_1 = epochs.average() # computed over all epochs
+ evoked_2 = epochs[-5:].average() # computed over the last 5 epochs
+
+ Parameters
+ ----------
+ client : instance of mne.realtime.RtClient
+ The realtime client.
+ event_id : int | list of int
+ The id of the event to consider. If int, only events with the
+ ID specified by event_id are considered. Multiple event ID's
+ can be specified using a list.
+ tmin : float
+ Start time before event.
+ tmax : float
+ End time after event.
+ stim_channel : string or list of string
+ Name of the stim channel or all the stim channels affected by
+ the trigger.
+ sleep_time : float
+ Time in seconds to wait between checking for new epochs when epochs
+ are requested and the receive queue is empty.
+ name : string
+ Comment that describes the Evoked data created.
+ keep_comp : boolean
+ Apply CTF gradient compensation.
+ baseline : None (default) or tuple of length 2
+ The time interval to apply baseline correction.
+ If None do not apply it. If baseline is (a, b)
+ the interval is between "a (s)" and "b (s)".
+ If a is None the beginning of the data is used
+ and if b is None then b is set to the end of the interval.
+ If baseline is equal to (None, None) all the time
+ interval is used.
+ reject : dict
+ Epoch rejection parameters based on peak to peak amplitude.
+ Valid keys are 'grad' | 'mag' | 'eeg' | 'eog' | 'ecg'.
+ If reject is None then no rejection is done.
+ Values are float. Example:
+ reject = dict(grad=4000e-13, # T / m (gradiometers)
+ mag=4e-12, # T (magnetometers)
+ eeg=40e-6, # uV (EEG channels)
+ eog=250e-6 # uV (EOG channels)
+ )
+ flat : dict
+ Epoch rejection parameters based on flatness of signal
+ Valid keys are 'grad' | 'mag' | 'eeg' | 'eog' | 'ecg'
+ If flat is None then no rejection is done.
+ proj : bool, optional
+ Apply SSP projection vectors
+ decim : int
+ Factor by which to downsample the data from the raw file upon import.
+ Warning: This simply selects every nth sample, data is not filtered
+ here. If data is not properly filtered, aliasing artifacts may occur.
+ reject_tmin : scalar | None
+ Start of the time window used to reject epochs (with the default None,
+ the window will start with tmin).
+ reject_tmax : scalar | None
+ End of the time window used to reject epochs (with the default None,
+ the window will end with tmax).
+ detrend : int | None
+ If 0 or 1, the data channels (MEG and EEG) will be detrended when
+ loaded. 0 is a constant (DC) detrend, 1 is a linear detrend. None
+ is no detrending. Note that detrending is performed before baseline
+ correction. If no DC offset is preferred (zeroth order detrending),
+ either turn off baseline correction, as this may introduce a DC
+ shift, or set baseline correction to use the entire time interval
+ (will yield equivalent results but be slower).
+ add_eeg_ref : bool
+ If True, an EEG average reference will be added (unless one
+ already exists).
+ isi_max : float
+ The maximmum time in seconds between epochs. If no epoch
+ arrives in the next isi_max seconds the RtEpochs stops.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ Defaults to client.verbose.
+
+ Attributes
+ ----------
+ info : dict
+ Measurement info.
+ event_id : dict
+ Names of of conditions corresponding to event_ids.
+ ch_names : list of string
+ List of channels' names.
+ events : list of tuples
+ The events associated with the epochs currently in the queue.
+ verbose : bool, str, int, or None
+ See above.
+ """
+ @verbose
+ def __init__(self, client, event_id, tmin, tmax, stim_channel='STI 014',
+ sleep_time=0.1, baseline=(None, 0), picks=None,
+ name='Unknown', keep_comp=None, dest_comp=None, reject=None,
+ flat=None, proj=True, decim=1, reject_tmin=None,
+ reject_tmax=None, detrend=None, add_eeg_ref=True,
+ isi_max=2., verbose=None):
+
+ info = client.get_measurement_info()
+
+ # the measurement info of the data as we receive it
+ self._client_info = copy.deepcopy(info)
+
+ verbose = client.verbose if verbose is None else verbose
+
+ # call _BaseEpochs constructor
+ super(RtEpochs, self).__init__(info, event_id, tmin, tmax,
+ baseline=baseline, picks=picks, name=name, keep_comp=keep_comp,
+ dest_comp=dest_comp, reject=reject, flat=flat,
+ decim=decim, reject_tmin=reject_tmin, reject_tmax=reject_tmax,
+ detrend=detrend, add_eeg_ref=add_eeg_ref, verbose=verbose)
+
+ self.proj = proj
+ self._projector, self.info = setup_proj(self.info, add_eeg_ref,
+ activate=self.proj)
+
+ self._client = client
+
+ if not isinstance(stim_channel, list):
+ stim_channel = [stim_channel]
+
+ stim_picks = pick_channels(self._client_info['ch_names'],
+ include=stim_channel, exclude=[])
+
+ if len(stim_picks) == 0:
+ raise ValueError('No stim channel found to extract event '
+ 'triggers.')
+
+ self._stim_picks = stim_picks
+
+ self._sleep_time = sleep_time
+
+ # add calibration factors
+ cals = np.zeros(self._client_info['nchan'])
+ for k in range(self._client_info['nchan']):
+ cals[k] = (self._client_info['chs'][k]['range']
+ * self._client_info['chs'][k]['cal'])
+ self._cals = cals[:, None]
+
+ # FIFO queues for received epochs and events
+ self._epoch_queue = list()
+ self.events = list()
+
+ # variables needed for receiving raw buffers
+ self._last_buffer = None
+ self._first_samp = 0
+ self._event_backlog = list()
+
+ # Number of good and bad epochs received
+ self._n_good = 0
+ self._n_bad = 0
+
+ self._started = False
+ self._last_time = time.time()
+
+ self.isi_max = isi_max
+
+ def start(self):
+ """Start receiving epochs
+
+ The measurement will be started if it has not already been started.
+ """
+ if not self._started:
+ # register the callback
+ self._client.register_receive_callback(self._process_raw_buffer)
+
+ # start the measurement and the receive thread
+ nchan = self._client_info['nchan']
+ self._client.start_receive_thread(nchan)
+ self._started = True
+
+ self._last_time = np.inf # init delay counter. Will stop iterations
+
+ def stop(self, stop_receive_thread=False, stop_measurement=False):
+ """Stop receiving epochs
+
+ Parameters
+ ----------
+ stop_receive_thread : bool
+ Stop the receive thread. Note: Other RtEpochs instances will also
+ stop receiving epochs when the receive thread is stopped. The
+ receive thread will always be stopped if stop_measurement is True.
+
+ stop_measurement : bool
+ Also stop the measurement. Note: Other clients attached to the
+ server will also stop receiving data.
+ """
+ if self._started:
+ self._client.unregister_receive_callback(self._process_raw_buffer)
+ self._started = False
+
+ if stop_receive_thread or stop_measurement:
+ self._client.stop_receive_thread(stop_measurement=stop_measurement)
+
+ def next(self, return_event_id=False):
+ """To make iteration over epochs easy.
+ """
+ first = True
+ while True:
+ current_time = time.time()
+ if current_time > (self._last_time + self.isi_max):
+ logger.info('Time of %s seconds exceeded.' % self.isi_max)
+ raise StopIteration
+ if len(self._epoch_queue) > self._current:
+ epoch = self._epoch_queue[self._current]
+ event_id = self.events[self._current][-1]
+ self._current += 1
+ self._last_time = current_time
+ if return_event_id:
+ return epoch, event_id
+ else:
+ return epoch
+ if self._started:
+ if first:
+ logger.info('Waiting for epoch %d' % (self._current + 1))
+ first = False
+ time.sleep(self._sleep_time)
+ else:
+ raise RuntimeError('Not enough epochs in queue and currently '
+ 'not receiving epochs, cannot get epochs!')
+
+ def _get_data_from_disk(self):
+ """Return the data for n_epochs epochs"""
+
+ epochs = list()
+ for epoch in self:
+ epochs.append(epoch)
+
+ data = np.array(epochs)
+
+ return data
+
+ def _process_raw_buffer(self, raw_buffer):
+ """Process raw buffer (callback from RtClient)
+
+ Note: Do not print log messages during regular use. It will be printed
+ asynchronously which is annyoing when working in an interactive shell.
+
+ Parameters
+ ----------
+ raw_buffer : array of float, shape=(nchan, n_times)
+ The raw buffer.
+ """
+ verbose = 'ERROR'
+ sfreq = self.info['sfreq']
+ n_samp = len(self._raw_times)
+
+ # relative start and stop positions in samples
+ tmin_samp = int(round(sfreq * self.tmin))
+ tmax_samp = tmin_samp + n_samp
+
+ last_samp = self._first_samp + raw_buffer.shape[1] - 1
+
+ # apply calibration without inplace modification
+ raw_buffer = self._cals * raw_buffer
+
+ # detect events
+ data = np.abs(raw_buffer[self._stim_picks]).astype(np.int)
+ data = np.atleast_2d(data)
+ buff_events = _find_events(data, self._first_samp, verbose=verbose)
+
+ events = self._event_backlog
+ for event_id in self.event_id.values():
+ idx = np.where(buff_events[:, -1] == event_id)[0]
+ events.extend(zip(list(buff_events[idx, 0]),
+ list(buff_events[idx, -1])))
+
+ events.sort()
+
+ event_backlog = list()
+ for event_samp, event_id in events:
+ epoch = None
+ if (event_samp + tmin_samp >= self._first_samp
+ and event_samp + tmax_samp <= last_samp):
+ # easy case: whole epoch is in this buffer
+ start = event_samp + tmin_samp - self._first_samp
+ stop = event_samp + tmax_samp - self._first_samp
+ epoch = raw_buffer[:, start:stop]
+ elif (event_samp + tmin_samp < self._first_samp
+ and event_samp + tmax_samp <= last_samp):
+ # have to use some samples from previous buffer
+ if self._last_buffer is None:
+ continue
+ n_last = self._first_samp - (event_samp + tmin_samp)
+ n_this = n_samp - n_last
+ epoch = np.c_[self._last_buffer[:, -n_last:],
+ raw_buffer[:, :n_this]]
+ elif event_samp + tmax_samp > last_samp:
+ # we need samples from next buffer
+ if event_samp + tmin_samp < self._first_samp:
+ raise RuntimeError('Epoch spans more than two raw '
+ 'buffers, increase buffer size!')
+ # we will process this epoch with the next buffer
+ event_backlog.append((event_samp, event_id))
+ else:
+ raise RuntimeError('Unhandled case..')
+
+ if epoch is not None:
+ self._append_epoch_to_queue(epoch, event_samp, event_id)
+
+ # set things up for processing of next buffer
+ self._event_backlog = event_backlog
+ self._first_samp = last_samp + 1
+ self._last_buffer = raw_buffer
+
+ def _append_epoch_to_queue(self, epoch, event_samp, event_id):
+ """Append a (raw) epoch to queue
+
+ Note: Do not print log messages during regular use. It will be printed
+ asynchronously which is annyoing when working in an interactive shell.
+
+ Parameters
+ ----------
+ epoch : array of float, shape=(nchan, n_times)
+ The raw epoch (only calibration has been applied) over all
+ channels.
+ event_samp : int
+ The time in samples when the epoch occured.
+ event_id : int
+ The event ID of the epoch.
+ """
+ # select the channels
+ epoch = epoch[self.picks, :]
+
+ # handle offset
+ if self._offset is not None:
+ epoch += self._offset
+
+ # apply SSP
+ if self.proj and self._projector is not None:
+ epoch = np.dot(self._projector, epoch)
+
+ # Detrend
+ if self.detrend is not None:
+ picks = pick_types(self.info, meg=True, eeg=True, stim=False,
+ eog=False, ecg=False, emg=False, ref_meg=False)
+ epoch[picks] = detrend(epoch[picks], self.detrend, axis=1)
+
+ # Baseline correct
+ epoch = rescale(epoch, self._raw_times, self.baseline, 'mean',
+ copy=False, verbose='ERROR')
+
+ # Decimate
+ if self.decim > 1:
+ epoch = epoch[:, self._decim_idx]
+
+ # Decide if this is a good epoch
+ is_good, _ = self._is_good_epoch(epoch, verbose='ERROR')
+
+ if is_good:
+ self._epoch_queue.append(epoch)
+ self.events.append((event_samp, 0, event_id))
+ self._n_good += 1
+ else:
+ self._n_bad += 1
+
+ def __repr__(self):
+ s = 'good / bad epochs received: %d / %d, epochs in queue: %d, '\
+ % (self._n_good, self._n_bad, len(self._epoch_queue))
+ s += ', tmin : %s (s)' % self.tmin
+ s += ', tmax : %s (s)' % self.tmax
+ s += ', baseline : %s' % str(self.baseline)
+ return '<RtEpochs | %s>' % s
diff --git a/mne/realtime/mockclient.py b/mne/realtime/mockclient.py
new file mode 100644
index 0000000..a1039be
--- /dev/null
+++ b/mne/realtime/mockclient.py
@@ -0,0 +1,175 @@
+# Authors: Mainak Jas <mainak at neuro.hut.fi>
+# Denis Engemann <d.engemann at fz-juelich.de>
+# Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+#
+# License: BSD (3-clause)
+
+import copy
+import numpy as np
+from ..event import find_events
+
+
+class MockRtClient(object):
+ """Mock Realtime Client
+
+ Attributes
+ ----------
+ raw : instance of Raw object
+ The raw object which simulates the RtClient
+ info : dict
+ Measurement info.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+ def __init__(self, raw, verbose=None):
+ self.raw = raw
+ self.info = copy.deepcopy(self.raw.info)
+ self.verbose = verbose
+
+ self._current = dict() # pointer to current index for the event
+ self._last = dict() # Last index for the event
+
+ def get_measurement_info(self):
+ """Returns the measurement info.
+
+ Returns
+ -------
+ self.info : dict
+ The measurement info.
+ """
+ return self.info
+
+ def send_data(self, epochs, picks, tmin, tmax, buffer_size):
+ """Read from raw object and send them to RtEpochs for processing.
+
+ Parameters
+ ----------
+ epochs : instance of RtEpochs
+ The epochs object.
+ picks : array of int
+ Indices of channels.
+ tmin : float
+ Time instant to start receiving buffers.
+ tmax : float
+ Time instant to stop receiving buffers.
+ buffer_size : int
+ Size of each buffer in terms of number of samples.
+ """
+ # this is important to emulate a thread, instead of automatically
+ # or constantly sending data, we will invoke this explicitly to send
+ # the next buffer
+
+ sfreq = self.info['sfreq']
+ tmin_samp = int(round(sfreq * tmin))
+ tmax_samp = int(round(sfreq * tmax))
+
+ iter_times = zip(range(tmin_samp, tmax_samp, buffer_size),
+ range(buffer_size, tmax_samp, buffer_size))
+
+ for ii, (start, stop) in enumerate(iter_times):
+ # channels are picked in _append_epoch_to_queue. No need to pick
+ # here
+ data, times = self.raw[:, start:stop]
+
+ # to undo the calibration done in _process_raw_buffer
+ cals = np.zeros(self.info['nchan'])
+ for k in range(self.info['nchan']):
+ cals[k] = (self.info['chs'][k]['range']
+ * self.info['chs'][k]['cal'])
+
+ self._cals = cals[:, None]
+ data[picks, :] = data[picks, :] / self._cals
+
+ epochs._process_raw_buffer(data)
+
+ # The following methods do not seem to be important for this use case,
+ # but they need to be present for the emulation to work because
+ # RtEpochs expects them to be there.
+
+ def get_event_data(self, event_id, tmin, tmax, picks, stim_channel=None,
+ min_duration=0):
+ """Simulate the data for a particular event-id.
+
+ The epochs corresponding to a particular event-id are returned. The
+ method remembers the epoch that was returned in the previous call and
+ returns the next epoch in sequence. Once all epochs corresponding to
+ an event-id have been exhausted, the method returns None.
+
+ Parameters
+ ----------
+ event_id : int
+ The id of the event to consider.
+ tmin : float
+ Start time before event.
+ tmax : float
+ End time after event.
+ stim_channel : None | string | list of string
+ Name of the stim channel or all the stim channels
+ affected by the trigger. If None, the config variables
+ 'MNE_STIM_CHANNEL', 'MNE_STIM_CHANNEL_1', 'MNE_STIM_CHANNEL_2',
+ etc. are read. If these are not found, it will default to
+ 'STI 014'.
+ min_duration : float
+ The minimum duration of a change in the events channel required
+ to consider it as an event (in seconds).
+
+ Returns
+ -------
+ data : 2D array with shape [n_channels, n_times]
+ The epochs that are being simulated
+ """
+
+ # Get the list of all events
+ events = find_events(self.raw, stim_channel=stim_channel,
+ verbose=False, output='onset',
+ consecutive='increasing',
+ min_duration=min_duration)
+
+ # Get the list of only the specified event
+ idx = np.where(events[:, -1] == event_id)[0]
+ event_samp = events[idx, 0]
+
+ # Only do this the first time for each event type
+ if event_id not in self._current:
+
+ # Initialize pointer for the event to 0
+ self._current[event_id] = 0
+ self._last[event_id] = len(event_samp)
+
+ # relative start and stop positions in samples
+ tmin_samp = int(round(self.info['sfreq'] * tmin))
+ tmax_samp = int(round(self.info['sfreq'] * tmax)) + 1
+
+ if self._current[event_id] < self._last[event_id]:
+
+ # Select the current event from the events list
+ ev_samp = event_samp[self._current[event_id]]
+
+ # absolute start and stop positions in samples
+ start = ev_samp + tmin_samp - self.raw.first_samp
+ stop = ev_samp + tmax_samp - self.raw.first_samp
+
+ self._current[event_id] += 1 # increment pointer
+
+ data, _ = self.raw[picks, start:stop]
+
+ return data
+
+ else:
+ return None
+
+ def register_receive_callback(self, x):
+ """API boilerplate"""
+ pass
+
+ def start_receive_thread(self, x):
+ """API boilerplate"""
+ pass
+
+ def unregister_receive_callback(self, x):
+ """API boilerplate"""
+ pass
+
+ def _stop_receive_thread(self):
+ """API boilerplate"""
+ pass
diff --git a/mne/realtime/stim_server_client.py b/mne/realtime/stim_server_client.py
new file mode 100644
index 0000000..a572176
--- /dev/null
+++ b/mne/realtime/stim_server_client.py
@@ -0,0 +1,289 @@
+# Author: Mainak Jas <mainak at neuro.hut.fi>
+# License: BSD (3-clause)
+
+import Queue
+import time
+import socket
+import SocketServer
+import threading
+
+import numpy as np
+
+from ..utils import logger, verbose
+
+
+class _ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
+ """Creates a threaded TCP server
+
+ Parameters
+ ----------
+ server_address : str
+ Address on which server is listening
+ request_handler_class : subclass of BaseRequestHandler
+ _TriggerHandler which defines the handle method
+ stim_server : instance of StimServer
+ object of StimServer class
+ """
+
+ def __init__(self, server_address, request_handler_class,
+ stim_server):
+
+ # Basically, this server is the same as a normal TCPServer class
+ # except that it has an additional attribute stim_server
+
+ # Create the server and bind it to the desired server address
+ SocketServer.TCPServer.__init__(self, server_address,
+ request_handler_class,
+ False)
+
+ self.stim_server = stim_server
+
+
+class _TriggerHandler(SocketServer.BaseRequestHandler):
+ """Request handler on the server side."""
+
+ def handle(self):
+ """Method to handle requests on the server side."""
+
+ self.request.settimeout(None)
+
+ while self.server.stim_server._running:
+
+ data = self.request.recv(1024) # clip input at 1Kb
+
+ if data == 'add client':
+ # Add stim_server._client
+ client_id = self.server.stim_server \
+ ._add_client(self.client_address[0],
+ self)
+
+ # Instantiate queue for communication between threads
+ # Note: new queue for each handler
+ if not hasattr(self, '_tx_queue'):
+ self._tx_queue = Queue.Queue()
+
+ self.request.sendall("Client added")
+
+ # Mark the client as running
+ for client in self.server.stim_server._clients:
+ if client['id'] == client_id:
+ client['running'] = True
+
+ if data == 'get trigger':
+
+ # Pop triggers and send them
+ if (self._tx_queue.qsize() > 0 and
+ self.server.stim_server, '_clients'):
+
+ trigger = self._tx_queue.get()
+ self.request.sendall(str(trigger))
+ else:
+ self.request.sendall("Empty")
+
+
+class StimServer(object):
+ """Stimulation Server
+
+ Server to communicate with StimClient(s).
+
+ Parameters
+ ----------
+ ip : str
+ IP address of the host where StimServer is running.
+ port : int
+ The port to which the stimulation server must bind to.
+ n_clients : int
+ The number of clients which will connect to the server.
+ """
+
+ def __init__(self, ip='localhost', port=4218, n_clients=1):
+
+ # Start a threaded TCP server, binding to localhost on specified port
+ self._data = _ThreadedTCPServer((ip, port),
+ _TriggerHandler, self)
+ self.n_clients = n_clients
+
+ def __enter__(self):
+ # This is done to avoid "[Errno 98] Address already in use"
+ self._data.allow_reuse_address = True
+ self._data.server_bind()
+ self._data.server_activate()
+
+ # Start a thread for the server
+ self._thread = threading.Thread(target=self._data.serve_forever)
+
+ # Ctrl-C will cleanly kill all spawned threads
+ # Once the main thread exits, other threads will exit
+ self._thread.daemon = True
+ self._thread.start()
+
+ self._running = False
+ self._clients = list()
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.shutdown()
+
+ @verbose
+ def start(self, timeout=np.inf, verbose=None):
+ """Method to start the server.
+
+ Parameters
+ ----------
+ timeout : float
+ Maximum time to wait for clients to be added.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+
+ # Start server
+ if not self._running:
+ logger.info('RtServer: Start')
+ self._running = True
+
+ start_time = time.time() # init delay counter.
+
+ # wait till n_clients are added
+ while (len(self._clients) < self.n_clients):
+ current_time = time.time()
+
+ if (current_time > start_time + timeout):
+ raise StopIteration
+
+ time.sleep(0.1)
+
+ @verbose
+ def _add_client(self, ip, sock, verbose=None):
+ """Add client.
+
+ Parameters
+ ----------
+ ip : str
+ IP address of the client.
+ sock : instance of socket.socket
+ The client socket.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+
+ logger.info("Adding client with ip = %s" % ip)
+
+ client = dict(ip=ip, id=len(self._clients), running=False, socket=sock)
+ self._clients.append(client)
+
+ return client['id']
+
+ @verbose
+ def shutdown(self, verbose=None):
+ """Method to shutdown the client and server.
+
+ Parameters
+ ----------
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+
+ logger.info("Shutting down ...")
+
+ # stop running all the clients
+ if hasattr(self, '_clients'):
+ for client in self._clients:
+ client['running'] = False
+
+ self._running = False
+
+ self._data.shutdown()
+ self._data.server_close()
+ self._data.socket.close()
+
+ @verbose
+ def add_trigger(self, trigger, verbose=None):
+ """Method to add a trigger.
+
+ Parameters
+ ----------
+ trigger : int
+ The trigger to be added to the queue for sending to StimClient.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+
+ for client in self._clients:
+ client_id = client['id']
+ logger.info("Sending trigger %d to client %d"
+ % (trigger, client_id))
+ client['socket']._tx_queue.put(trigger)
+
+
+class StimClient(object):
+ """Stimulation Client
+
+ Client to communicate with StimServer
+
+ Parameters
+ ----------
+ host : str
+ Hostname (or IP address) of the host where StimServer is running.
+ port : int
+ Port to use for the connection.
+ timeout : float
+ Communication timeout in seconds.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+
+ @verbose
+ def __init__(self, host, port=4218, timeout=5.0, verbose=None):
+ self._host = host
+ self._port = port
+
+ try:
+ logger.info("Setting up client socket")
+ self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self._sock.settimeout(timeout)
+ self._sock.connect((host, port))
+
+ logger.info("Establishing connection with server")
+ self._sock.send("add client")
+ resp = self._sock.recv(1024)
+
+ if resp == 'Client added':
+ logger.info("Connection established")
+
+ except Exception:
+ raise RuntimeError('Setting up acquisition <-> stimulation '
+ 'computer connection (host: %s '
+ 'port: %d) failed. Make sure StimServer '
+ 'is running.' % (host, port))
+
+ @verbose
+ def get_trigger(self, timeout=5.0, verbose=None):
+ """Method to get triggers from StimServer.
+
+ Parameters
+ ----------
+ timeout : float
+ maximum time to wait for a valid trigger from the server
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+ start_time = time.time() # init delay counter. Will stop iterations
+
+ while True:
+ try:
+ current_time = time.time()
+
+ # Raise timeout error
+ if current_time > (start_time + timeout):
+ logger.info("received nothing")
+ return None
+
+ self._sock.send("get trigger")
+ trigger = self._sock.recv(1024)
+
+ if trigger != 'Empty':
+ logger.info("received trigger %s" % str(trigger))
+ return int(trigger)
+
+ except RuntimeError as err:
+ logger.info('Cannot receive triggers: %s' % (err))
diff --git a/mne/tests/__init__.py b/mne/realtime/tests/__init__.py
similarity index 100%
copy from mne/tests/__init__.py
copy to mne/realtime/tests/__init__.py
diff --git a/mne/realtime/tests/test_mockclient.py b/mne/realtime/tests/test_mockclient.py
new file mode 100644
index 0000000..5def1ad
--- /dev/null
+++ b/mne/realtime/tests/test_mockclient.py
@@ -0,0 +1,58 @@
+import os.path as op
+
+import mne
+from mne import Epochs, read_events
+from mne.realtime import MockRtClient, RtEpochs
+
+from nose.tools import assert_true
+from numpy.testing import assert_array_equal
+
+base_dir = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data')
+raw_fname = op.join(base_dir, 'test_raw.fif')
+event_name = op.join(base_dir, 'test-eve.fif')
+
+raw = mne.fiff.Raw(raw_fname, preload=True, verbose=False)
+
+events = read_events(event_name)
+
+picks = mne.fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
+ stim=True, exclude=raw.info['bads'])
+
+
+def test_mockclient():
+ """Test the RtMockClient."""
+
+ event_id, tmin, tmax = 1, -0.2, 0.5
+
+ epochs = Epochs(raw, events[:7], event_id=event_id, tmin=tmin, tmax=tmax,
+ picks=picks, baseline=(None, 0), preload=True)
+ data = epochs.get_data()
+
+ rt_client = MockRtClient(raw)
+ rt_epochs = RtEpochs(rt_client, event_id, tmin, tmax, picks=picks)
+
+ rt_epochs.start()
+ rt_client.send_data(rt_epochs, picks, tmin=0, tmax=10, buffer_size=1000)
+
+ rt_data = rt_epochs.get_data()
+
+ assert_true(rt_data.shape == data.shape)
+ assert_array_equal(rt_data, data)
+
+
+def test_get_event_data():
+ """Test emulation of realtime data stream."""
+
+ event_id, tmin, tmax = 2, -0.1, 0.3
+ epochs = Epochs(raw, events, event_id=event_id,
+ tmin=tmin, tmax=tmax, picks=picks, baseline=None,
+ preload=True, proj=False)
+
+ data = epochs.get_data()[0, :, :]
+
+ rt_client = MockRtClient(raw)
+ rt_data = rt_client.get_event_data(event_id=event_id, tmin=tmin,
+ tmax=tmax, picks=picks,
+ stim_channel='STI 014')
+
+ assert_array_equal(rt_data, data)
diff --git a/mne/realtime/tests/test_stim_client_server.py b/mne/realtime/tests/test_stim_client_server.py
new file mode 100644
index 0000000..51612cb
--- /dev/null
+++ b/mne/realtime/tests/test_stim_client_server.py
@@ -0,0 +1,63 @@
+import threading
+import time
+import Queue
+
+from mne.realtime import StimServer, StimClient
+from nose.tools import assert_equal, assert_raises
+
+
+def test_connection():
+ """Test TCP/IP connection for StimServer <-> StimClient.
+ """
+
+ # have to start a thread to simulate the effect of two
+ # different computers since stim_server.start() is designed to
+ # be a blocking method
+
+ # use separate queues because timing matters
+ trig_queue1 = Queue.Queue()
+ trig_queue2 = Queue.Queue()
+
+ # start a thread to emulate 1st client
+ thread1 = threading.Thread(target=connect_client, args=(trig_queue1,))
+ thread1.daemon = True
+ thread1.start()
+
+ # start another thread to emulate 2nd client
+ thread2 = threading.Thread(target=connect_client, args=(trig_queue2,))
+ thread2.daemon = True
+ thread2.start()
+
+ with StimServer('localhost', port=4218, n_clients=2) as stim_server:
+ stim_server.start()
+
+ # Add the trigger to the queue for both clients
+ stim_server.add_trigger(20)
+
+ # the assert_equal must be in the test_connection() method
+ # Hence communication between threads is necessary
+ trig1 = trig_queue1.get()
+ trig2 = trig_queue2.get()
+ assert_equal(trig1, 20)
+
+ # test if both clients receive the same trigger
+ assert_equal(trig1, trig2)
+
+ # test timeout for stim_server
+ with StimServer('localhost', port=4218) as stim_server:
+ assert_raises(StopIteration, stim_server.start, 1.0)
+
+
+def connect_client(trig_queue):
+ """Helper method that instantiates the StimClient.
+ """
+ # just wait till the main thread reaches stim_server.start()
+ time.sleep(1.)
+
+ # instantiate StimClient
+ stim_client = StimClient('localhost', port=4218)
+
+ # wait a bit more for script to reach stim_server.add_trigger()
+ time.sleep(1.)
+
+ trig_queue.put(stim_client.get_trigger())
diff --git a/mne/selection.py b/mne/selection.py
index 8ea7937..5f2d9fe 100644
--- a/mne/selection.py
+++ b/mne/selection.py
@@ -6,10 +6,7 @@
from os import path
-import logging
-logger = logging.getLogger('mne')
-
-from . import verbose
+from .utils import logger, verbose
@verbose
diff --git a/mne/simulation/__init__.py b/mne/simulation/__init__.py
index 7076a90..86402da 100644
--- a/mne/simulation/__init__.py
+++ b/mne/simulation/__init__.py
@@ -1,6 +1,6 @@
"""Data simulation code
"""
-from .evoked import generate_evoked
+from .evoked import generate_evoked, generate_noise_evoked, add_noise_evoked
-from .source import select_source_in_label, generate_sparse_stc
+from .source import select_source_in_label, generate_sparse_stc, generate_stc
diff --git a/mne/simulation/tests/test_evoked.py b/mne/simulation/tests/test_evoked.py
index 1417f0e..3950757 100644
--- a/mne/simulation/tests/test_evoked.py
+++ b/mne/simulation/tests/test_evoked.py
@@ -16,7 +16,7 @@ import mne
from mne.fiff.pick import pick_types_evoked, pick_types_forward
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
fwd_fname = op.join(data_path, 'MEG', 'sample',
'sample_audvis-meg-eeg-oct-6-fwd.fif')
raw_fname = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests',
@@ -27,6 +27,7 @@ cov_fname = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests',
'data', 'test-cov.fif')
+ at sample.requires_sample_data
def test_simulate_evoked():
""" Test simulation of evoked data """
@@ -36,7 +37,7 @@ def test_simulate_evoked():
cov = mne.read_cov(cov_fname)
label_names = ['Aud-lh', 'Aud-rh']
labels = [read_label(op.join(data_path, 'MEG', 'sample', 'labels',
- '%s.label' % label)) for label in label_names]
+ '%s.label' % label)) for label in label_names]
evoked_template = mne.fiff.read_evoked(ave_fname, setno=0, baseline=None)
evoked_template = pick_types_evoked(evoked_template, meg=True, eeg=True,
diff --git a/mne/simulation/tests/test_source.py b/mne/simulation/tests/test_source.py
index 0d2449e..e26da75 100644
--- a/mne/simulation/tests/test_source.py
+++ b/mne/simulation/tests/test_source.py
@@ -10,21 +10,20 @@ from mne.label import Label
from mne.simulation.source import generate_stc, generate_sparse_stc
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
fname_fwd = op.join(data_path, 'MEG', 'sample',
'sample_audvis-meg-oct-6-fwd.fif')
-fwd = read_forward_solution(fname_fwd, force_fixed=True)
label_names = ['Aud-lh', 'Aud-rh', 'Vis-rh']
-labels = [read_label(op.join(data_path, 'MEG', 'sample', 'labels',
- '%s.label' % label)) for label in label_names]
label_names_single_hemi = ['Aud-rh', 'Vis-rh']
-labels_single_hemi = [read_label(op.join(data_path, 'MEG', 'sample', 'labels',
- '%s.label' % label)) for label in label_names_single_hemi]
+ at sample.requires_sample_data
def test_generate_stc():
""" Test generation of source estimate """
+ fwd = read_forward_solution(fname_fwd, force_fixed=True)
+ labels = [read_label(op.join(data_path, 'MEG', 'sample', 'labels',
+ '%s.label' % label)) for label in label_names]
mylabels = []
for i, label in enumerate(labels):
new_label = Label(vertices=label.vertices,
@@ -74,19 +73,23 @@ def test_generate_stc():
if hemi_idx == 1:
idx += len(stc.vertno[0])
- assert_array_almost_equal(stc.data[idx],
- ((2. * i) ** 2.) * np.ones((len(idx), n_times)))
+ res = ((2. * i) ** 2.) * np.ones((len(idx), n_times))
+ assert_array_almost_equal(stc.data[idx], res)
+ at sample.requires_sample_data
def test_generate_sparse_stc():
""" Test generation of sparse source estimate """
+ fwd = read_forward_solution(fname_fwd, force_fixed=True)
+ labels = [read_label(op.join(data_path, 'MEG', 'sample', 'labels',
+ '%s.label' % label)) for label in label_names]
n_times = 10
tmin = 0
tstep = 1e-3
- stc_data = np.ones((len(labels), n_times))\
- * np.arange(len(labels))[:, None]
+ stc_data = (np.ones((len(labels), n_times))
+ * np.arange(len(labels))[:, None])
stc_1 = generate_sparse_stc(fwd['src'], labels, stc_data, tmin, tstep, 0)
for i, label in enumerate(labels):
@@ -113,8 +116,13 @@ def test_generate_sparse_stc():
assert_array_equal(stc_1.rh_vertno, stc_2.rh_vertno)
+ at sample.requires_sample_data
def test_generate_stc_single_hemi():
""" Test generation of source estimate """
+ fwd = read_forward_solution(fname_fwd, force_fixed=True)
+ labels_single_hemi = [read_label(op.join(data_path, 'MEG', 'sample',
+ 'labels', '%s.label' % label))
+ for label in label_names_single_hemi]
mylabels = []
for i, label in enumerate(labels_single_hemi):
new_label = Label(vertices=label.vertices,
@@ -164,19 +172,23 @@ def test_generate_stc_single_hemi():
if hemi_idx == 1:
idx += len(stc.vertno[0])
- assert_array_almost_equal(stc.data[idx],
- ((2. * i) ** 2.) * np.ones((len(idx), n_times)))
+ res = ((2. * i) ** 2.) * np.ones((len(idx), n_times))
+ assert_array_almost_equal(stc.data[idx], res)
+ at sample.requires_sample_data
def test_generate_sparse_stc_single_hemi():
""" Test generation of sparse source estimate """
-
+ fwd = read_forward_solution(fname_fwd, force_fixed=True)
n_times = 10
tmin = 0
tstep = 1e-3
+ labels_single_hemi = [read_label(op.join(data_path, 'MEG', 'sample',
+ 'labels', '%s.label' % label))
+ for label in label_names_single_hemi]
- stc_data = np.ones((len(labels_single_hemi), n_times))\
- * np.arange(len(labels_single_hemi))[:, None]
+ stc_data = (np.ones((len(labels_single_hemi), n_times))
+ * np.arange(len(labels_single_hemi))[:, None])
stc_1 = generate_sparse_stc(fwd['src'], labels_single_hemi, stc_data,
tmin, tstep, 0)
diff --git a/mne/source_estimate.py b/mne/source_estimate.py
index aa19e6e..39c9ec7 100644
--- a/mne/source_estimate.py
+++ b/mne/source_estimate.py
@@ -12,48 +12,17 @@ from scipy import linalg, sparse
from scipy.sparse import csr_matrix, coo_matrix
import warnings
-import logging
-logger = logging.getLogger('mne')
-
from .filter import resample
from .parallel import parallel_func
-from .surface import read_surface
-from .utils import get_subjects_dir, _check_subject, \
- _check_pandas_index_arguments, _check_pandas_installed, \
- deprecated
+from .surface import (read_surface, _get_ico_surface, read_morph_map,
+ _compute_nearest)
+from .utils import (get_subjects_dir, _check_subject,
+ _check_pandas_index_arguments, _check_pandas_installed,
+ logger, verbose)
from .viz import plot_source_estimates
-from . import verbose
from . fixes import in1d
- at deprecated('read_stc is deprecated and will be removed with version 0.7. '
- 'Please use read_source_estimate instead.')
-def read_stc(filename):
- """Read an STC file and return as dict
-
- STC files contain activations or source reconstructions.
-
- Parameters
- ----------
- filename : string
- The name of the STC file.
-
- Returns
- -------
- data: dict
- The STC structure. It has the following keys:
- tmin The first time point of the data in seconds
- tstep Time between frames in seconds
- vertices vertex indices (0 based)
- data The data matrix (nvert * ntime)
-
- See Also
- --------
- read_source_estimate
- """
- return _read_stc(filename)
-
-
def _read_stc(filename):
""" Aux Function
"""
@@ -95,31 +64,6 @@ def _read_stc(filename):
return stc
- at deprecated('write_stc is deprecated and will be removed with version 0.7. '
- 'Please use SourceEstimate.save instead.')
-def write_stc(filename, tmin, tstep, vertices, data):
- """Write an STC file
-
- Parameters
- ----------
- filename : string
- The name of the STC file.
- tmin : float
- The first time point of the data in seconds.
- tstep : float
- Time between frames in seconds.
- vertices : array of integers
- Vertex indices (0 based).
- data : 2D array
- The data matrix (nvert * ntime).
-
- See Also
- --------
- SourceEstimate.save (instance method)
- """
- return _write_stc(filename, tmin, tstep, vertices, data)
-
-
def _write_stc(filename, tmin, tstep, vertices, data):
"""Write an STC file
@@ -168,29 +112,6 @@ def _read_3(fid):
return out
- at deprecated('read_w is deprecated and will be removed with version 0.7. '
- 'Please use read_source_estimate instead.')
-def read_w(filename):
- """Read a w file and return as dict
-
- w files contain activations or source reconstructions for a single time
- point.
-
- Parameters
- ----------
- filename : string
- The name of the w file.
-
- Returns
- -------
- data: dict
- The w structure. It has the following keys:
- vertices vertex indices (0 based)
- data The data matrix (nvert long)
- """
- return _read_w(filename)
-
-
def _read_w(filename):
"""Read a w file and return as dict
@@ -248,30 +169,6 @@ def _write_3(fid, val):
fid.write(f_bytes.tostring())
- at deprecated('read_w is deprecated and will be removed with version 0.7. '
- 'Please use SoureEstimate.save instead.')
-def write_w(filename, vertices, data):
- """Read a w file
-
- w files contain activations or source reconstructions for a single time
- point.
-
- Parameters
- ----------
- filename: string
- The name of the w file.
- vertices: array of int
- Vertex indices (0 based).
- data: 1D array
- The data array (nvert).
-
- See Also
- --------
- SourceEstimate.save (instance method)
- """
- return _write_w(filename, vertices, data)
-
-
def _write_w(filename, vertices, data):
"""Read a w file
@@ -310,7 +207,7 @@ def _write_w(filename, vertices, data):
def read_source_estimate(fname, subject=None):
- """Returns a SourceEstimate object.
+ """Read a soure estimate object
Parameters
----------
@@ -323,6 +220,11 @@ def read_source_estimate(fname, subject=None):
subjects). Note that due to file specification limitations, the
subject name isn't saved to or loaded from files written to disk.
+ Returns
+ -------
+ stc : SourceEstimate | VolSourceEstimate
+ The soure estimate object loaded from file.
+
Notes
-----
- for volume source estimates, ``fname`` should provide the path to a
@@ -405,8 +307,42 @@ def read_source_estimate(fname, subject=None):
kwargs['tmin'] = 0.0
kwargs['tstep'] = 1.0
+ if ftype != 'volume':
+ # Make sure the vertices are ordered
+ vertices = kwargs['vertices']
+ if any([np.any(np.diff(v.astype(int)) <= 0) for v in vertices]):
+ sidx = [np.argsort(verts) for verts in vertices]
+ vertices = [verts[idx] for verts, idx in zip(vertices, sidx)]
+ data = kwargs['data'][np.r_[sidx[0], len(sidx[0]) + sidx[1]]]
+ kwargs['vertices'] = vertices
+ kwargs['data'] = data
+
kwargs['subject'] = subject
- return SourceEstimate(**kwargs)
+
+ if ftype == 'volume':
+ stc = VolSourceEstimate(**kwargs)
+ else:
+ stc = SourceEstimate(**kwargs)
+
+ return stc
+
+
+def _make_stc(data, vertices, tmin=None, tstep=None, subject=None):
+ """Helper function to generate either a surface or volume source estimate
+ """
+
+ if isinstance(vertices, list) and len(vertices) == 2:
+ # make a surface source estimate
+ stc = SourceEstimate(data, vertices=vertices, tmin=tmin, tstep=tstep,
+ subject=subject)
+ elif isinstance(vertices, np.ndarray) or isinstance(vertices, list)\
+ and len(vertices) == 1:
+ stc = VolSourceEstimate(data, vertices=vertices, tmin=tmin,
+ tstep=tstep, subject=subject)
+ else:
+ raise ValueError('vertices has to be either a list with one or two '
+ 'arrays or an array')
+ return stc
class _NotifyArray(np.ndarray):
@@ -465,10 +401,8 @@ def _verify_source_estimate_compat(a, b):
'names, "%s" and "%s"' % (a.name, b.name))
-class SourceEstimate(object):
- """SourceEstimate container
-
- Can be saved and loaded from .stc or .w files.
+class _BaseSourceEstimate(object):
+ """Abstract base class for source estimates
Parameters
----------
@@ -495,7 +429,7 @@ class SourceEstimate(object):
The subject name.
times : array of shape (n_times,)
The time vector.
- vertno : array or list of array of shape (n_dipoles,)
+ vertices : array or list of arrays of shape (n_dipoles,)
The indices of the dipoles in the different source spaces. Can
be an array if there is only one source space (e.g., for volumes).
data : array of shape (n_dipoles, n_times)
@@ -521,11 +455,20 @@ class SourceEstimate(object):
not all([isinstance(v, np.ndarray) for v in vertices]):
raise ValueError('Vertices, if a list, must contain one or '
'two numpy arrays')
+
+ if any([np.any(np.diff(v.astype(int)) <= 0) for v in vertices]):
+ raise ValueError('Vertices must be ordered in increasing '
+ 'order.')
+
n_src = sum([len(v) for v in vertices])
- elif not isinstance(vertices, np.ndarray):
- raise ValueError('Vertices must be a list or numpy array')
- else:
+
+ if len(vertices) == 1:
+ vertices = vertices[0]
+ elif isinstance(vertices, np.ndarray):
n_src = len(vertices)
+ else:
+ raise ValueError('Vertices must be a list or numpy array')
+
# safeguard the user against doing something silly
if data is not None and data.shape[0] != n_src:
raise ValueError('Number of vertices (%i) and stc.shape[0] (%i) '
@@ -542,67 +485,6 @@ class SourceEstimate(object):
self._update_times()
self.subject = _check_subject(None, subject, False)
- @verbose
- def save(self, fname, ftype='stc', verbose=None):
- """Save the source estimates to a file
-
- Parameters
- ----------
- fname : string
- The stem of the file name. The file names used for surface source
- spaces are obtained by adding "-lh.stc" and "-rh.stc" (or "-lh.w"
- and "-rh.w") to the stem provided, for the left and the right
- hemisphere, respectively. For volume source spaces, the stem is
- extended with "-vl.stc" or "-vl.w".
- ftype : string
- File format to use. Allowed values are "stc" (default) and "w".
- The "w" format only supports a single time point.
- verbose : bool, str, int, or None
- If not None, override default verbose level (see mne.verbose).
- Defaults to self.verbose.
- """
- if ftype not in ['stc', 'w']:
- raise ValueError('ftype must be "stc" or "w", not "%s"' % ftype)
- if self.is_surface():
- lh_data = self.data[:len(self.lh_vertno)]
- rh_data = self.data[-len(self.rh_vertno):]
-
- if ftype == 'stc':
- logger.info('Writing STC to disk...')
- _write_stc(fname + '-lh.stc', tmin=self.tmin, tstep=self.tstep,
- vertices=self.lh_vertno, data=lh_data)
- _write_stc(fname + '-rh.stc', tmin=self.tmin, tstep=self.tstep,
- vertices=self.rh_vertno, data=rh_data)
- elif ftype == 'w':
- if self.shape[1] != 1:
- raise ValueError('w files can only contain a single time '
- 'point')
- logger.info('Writing STC to disk (w format)...')
- _write_w(fname + '-lh.w', vertices=self.lh_vertno,
- data=lh_data[:, 0])
- _write_w(fname + '-rh.w', vertices=self.rh_vertno,
- data=rh_data[:, 0])
- else:
- if isinstance(self.vertno, list):
- write_vertices = self.vertno[0]
- else:
- write_vertices = self.vertno
- if ftype == 'stc':
- logger.info('Writing STC to disk...')
- if not (fname.endswith('-vl.stc')
- or fname.endswith('-vol.stc')):
- fname += '-vl.stc'
- _write_stc(fname, tmin=self.tmin, tstep=self.tstep,
- vertices=write_vertices, data=self.data)
- elif ftype == 'w':
- logger.info('Writing STC to disk (w format)...')
- if not (fname.endswith('-vl.w')
- or fname.endswith('-vol.w')):
- fname += '-vl.w'
- _write_w(fname, vertices=write_vertices, data=self.data)
-
- logger.info('[done]')
-
def _remove_kernel_sens_data_(self):
"""Remove kernel and sensor space data
@@ -616,20 +498,6 @@ class SourceEstimate(object):
self._kernel = None
self._sens_data = None
- def __repr__(self):
- if isinstance(self.vertno, list):
- nv = sum([len(v) for v in self.vertno])
- else:
- nv = self.vertno.size
- s = "%d vertices" % nv
- if self.subject is not None:
- s += ", subject : %s" % self.subject
- s += ", tmin : %s (ms)" % (1e3 * self.tmin)
- s += ", tmax : %s (ms)" % (1e3 * self.times[-1])
- s += ", tstep : %s (ms)" % (1e3 * self.tstep)
- s += ", data size : %s x %s" % self.shape
- return "<SourceEstimate | %s>" % s
-
def crop(self, tmin=None, tmax=None):
"""Restrict SourceEstimate to a time interval
@@ -654,6 +522,7 @@ class SourceEstimate(object):
self._data = self._data[:, mask]
self._update_times()
+ return self # return self for chaining methods
@verbose
def resample(self, sfreq, npad=100, window='boxcar', n_jobs=1,
@@ -703,35 +572,11 @@ class SourceEstimate(object):
return self._data
@property
- def lh_data(self):
- return self.data[:len(self.lh_vertno)]
-
- @property
- def rh_data(self):
- return self.data[len(self.lh_vertno):]
-
- @property
- def lh_vertno(self):
- return self.vertno[0]
-
- @property
- def rh_vertno(self):
- return self.vertno[1]
-
- @property
def shape(self):
if self._data is not None:
return self._data.shape
return (self._kernel.shape[0], self._sens_data.shape[1])
- def is_surface(self):
- """Returns True if source estimate is defined over surfaces
- """
- if isinstance(self.vertno, list) and len(self.vertno) == 2:
- return True
- else:
- return False
-
def _update_times(self):
"""Update the times attribute after changing tmin, tmax, or tstep"""
self.times = self.tmin + (self.tstep * np.arange(self.shape[1]))
@@ -743,13 +588,30 @@ class SourceEstimate(object):
def __iadd__(self, a):
self._remove_kernel_sens_data_()
- if isinstance(a, SourceEstimate):
+ if isinstance(a, _BaseSourceEstimate):
_verify_source_estimate_compat(self, a)
self._data += a.data
else:
self._data += a
return self
+ def mean(self):
+ """Make a summary stc file with mean power between tmin and tmax.
+
+ Returns
+ -------
+ stc : instance of SourceEstimate
+ The modified stc (note: method operates inplace).
+ """
+ data = self.data
+ tmax = self.tmin + self.tstep * data.shape[1]
+ tmin = (self.tmin + tmax) / 2.
+ tstep = tmax - self.tmin
+ mean_stc = SourceEstimate(self.data.mean(axis=1)[:, np.newaxis],
+ vertices=self.vertno, tmin=tmin,
+ tstep=tstep, subject=self.subject)
+ return mean_stc
+
def __sub__(self, a):
stc = copy.deepcopy(self)
stc -= a
@@ -757,7 +619,7 @@ class SourceEstimate(object):
def __isub__(self, a):
self._remove_kernel_sens_data_()
- if isinstance(a, SourceEstimate):
+ if isinstance(a, _BaseSourceEstimate):
_verify_source_estimate_compat(self, a)
self._data -= a.data
else:
@@ -771,7 +633,7 @@ class SourceEstimate(object):
def __idiv__(self, a):
self._remove_kernel_sens_data_()
- if isinstance(a, SourceEstimate):
+ if isinstance(a, _BaseSourceEstimate):
_verify_source_estimate_compat(self, a)
self._data /= a.data
else:
@@ -785,7 +647,7 @@ class SourceEstimate(object):
def __imul__(self, a):
self._remove_kernel_sens_data_()
- if isinstance(a, SourceEstimate):
+ if isinstance(a, _BaseSourceEstimate):
_verify_source_estimate_compat(self, a)
self._data *= a.data
else:
@@ -842,49 +704,419 @@ class SourceEstimate(object):
----------
width : scalar
Width of the individual bins in seconds.
-
func : callable
Function that is applied to summarize the data. Needs to accept a
numpy.array as first input and an ``axis`` keyword argument.
-
tstart : scalar | None
Time point where the first bin starts. The default is the first
time point of the stc.
-
tstop : scalar | None
Last possible time point contained in a bin (if the last bin would
be shorter than width it is dropped). The default is the last time
point of the stc.
+
+ Returns
+ -------
+ stc : instance of SourceEstimate
+ The binned SourceEstimate.
"""
if tstart is None:
tstart = self.tmin
if tstop is None:
tstop = self.times[-1]
- times = np.arange(tstart, tstop + self.tstep, width)
- nv, _ = self.shape
- nt = len(times) - 1
- data = np.empty((nv, nt), dtype=self.data.dtype)
- for i in xrange(nt):
- idx = (self.times >= times[i]) & (self.times < times[i + 1])
- data[:, i] = func(self.data[:, idx], axis=1)
+ times = np.arange(tstart, tstop + self.tstep, width)
+ nv, _ = self.shape
+ nt = len(times) - 1
+ data = np.empty((nv, nt), dtype=self.data.dtype)
+ for i in xrange(nt):
+ idx = (self.times >= times[i]) & (self.times < times[i + 1])
+ data[:, i] = func(self.data[:, idx], axis=1)
+
+ tmin = times[0] + width / 2.
+ stc = _make_stc(data, vertices=self.vertno,
+ tmin=tmin, tstep=width, subject=self.subject)
+ return stc
+
+ def transform_data(self, transform_fun, fun_args=None,
+ idx=None, tmin_idx=None, tmax_idx=None, **kwargs):
+ """Get data after a linear (time) transform has been applied
+
+ The transorm is applied to each source time course independently.
+
+
+ Parameters
+ ----------
+ transform_fun : callable
+ The transform to be applied. The first parameter of the function
+ is the input data. The first return value is the transformed
+ data, remaining outputs are ignored. The first dimension of the
+ transformed data has to be the same as the first dimension of the
+ input data.
+ fun_args : tuple | None
+ Additional parameters to be passed to transform_fun.
+ idx : array | None
+ Indicices of source time courses for which to compute transform.
+ If None, all time courses are used.
+ tmin_idx : int | None
+ Index of first time point to include. If None, the index of the
+ first time point is used.
+ tmax_idx : int | None
+ Index of the first time point not to include. If None, time points
+ up to (and including) the last time point are included.
+ **kwargs : dict
+ Keyword arguments to be passed to transform_fun.
+
+ Returns
+ -------
+ data_t : ndarray
+ The transformed data.
+
+ .. note::
+ Applying transforms can be significantly faster if the
+ SourceEstimate object was created using "(kernel, sens_data)", for
+ the "data" parameter as the transform is applied in sensor space.
+ Inverse methods, e.g., "apply_inverse_epochs", or "lcmv_epochs" do
+ this automatically (if possible).
+ """
+
+ if idx is None:
+ # use all time courses by default
+ idx = slice(None, None)
+
+ if fun_args is None:
+ fun_args = tuple()
+
+ if self._kernel is None and self._sens_data is None:
+ # transform source space data directly
+ data_t = transform_fun(self.data[idx, tmin_idx:tmax_idx],
+ *fun_args, **kwargs)
+
+ if isinstance(data_t, tuple):
+ # use only first return value
+ data_t = data_t[0]
+ else:
+ # apply transform in sensor space
+ sens_data_t = transform_fun(self._sens_data[:, tmin_idx:tmax_idx],
+ *fun_args, **kwargs)
+
+ if isinstance(sens_data_t, tuple):
+ # use only first return value
+ sens_data_t = sens_data_t[0]
+
+ # apply inverse
+ data_shape = sens_data_t.shape
+ if len(data_shape) > 2:
+ # flatten the last dimensions
+ sens_data_t = sens_data_t.reshape(data_shape[0],
+ np.prod(data_shape[1:]))
+
+ data_t = np.dot(self._kernel[idx, :], sens_data_t)
+
+ # restore original shape if necessary
+ if len(data_shape) > 2:
+ data_t = data_t.reshape(data_t.shape[0], *data_shape[1:])
+
+ return data_t
+
+ def transform(self, func, func_args=None,
+ idx=None, tmin=None, tmax=None, copy=False, **kwargs):
+ """Apply linear transform
+
+ The transform is applied to each source time course independently.
+
+ Parameters
+ ----------
+ func : callable
+ The transform to be applied. The first parameter of the function
+ is the input data. The first two dimensions of the transformed
+ data should be (i) vertices and (ii) time. Transforms which yield
+ 3D output (e.g. time-frequency transforms) are valid, so long as
+ the first two dimensions are vertices and time. In this case, the
+ copy parameter must be True and a list of SourceEstimates, rather
+ than a single SourceEstimate, will be returned, one for each index
+ of the 3rd dimension of the transformed data. In the case of
+ transforms yielding 2D output (e.g. filtering), the user has the
+ option of modifying the input inplace (copy = False) or returning
+ a new instance of SourceEstimate (copy = True) with the
+ transformed data.
+ func_args : tuple | None
+ Additional parameters to be passed to func.
+ idx : array | None
+ Indices of source time courses for which to compute transform.
+ If None, all time courses are used.
+ tmin : float | int | None
+ First time point to include (ms). If None, self.tmin is used.
+ tmax : float | int | None
+ Last time point to include (ms). If None, self.tmax is used.
+ copy : bool
+ If True, return a new instance of SourceEstimate instead of
+ modifying the input inplace.
+ **kwargs : dict
+ Keyword arguments to be passed to func.
+
+ Returns
+ -------
+ stcs : instance of SourceEstimate | list
+ The transformed stc or, in the case of transforms which yield
+ N-dimensional output (where N > 2), a list of stcs. For a list,
+ copy must be True.
+
+ Notes
+ -----
+ Applying transforms can be significantly faster if the
+ SourceEstimate object was created using "(kernel, sens_data)", for
+ the "data" parameter as the transform is applied in sensor space.
+ Inverse methods, e.g., "apply_inverse_epochs", or "lcmv_epochs" do
+ this automatically (if possible).
+ """
+
+ # min and max data indices to include
+ times = np.round(1000 * self.times)
+
+ if tmin is None:
+ tmin_idx = None
+ else:
+ tmin = float(tmin)
+ tmin_idx = np.where(times >= tmin)[0][0]
+
+ if tmax is None:
+ tmax_idx = None
+ else:
+ tmax = float(tmax)
+ tmax_idx = np.where(times <= tmax)[0][-1]
+
+ data_t = self.transform_data(func, fun_args=func_args, idx=idx,
+ tmin_idx=tmin_idx, tmax_idx=tmax_idx,
+ **kwargs)
+
+ # account for change in n_vertices
+ if idx is not None:
+ idx_lh = idx[idx < len(self.lh_vertno)]
+ idx_rh = idx[idx >= len(self.lh_vertno)] - len(self.lh_vertno)
+ verts_lh = self.lh_vertno[idx_lh]
+ verts_rh = self.rh_vertno[idx_rh]
+ else:
+ verts_lh = self.lh_vertno
+ verts_rh = self.rh_vertno
+ verts = [verts_lh, verts_rh]
+
+ tmin_idx = 0 if tmin_idx is None else tmin_idx
+ tmax_idx = -1 if tmax_idx is None else tmax_idx
+
+ tmin = self.times[tmin_idx]
+
+ times = np.arange(self.times[tmin_idx],
+ self.times[tmax_idx] + self.tstep / 2, self.tstep)
+
+ if data_t.ndim > 2:
+ # return list of stcs if transformed data has dimensionality > 2
+ if copy:
+ stcs = [SourceEstimate(data_t[:, :, a], verts, tmin,
+ self.tstep, self.subject)
+ for a in range(data_t.shape[-1])]
+ else:
+ raise ValueError('copy must be True if transformed data has '
+ 'more than 2 dimensions')
+ else:
+ # return new or overwritten stc
+ stcs = self if not copy else self.copy()
+ stcs._data, stcs.vertno = data_t, verts
+ stcs.tmin, stcs.times = tmin, times
+
+ return stcs
+
+ def as_data_frame(self, index=None, scale_time=1e3, copy=True):
+ """Represent source estimates as Pandas DataFrame
+
+ Export source estimates in tabular structure with vertices as columns
+ and two additional info columns 'subject' and 'time'.
+ This function is useful to visualize and analyse source time courses
+ with external statistical software such as statsmodels or R.
+
+ Parameters
+ ----------
+ index : tuple of str | None
+ Column to be used as index for the data. Valid string options
+ are 'subject' and 'time'. If None, both info
+ columns will be included in the table as categorial data.
+ If stc.subject is None, only time will be included.
+ scale_time : float
+ Scaling to be applied to time units.
+ copy : bool
+ If true, data will be copied. Else data may be modified in place.
+
+ Returns
+ -------
+ df : instance of DataFrame
+ Source estimates exported into tabular data structure.
+ """
+ pd = _check_pandas_installed()
+
+ default_index = ['subject', 'time']
+ if index is not None:
+ _check_pandas_index_arguments(index, default_index)
+ else:
+ index = default_index
+ if self.subject is None:
+ index.remove('subject')
+
+ data = self.data.T
+ shape = data.shape
+ mindex = list()
+ mindex.append(('time', self.times * scale_time))
+ mindex.append(('subject', np.repeat(self.subject, shape[0])))
+
+ if copy:
+ data = data.copy()
+ assert all(len(mdx) == len(mindex[0]) for mdx in mindex)
+
+ if isinstance(self.vertno, list):
+ # surface source estimates
+ v_names = [i for e in [['%s %i' % ('LH' if ii < 1 else 'RH', vert)
+ for vert in vertno]
+ for ii, vertno in enumerate(self.vertno)] for i in e]
+ else:
+ # volume source estimates
+ v_names = ['VOL %d' % vert for vert in self.vertno]
+
+ df = pd.DataFrame(data, columns=v_names)
+ [df.insert(i, k, v) for i, (k, v) in enumerate(mindex)]
+
+ if index is not None:
+ if 'time' in index:
+ df['time'] = df['time'].astype(np.int64)
+ with warnings.catch_warnings(True):
+ df.set_index(index, inplace=True)
+
+ return df
+
+
+class SourceEstimate(_BaseSourceEstimate):
+ """Container for surface source estimates
+
+ Parameters
+ ----------
+ data : array of shape (n_dipoles, n_times) | 2-tuple (kernel, sens_data)
+ The data in source space. The data can either be a single array or
+ a tuple with two arrays: "kernel" shape (n_vertices, n_sensors) and
+ "sens_data" shape (n_sensors, n_times). In this case, the source
+ space data corresponds to "numpy.dot(kernel, sens_data)".
+ vertices : list of two arrays
+ Vertex numbers corresponding to the data.
+ tmin : scalar
+ Time point of the first sample in data.
+ tstep : scalar
+ Time step between successive samples in data.
+ subject : str | None
+ The subject name. While not necessary, it is safer to set the
+ subject parameter to avoid analysis errors.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Attributes
+ ----------
+ subject : str | None
+ The subject name.
+ times : array of shape (n_times,)
+ The time vector.
+ vertno : list of two arrays of shape (n_dipoles,)
+ The indices of the dipoles in the left and right source space.
+ data : array of shape (n_dipoles, n_times)
+ The data in source space.
+ shape : tuple
+ The shape of the data. A tuple of int (n_dipoles, n_times).
+ """
+ @verbose
+ def __init__(self, data, vertices=None, tmin=None, tstep=None,
+ subject=None, verbose=None):
+
+ if not (isinstance(vertices, list) and len(vertices) == 2):
+ raise ValueError('Vertices, if a list, must contain two '
+ 'numpy arrays')
+
+ _BaseSourceEstimate.__init__(self, data, vertices=vertices, tmin=tmin,
+ tstep=tstep, subject=subject,
+ verbose=verbose)
+
+ @verbose
+ def save(self, fname, ftype='stc', verbose=None):
+ """Save the source estimates to a file
+
+ Parameters
+ ----------
+ fname : string
+ The stem of the file name. The file names used for surface source
+ spaces are obtained by adding "-lh.stc" and "-rh.stc" (or "-lh.w"
+ and "-rh.w") to the stem provided, for the left and the right
+ hemisphere, respectively.
+ ftype : string
+ File format to use. Allowed values are "stc" (default) and "w".
+ The "w" format only supports a single time point.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ Defaults to self.verbose.
+ """
+ if ftype not in ['stc', 'w']:
+ raise ValueError('ftype must be "stc" or "w", not "%s"' % ftype)
+
+ lh_data = self.data[:len(self.lh_vertno)]
+ rh_data = self.data[-len(self.rh_vertno):]
+
+ if ftype == 'stc':
+ logger.info('Writing STC to disk...')
+ _write_stc(fname + '-lh.stc', tmin=self.tmin, tstep=self.tstep,
+ vertices=self.lh_vertno, data=lh_data)
+ _write_stc(fname + '-rh.stc', tmin=self.tmin, tstep=self.tstep,
+ vertices=self.rh_vertno, data=rh_data)
+ elif ftype == 'w':
+ if self.shape[1] != 1:
+ raise ValueError('w files can only contain a single time '
+ 'point')
+ logger.info('Writing STC to disk (w format)...')
+ _write_w(fname + '-lh.w', vertices=self.lh_vertno,
+ data=lh_data[:, 0])
+ _write_w(fname + '-rh.w', vertices=self.rh_vertno,
+ data=rh_data[:, 0])
+
+ logger.info('[done]')
+
+ def __repr__(self):
+ if isinstance(self.vertno, list):
+ nv = sum([len(v) for v in self.vertno])
+ else:
+ nv = self.vertno.size
+ s = "%d vertices" % nv
+ if self.subject is not None:
+ s += ", subject : %s" % self.subject
+ s += ", tmin : %s (ms)" % (1e3 * self.tmin)
+ s += ", tmax : %s (ms)" % (1e3 * self.times[-1])
+ s += ", tstep : %s (ms)" % (1e3 * self.tstep)
+ s += ", data size : %s x %s" % self.shape
+ return "<SourceEstimate | %s>" % s
+
+ @property
+ def lh_data(self):
+ return self.data[:len(self.lh_vertno)]
+
+ @property
+ def rh_data(self):
+ return self.data[len(self.lh_vertno):]
- tmin = times[0] + width / 2.
- stc = SourceEstimate(data, vertices=self.vertno,
- tmin=tmin, tstep=width, subject=self.subject)
- return stc
+ @property
+ def lh_vertno(self):
+ return self.vertno[0]
+
+ @property
+ def rh_vertno(self):
+ return self.vertno[1]
def _hemilabel_stc(self, label):
- is_surface = self.is_surface()
- # find applicable SourceEstimate vertices
- if is_surface:
- if label.hemi == 'lh':
- stc_vertices = self.vertno[0]
- else:
- stc_vertices = self.vertno[1]
- else:
+ if label.hemi == 'lh':
stc_vertices = self.vertno[0]
+ else:
+ stc_vertices = self.vertno[1]
# find index of the Label's vertices
idx = np.nonzero(map(label.vertices.__contains__, stc_vertices))[0]
@@ -893,7 +1125,7 @@ class SourceEstimate(object):
vertices = stc_vertices[idx]
# find data
- if is_surface and (label.hemi == 'rh'):
+ if label.hemi == 'rh':
values = self.data[idx + len(self.vertno[0])]
else:
values = self.data[idx]
@@ -913,8 +1145,6 @@ class SourceEstimate(object):
does not match any sources in the SourceEstimate, a ValueError is
raised.
"""
- if not self.is_surface():
- raise NotImplementedError
# make sure label and stc are compatible
if label.subject is not None and self.subject is not None \
and label.subject != self.subject:
@@ -954,6 +1184,11 @@ class SourceEstimate(object):
----------
vertno : list of array
New vertices to add. Can also contain old values.
+
+ Returns
+ -------
+ stc : instance of SourceEstimate
+ The modified stc (note: method operates inplace).
"""
if not isinstance(vertno, list):
raise TypeError('vertno must be a list')
@@ -1029,87 +1264,6 @@ class SourceEstimate(object):
return label_tc
- def transform_data(self, transform_fun, fun_args=None,
- idx=None, tmin_idx=None, tmax_idx=None, **kwargs):
- """Get data after a linear (time) transform has been applied
-
- The transorm is applied to each source time course independently.
-
-
- Parameters
- ----------
- transform_fun : callable
- The transform to be applied. The first parameter of the function
- is the input data. The first return value is the transformed
- data, remaining outputs are ignored. The first dimension of the
- transformed data has to be the same as the first dimension of the
- input data.
- fun_args : tuple | None
- Additional parameters to be passed to transform_fun.
- idx : array | None
- Indicices of source time courses for which to compute transform.
- If None, all time courses are used.
- tmin_idx : int | None
- Index of first time point to include. If None, the index of the
- first time point is used.
- tmax_idx : int | None
- Index of the first time point not to include. If None, time points
- up to (and including) the last time point are included.
- **kwargs : dict
- Keyword arguments to be passed to transform_fun.
-
- Returns
- -------
- data_t : ndarray
- The transformed data.
-
- .. note::
- Applying transforms can be significantly faster if the
- SourceEstimate object was created using "(kernel, sens_data)", for
- the "data" parameter as the transform is applied in sensor space.
- Inverse methods, e.g., "apply_inverse_epochs", or "lcmv_epochs" do
- this automatically (if possible).
- """
-
- if idx is None:
- # use all time courses by default
- idx = slice(None, None)
-
- if fun_args is None:
- fun_args = tuple()
-
- if self._kernel is None and self._sens_data is None:
- # transform source space data directly
- data_t = transform_fun(self.data[idx, tmin_idx:tmax_idx],
- *fun_args, **kwargs)
-
- if isinstance(data_t, tuple):
- # use only first return value
- data_t = data_t[0]
- else:
- # apply transform in sensor space
- sens_data_t = transform_fun(self._sens_data[:, tmin_idx:tmax_idx],
- *fun_args, **kwargs)
-
- if isinstance(sens_data_t, tuple):
- # use only first return value
- sens_data_t = sens_data_t[0]
-
- # apply inverse
- data_shape = sens_data_t.shape
- if len(data_shape) > 2:
- # flatten the last dimensions
- sens_data_t = sens_data_t.reshape(data_shape[0],
- np.prod(data_shape[1:]))
-
- data_t = np.dot(self._kernel[idx, :], sens_data_t)
-
- # restore original shape if necessary
- if len(data_shape) > 2:
- data_t = data_t.reshape(data_t.shape[0], *data_shape[1:])
-
- return data_t
-
def center_of_mass(self, subject=None, hemi=None, restrict_vertices=False,
subjects_dir=None):
"""Return the vertex on a given surface that is at the center of mass
@@ -1158,9 +1312,6 @@ class SourceEstimate(object):
"""
subject = _check_subject(self.subject, subject)
- if not self.is_surface():
- raise ValueError('Finding COM must be done on surface')
-
values = np.sum(self.data, axis=1) # sum across time
vert_inds = [np.arange(len(self.vertno[0])),
np.arange(len(self.vertno[1])) + len(self.vertno[0])]
@@ -1210,7 +1361,8 @@ class SourceEstimate(object):
colormap='hot', time_label='time=%0.2f ms',
smoothing_steps=10, fmin=5., fmid=10., fmax=15.,
transparent=True, alpha=1.0, time_viewer=False,
- config_opts={}, subjects_dir=None, figure=None):
+ config_opts={}, subjects_dir=None, figure=None,
+ views='lat', colorbar=True):
"""Plot SourceEstimates with PySurfer
Note: PySurfer currently needs the SUBJECTS_DIR environment variable,
@@ -1231,9 +1383,9 @@ class SourceEstimate(object):
is None, the environment will be used.
surface : str
The type of surface (inflated, white etc.).
- hemi : str, 'lh' | 'rh' | 'both'
- The hemisphere to display. Using 'both' opens two separate figures,
- one for each hemisphere.
+ hemi : str, 'lh' | 'rh' | 'split' | 'both'
+ The hemisphere to display. Using 'both' or 'split' requires
+ PySurfer version 0.4 or above.
colormap : str
The type of colormap to use.
time_label : str
@@ -1261,20 +1413,23 @@ class SourceEstimate(object):
figure : instance of mayavi.core.scene.Scene | None
If None, the last figure will be cleaned and a new figure will
be created.
+ views : str | list
+ View to use. See surfer.Brain().
+ colorbar : bool
+ If True, display colorbar on scene.
Returns
-------
- brain : Brain | list of Brain
- A instance of surfer.viz.Brain from PySurfer For hemi='both',
- a list with Brain instances for the left and right hemisphere is
- returned.
+ brain : Brain
+ A instance of surfer.viz.Brain from PySurfer.
"""
brain = plot_source_estimates(self, subject, surface=surface,
hemi=hemi, colormap=colormap, time_label=time_label,
smoothing_steps=smoothing_steps, fmin=fmin, fmid=fmid,
fmax=fmax, transparent=transparent, alpha=alpha,
time_viewer=time_viewer, config_opts=config_opts,
- subjects_dir=subjects_dir, figure=figure)
+ subjects_dir=subjects_dir, figure=figure, views=views,
+ colorbar=colorbar)
return brain
@verbose
@@ -1350,144 +1505,157 @@ class SourceEstimate(object):
return morph_data_precomputed(subject_from, subject_to, self,
vertices_to, morph_mat)
- def as_data_frame(self, index=None, scale_time=1e3, copy=True):
- """Represent source estimates as Pandas DataFrame
-
- Export source estimates in tabular structure with vertices as columns
- and two additional info columns 'subject' and 'time'.
- This function is useful to visualize and analyse source time courses
- with external statistical software such as statsmodels or R.
-
- Parameters
- ----------
- index : tuple of str | None
- Column to be used as index for the data. Valid string options
- are 'subject' and 'time'. If None, all three info
- columns will be included in the table as categorial data.
- scale_time : float
- Scaling to be applied to time units.
- copy : bool
- If true, data will be copied. Else data may be modified in place.
-
- Returns
- -------
- df : instance of DataFrame
- Source estimates exported into tabular data structure.
- """
- pd = _check_pandas_installed()
- default_index = ['subject', 'time']
- if index is not None:
- _check_pandas_index_arguments(index, default_index)
- else:
- index = default_index
+class VolSourceEstimate(_BaseSourceEstimate):
+ """Container for volume source estimates
- data = self.data.T
- shape = data.shape
- mindex = list()
- mindex.append(('time', self.times * scale_time))
- mindex.append(('subject', np.repeat(self.subject, shape[0])))
+ Parameters
+ ----------
+ data : array of shape (n_dipoles, n_times) | 2-tuple (kernel, sens_data)
+ The data in source space. The data can either be a single array or
+ a tuple with two arrays: "kernel" shape (n_vertices, n_sensors) and
+ "sens_data" shape (n_sensors, n_times). In this case, the source
+ space data corresponds to "numpy.dot(kernel, sens_data)".
+ vertices : array
+ Vertex numbers corresponding to the data.
+ tmin : scalar
+ Time point of the first sample in data.
+ tstep : scalar
+ Time step between successive samples in data.
+ subject : str | None
+ The subject name. While not necessary, it is safer to set the
+ subject parameter to avoid analysis errors.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
- if copy:
- data = data.copy()
- assert all(len(mdx) == len(mindex[0]) for mdx in mindex)
+ Attributes
+ ----------
+ subject : str | None
+ The subject name.
+ times : array of shape (n_times,)
+ The time vector.
+ vertno : array of shape (n_dipoles,)
+ The indices of the dipoles in the source space.
+ data : array of shape (n_dipoles, n_times)
+ The data in source space.
+ shape : tuple
+ The shape of the data. A tuple of int (n_dipoles, n_times).
+ """
+ @verbose
+ def __init__(self, data, vertices=None, tmin=None, tstep=None,
+ subject=None, verbose=None):
- vert_names = [i for e in [['%s %i' % ('LH' if ii < 1 else 'RH', vert)
- for vert in vertno]
- for ii, vertno in enumerate(self.vertno)] for i in e]
- df = pd.DataFrame(data, columns=vert_names)
- [df.insert(i, k, v) for i, (k, v) in enumerate(mindex)]
+ if not (isinstance(vertices, np.ndarray) or isinstance(vertices, list)
+ and len(vertices) == 1):
+ raise ValueError('Vertices must be a numpy array or a list with '
+ 'one array')
- if index is not None:
- with warnings.catch_warnings(True):
- df.set_index(index, inplace=True)
- if 'time' in df.index.names and hasattr(df.index, 'levels'):
- df.index.levels[1] = df.index.levels[1].astype(int)
+ _BaseSourceEstimate.__init__(self, data, vertices=vertices, tmin=tmin,
+ tstep=tstep, subject=subject,
+ verbose=verbose)
- return df
+ @verbose
+ def save(self, fname, ftype='stc', verbose=None):
+ """Save the source estimates to a file
-###############################################################################
-# Morphing
+ Parameters
+ ----------
+ fname : string
+ The stem of the file name. The stem is extended with "-vl.stc"
+ or "-vl.w".
+ ftype : string
+ File format to use. Allowed values are "stc" (default) and "w".
+ The "w" format only supports a single time point.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ Defaults to self.verbose.
+ """
+ if ftype not in ['stc', 'w']:
+ raise ValueError('ftype must be "stc" or "w", not "%s"' % ftype)
-from .fiff.constants import FIFF
-from .fiff.tag import find_tag
-from .fiff.open import fiff_open
-from .fiff.tree import dir_tree_find
-from .surface import read_bem_surfaces
+ if ftype == 'stc':
+ logger.info('Writing STC to disk...')
+ if not (fname.endswith('-vl.stc')
+ or fname.endswith('-vol.stc')):
+ fname += '-vl.stc'
+ _write_stc(fname, tmin=self.tmin, tstep=self.tstep,
+ vertices=self.vertno, data=self.data)
+ elif ftype == 'w':
+ logger.info('Writing STC to disk (w format)...')
+ if not (fname.endswith('-vl.w')
+ or fname.endswith('-vol.w')):
+ fname += '-vl.w'
+ _write_w(fname, vertices=self.vertno, data=self.data)
+ logger.info('[done]')
- at verbose
-def read_morph_map(subject_from, subject_to, subjects_dir=None,
- verbose=None):
- """Read morph map generated with mne_make_morph_maps
+ def save_as_volume(self, fname, src, dest='mri', mri_resolution=False):
+ """Save a volume source estimate in a nifti file
- Parameters
- ----------
- subject_from : string
- Name of the original subject as named in the SUBJECTS_DIR.
- subject_to : string
- Name of the subject on which to morph as named in the SUBJECTS_DIR.
- subjects_dir : string
- Path to SUBJECTS_DIR is not set in the environment.
- verbose : bool, str, int, or None
- If not None, override default verbose level (see mne.verbose).
+ Parameters
+ ----------
+ fname : string
+ The name of the generated nifti file.
+ src : list
+ The list of source spaces (should actually be of length 1)
+ dest : 'mri' | 'surf'
+ If 'mri' the volume is defined in the coordinate system of
+ the original T1 image. If 'surf' the coordinate system
+ of the FreeSurfer surface is used (Surface RAS).
+ mri_resolution: bool
+ It True the image is saved in MRI resolution.
+ WARNING: if you have many time points the file produced can be
+ huge.
- Returns
- -------
- left_map, right_map : sparse matrix
- The morph maps for the 2 hemispheres.
- """
+ Returns
+ -------
+ img : instance Nifti1Image
+ The image object.
+ """
+ save_stc_as_volume(fname, self, src, dest=dest,
+ mri_resolution=mri_resolution)
- subjects_dir = get_subjects_dir(subjects_dir)
+ def as_volume(self, src, dest='mri', mri_resolution=False):
+ """Export volume source estimate as a nifti object
- # Does the file exist
- name = '%s/morph-maps/%s-%s-morph.fif' % (subjects_dir, subject_from,
- subject_to)
- if not os.path.exists(name):
- name = '%s/morph-maps/%s-%s-morph.fif' % (subjects_dir, subject_to,
- subject_from)
- if not os.path.exists(name):
- raise ValueError('The requested morph map does not exist\n' +
- 'Perhaps you need to run the MNE tool:\n' +
- ' mne_make_morph_maps --from %s --to %s'
- % (subject_from, subject_to))
-
- fid, tree, _ = fiff_open(name)
-
- # Locate all maps
- maps = dir_tree_find(tree, FIFF.FIFFB_MNE_MORPH_MAP)
- if len(maps) == 0:
- fid.close()
- raise ValueError('Morphing map data not found')
-
- # Find the correct ones
- left_map = None
- right_map = None
- for m in maps:
- tag = find_tag(fid, m, FIFF.FIFF_MNE_MORPH_MAP_FROM)
- if tag.data == subject_from:
- tag = find_tag(fid, m, FIFF.FIFF_MNE_MORPH_MAP_TO)
- if tag.data == subject_to:
- # Names match: which hemishere is this?
- tag = find_tag(fid, m, FIFF.FIFF_MNE_HEMI)
- if tag.data == FIFF.FIFFV_MNE_SURF_LEFT_HEMI:
- tag = find_tag(fid, m, FIFF.FIFF_MNE_MORPH_MAP)
- left_map = tag.data
- logger.info(' Left-hemisphere map read.')
- elif tag.data == FIFF.FIFFV_MNE_SURF_RIGHT_HEMI:
- tag = find_tag(fid, m, FIFF.FIFF_MNE_MORPH_MAP)
- right_map = tag.data
- logger.info(' Right-hemisphere map read.')
+ Parameters
+ ----------
+ src : list
+ The list of source spaces (should actually be of length 1)
+ dest : 'mri' | 'surf'
+ If 'mri' the volume is defined in the coordinate system of
+ the original T1 image. If 'surf' the coordinate system
+ of the FreeSurfer surface is used (Surface RAS).
+ mri_resolution: bool
+ It True the image is saved in MRI resolution.
+ WARNING: if you have many time points the file produced can be
+ huge.
- fid.close()
- if left_map is None:
- raise ValueError('Left hemisphere map not found in %s' % name)
+ Returns
+ -------
+ img : instance Nifti1Image
+ The image object.
+ """
+ return save_stc_as_volume(None, self, src, dest=dest,
+ mri_resolution=mri_resolution)
- if right_map is None:
- raise ValueError('Left hemisphere map not found in %s' % name)
+ def __repr__(self):
+ if isinstance(self.vertno, list):
+ nv = sum([len(v) for v in self.vertno])
+ else:
+ nv = self.vertno.size
+ s = "%d vertices" % nv
+ if self.subject is not None:
+ s += ", subject : %s" % self.subject
+ s += ", tmin : %s (ms)" % (1e3 * self.tmin)
+ s += ", tmax : %s (ms)" % (1e3 * self.times[-1])
+ s += ", tstep : %s (ms)" % (1e3 * self.tstep)
+ s += ", data size : %s x %s" % self.shape
+ return "<VolSourceEstimate | %s>" % s
- return left_map, right_map
+###############################################################################
+# Morphing
def mesh_edges(tris):
"""Returns sparse matrix with edges as an adjacency matrix
@@ -1575,6 +1743,9 @@ def _morph_buffer(data, idx_use, e, smooth, n_vertices, nearest, maps,
n_iter = 99 # max nb of smoothing iterations (minus one)
if smooth is not None:
+ if smooth <= 0:
+ raise ValueError('The number of smoothing operations ("smooth") '
+ 'has to be at least 1.')
smooth -= 1
# make sure we're in CSR format
e = e.tocsr()
@@ -1660,48 +1831,6 @@ def _morph_mult(data, e, use_sparse, idx_use_data, idx_use_out=None):
return data
-def _compute_nearest(xhs, rr, use_balltree=True):
- """Find nearest neighbors
-
- Note: The rows in xhs and rr must all be unit-length vectors, otherwise
- the result will be incorrect.
-
- Parameters
- ----------
- xhs : array, shape=(n_samples, n_dim)
- Points of data set.
- rr : array, shape=(n_query, n_dim)
- Points to find nearest neighbors for.
- use_balltree : bool
- Use fast BallTree based search from scikit-learn. If scikit-learn
- is not installed it will fall back to the slow brute force search.
-
- Returns
- -------
- nearest : array, shape=(n_query,)
- Index of nearest neighbor in xhs for every point in rr.
- """
- if use_balltree:
- try:
- from sklearn.neighbors import BallTree
- except ImportError:
- logger.info('Nearest-neighbor searches will be significantly '
- 'faster if scikit-learn is installed.')
- use_balltree = False
-
- if use_balltree:
- ball_tree = BallTree(xhs)
- nearest = ball_tree.query(rr, k=1, return_distance=False)[:, 0]
- else:
- nearest = np.zeros(len(rr), dtype=np.int)
- dr = 32
- for k in range(0, len(rr), dr):
- dots = np.dot(rr[k:k + dr], xhs.T)
- nearest[k:k + dr] = np.argmax(dots, axis=1)
-
- return nearest
-
-
def _get_subject_sphere_tris(subject, subjects_dir):
spheres = [os.path.join(subjects_dir, subject, 'surf',
xh + '.sphere.reg') for xh in ['lh', 'rh']]
@@ -1751,7 +1880,7 @@ def morph_data(subject_from, subject_to, stc_from, grade=5, smooth=None,
stc_to : SourceEstimate
Source estimate for the destination subject.
"""
- if not stc_from.is_surface():
+ if not isinstance(stc_from, SourceEstimate):
raise ValueError('Morphing is only possible with surface source '
'estimates')
@@ -1921,6 +2050,8 @@ def grade_to_vertices(subject, grade, subjects_dir=None, n_jobs=1,
for a in [lhs, rhs, ico['rr']]]
vertices = parallel(my_compute_nearest(xhs, rr)
for xhs in [lhs, rhs])
+ # Make sure the vertices are ordered
+ vertices = [np.sort(verts) for verts in vertices]
else: # potentially fill the surface
vertices = [np.arange(lhs.shape[0]), np.arange(rhs.shape[0])]
@@ -2245,10 +2376,7 @@ def _get_connectivity_from_edges(edges, n_times, verbose=None):
@verbose
def _get_ico_tris(grade, verbose=None, return_surf=False):
"""Get triangles for ico surface."""
- ico_file_name = os.path.join(os.path.dirname(__file__), 'data',
- 'icos.fif.gz')
- ico = read_bem_surfaces(ico_file_name, s_id=9000 + grade)
-
+ ico = _get_ico_surface(grade)
if not return_surf:
return ico['tris']
else:
@@ -2260,9 +2388,10 @@ def save_stc_as_volume(fname, stc, src, dest='mri', mri_resolution=False):
Parameters
----------
- fname : string
- The name of the generated nifti file.
- stc : instance of SourceEstimate
+ fname : string | None
+ The name of the generated nifti file. If None, the image is only
+ returned and not saved.
+ stc : instance of VolSourceEstimate
The source estimate
src : list
The list of source spaces (should actually be of length 1)
@@ -2280,7 +2409,7 @@ def save_stc_as_volume(fname, stc, src, dest='mri', mri_resolution=False):
img : instance Nifti1Image
The image object.
"""
- if stc.is_surface():
+ if not isinstance(stc, VolSourceEstimate):
raise Exception('Only volume source estimates can be saved as '
'volumes')
@@ -2326,7 +2455,8 @@ def save_stc_as_volume(fname, stc, src, dest='mri', mri_resolution=False):
header.set_xyzt_units('mm', 'msec')
header['pixdim'][4] = 1e3 * stc.tstep
img = nib.Nifti1Image(vol, affine, header=header)
- nib.save(img, fname)
+ if fname is not None:
+ nib.save(img, fname)
return img
diff --git a/mne/source_space.py b/mne/source_space.py
index 070ba6c..9b076e6 100644
--- a/mne/source_space.py
+++ b/mne/source_space.py
@@ -4,24 +4,33 @@
# License: BSD (3-clause)
import numpy as np
+import os
import os.path as op
from scipy import sparse, linalg
-
-import logging
-logger = logging.getLogger('mne')
+from copy import deepcopy
from .fiff.constants import FIFF
from .fiff.tree import dir_tree_find
from .fiff.tag import find_tag, read_tag
from .fiff.open import fiff_open
-from .fiff.write import start_block, end_block, write_int, \
- write_float_sparse_rcs, write_string, \
- write_float_matrix, write_int_matrix, \
- write_coord_trans, start_file, end_file, write_id
-from .surface import read_surface
-from .utils import get_subjects_dir, run_subprocess, has_freesurfer, \
- has_nibabel
-from . import verbose
+from .fiff.write import (start_block, end_block, write_int,
+ write_float_sparse_rcs, write_string,
+ write_float_matrix, write_int_matrix,
+ write_coord_trans, start_file, end_file, write_id)
+from .surface import (read_surface, _create_surf_spacing, _get_ico_surface,
+ _tessellate_sphere_surf, read_bem_surfaces,
+ _read_surface_geom, _normalize_vectors,
+ _complete_surface_info, _compute_nearest,
+ fast_cross_3d)
+from .source_estimate import mesh_dist
+from .utils import (get_subjects_dir, run_subprocess, has_freesurfer,
+ has_nibabel, logger, verbose, check_scipy_version)
+from .fixes import in1d, partial
+from .parallel import parallel_func, check_n_jobs
+from .transforms import (invert_transform, apply_trans, _print_coord_trans,
+ combine_transforms)
+if has_nibabel():
+ import nibabel as nib
class SourceSpaces(list):
@@ -66,6 +75,17 @@ class SourceSpaces(list):
ss_repr = ', '.join(ss_repr)
return "<SourceSpaces: [{ss}]>".format(ss=ss_repr)
+ def copy(self):
+ """Make a copy of the source spaces
+
+ Returns
+ -------
+ src : instance of SourceSpaces
+ The copied source spaces.
+ """
+ src = deepcopy(self)
+ return src
+
def save(self, fname):
"""Save the source spaces to a fif file
@@ -148,7 +168,7 @@ def read_source_spaces_from_tree(fid, tree, add_geom=False, verbose=None):
this = _read_one_source_space(fid, s)
logger.info(' [done]')
if add_geom:
- complete_source_space_info(this)
+ _complete_source_space_info(this)
src.append(this)
@@ -216,10 +236,12 @@ def _read_one_source_space(fid, this, verbose=None):
raise ValueError('Unknown source space type')
else:
src_type = int(tag.data)
- if src_type == 1:
+ if src_type == FIFF.FIFFV_MNE_SPACE_SURFACE:
res['type'] = 'surf'
- elif src_type == 2:
+ elif src_type == FIFF.FIFFV_MNE_SPACE_VOLUME:
res['type'] = 'vol'
+ elif src_type == FIFF.FIFFV_MNE_SPACE_DISCRETE:
+ res['type'] = 'discrete'
else:
raise ValueError('Unknown source space type (%d)' % src_type)
@@ -396,7 +418,7 @@ def _read_one_source_space(fid, this, verbose=None):
@verbose
-def complete_source_space_info(this, verbose=None):
+def _complete_source_space_info(this, verbose=None):
"""Add more info on surface
"""
# Main triangulation
@@ -406,7 +428,7 @@ def complete_source_space_info(this, verbose=None):
r2 = this['rr'][this['tris'][:, 1], :]
r3 = this['rr'][this['tris'][:, 2], :]
this['tri_cent'] = (r1 + r2 + r3) / 3.0
- this['tri_nn'] = np.cross((r2 - r1), (r3 - r1))
+ this['tri_nn'] = fast_cross_3d((r2 - r1), (r3 - r1))
size = np.sqrt(np.sum(this['tri_nn'] ** 2, axis=1))
this['tri_area'] = size / 2.0
this['tri_nn'] /= size[:, None]
@@ -419,7 +441,7 @@ def complete_source_space_info(this, verbose=None):
r2 = this['rr'][this['use_tris'][:, 1], :]
r3 = this['rr'][this['use_tris'][:, 2], :]
this['use_tri_cent'] = (r1 + r2 + r3) / 3.0
- this['use_tri_nn'] = np.cross((r2 - r1), (r3 - r1))
+ this['use_tri_nn'] = fast_cross_3d((r2 - r1), (r3 - r1))
this['use_tri_area'] = np.sqrt(np.sum(this['use_tri_nn'] ** 2, axis=1)
) / 2.0
logger.info('[done]')
@@ -501,7 +523,7 @@ def _get_vertno(src):
# Write routines
@verbose
-def write_source_spaces_to_fid(fid, src, verbose=None):
+def _write_source_spaces_to_fid(fid, src, verbose=None):
"""Write the source spaces to a FIF file
Parameters
@@ -552,7 +574,7 @@ def write_source_spaces(fname, src, verbose=None):
end_block(fid, FIFF.FIFFB_MNE_ENV)
- write_source_spaces_to_fid(fid, src, verbose)
+ _write_source_spaces_to_fid(fid, src, verbose)
end_block(fid, FIFF.FIFFB_MNE)
end_file(fid)
@@ -561,30 +583,63 @@ def write_source_spaces(fname, src, verbose=None):
def _write_one_source_space(fid, this, verbose=None):
"""Write one source space"""
if this['type'] == 'surf':
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_TYPE, 1)
+ src_type = FIFF.FIFFV_MNE_SPACE_SURFACE
elif this['type'] == 'vol':
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_TYPE, 2)
+ src_type = FIFF.FIFFV_MNE_SPACE_VOLUME
+ elif this['type'] == 'discrete':
+ src_type = FIFF.FIFFV_MNE_SPACE_DISCRETE
else:
- raise ValueError('Unknown source space type (%d)' % this['type'])
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_ID, this['id'])
+ raise ValueError('Unknown source space type (%s)' % this['type'])
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_TYPE, src_type)
+ if this['id'] >= 0:
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_ID, this['id'])
data = this.get('subject_his_id', None)
if data:
write_string(fid, FIFF.FIFF_SUBJ_HIS_ID, data)
write_int(fid, FIFF.FIFF_MNE_COORD_FRAME, this['coord_frame'])
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NPOINTS, this['np'])
+ write_float_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_POINTS, this['rr'])
+ write_float_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NORMALS, this['nn'])
+
+ # Which vertices are active
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_SELECTION, this['inuse'])
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NUSE, this['nuse'])
+
+ if this['ntri'] > 0:
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NTRI, this['ntri'])
+ write_int_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_TRIANGLES,
+ this['tris'] + 1)
+
+ if this['type'] != 'vol' and this['use_tris'] is not None:
+ # Use triangulation
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NUSE_TRI, this['nuse_tri'])
+ write_int_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_USE_TRIANGLES,
+ this['use_tris'] + 1)
+
if this['type'] == 'vol':
+ neighbor_vert = this.get('neighbor_vert', None)
+ if neighbor_vert is not None:
+ nneighbors = np.array([len(n) for n in neighbor_vert])
+ neighbors = np.concatenate(neighbor_vert)
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NNEIGHBORS, nneighbors)
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NEIGHBORS, neighbors)
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_VOXEL_DIMS, this['shape'])
write_coord_trans(fid, this['src_mri_t'])
+ write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_VOXEL_DIMS, this['shape'])
+
start_block(fid, FIFF.FIFFB_MNE_PARENT_MRI_FILE)
+ write_coord_trans(fid, this['mri_ras_t'])
write_coord_trans(fid, this['vox_mri_t'])
- write_coord_trans(fid, this['mri_ras_t'])
+ mri_volume_name = this.get('mri_volume_name', None)
+ if mri_volume_name is not None:
+ write_string(fid, FIFF.FIFF_MNE_FILE_NAME, mri_volume_name)
write_float_sparse_rcs(fid, FIFF.FIFF_MNE_SOURCE_SPACE_INTERPOLATOR,
- this['interpolator'])
+ this['interpolator'])
if 'mri_file' in this and this['mri_file'] is not None:
write_string(fid, FIFF.FIFF_MNE_SOURCE_SPACE_MRI_FILE,
@@ -596,30 +651,11 @@ def _write_one_source_space(fid, this, verbose=None):
end_block(fid, FIFF.FIFFB_MNE_PARENT_MRI_FILE)
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NPOINTS, this['np'])
- write_float_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_POINTS, this['rr'])
- write_float_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NORMALS, this['nn'])
-
- # Which vertices are active
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_SELECTION, this['inuse'])
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NUSE, this['nuse'])
-
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NTRI, this['ntri'])
- if this['ntri'] > 0:
- write_int_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_TRIANGLES,
- this['tris'] + 1)
-
- if this['type'] != 'vol' and this['use_tris'] is not None:
- # Use triangulation
- write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NUSE_TRI, this['nuse_tri'])
- write_int_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_USE_TRIANGLES,
- this['use_tris'] + 1)
-
# Patch-related information
if this['nearest'] is not None:
write_int(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NEAREST, this['nearest'])
write_float_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NEAREST_DIST,
- this['nearest_dist'])
+ this['nearest_dist'])
# Distances
if this['dist'] is not None:
@@ -631,6 +667,9 @@ def _write_one_source_space(fid, this, verbose=None):
this['dist_limit'])
+##############################################################################
+# Surface to MNI conversion
+
@verbose
def vertex_to_mni(vertices, hemis, subject, subjects_dir=None, mode=None,
verbose=None):
@@ -731,10 +770,9 @@ def _read_talxfm(subject, subjects_dir, mode=None, verbose=None):
# now get Norig and Torig
path = op.join(subjects_dir, subject, 'mri', 'orig.mgz')
- try:
- import nibabel as nib
+ if has_nibabel():
use_nibabel = True
- except ImportError:
+ else:
use_nibabel = False
if mode == 'nibabel':
raise ImportError('Tried to import nibabel but failed, try using '
@@ -764,3 +802,835 @@ def _read_talxfm(subject, subjects_dir, mode=None, verbose=None):
nt_orig.append(stdout.reshape(4, 4))
xfm = np.dot(xfm, np.dot(nt_orig[0], linalg.inv(nt_orig[1])))
return xfm
+
+
+###############################################################################
+# Creation and decimation
+
+ at verbose
+def setup_source_space(subject, fname=True, spacing='oct6', surface='white',
+ overwrite=False, subjects_dir=None, verbose=None):
+ """Setup a source space with subsampling
+
+ Parameters
+ ----------
+ subject : str
+ Subject to process.
+ fname : str | None | bool
+ Filename to use. If True, a default name will be used. If None,
+ the source space will not be saved (only returned).
+ spacing : str
+ The spacing to use. Can be ``'ico#'`` for a recursively subdivided
+ icosahedron, ``'oct#'`` for a recursively subdivided octahedron,
+ or ``'all'`` for all points.
+ surface : str
+ The surface to use.
+ overwrite: bool
+ If True, overwrite output file (if it exists).
+ subjects_dir : string, or None
+ Path to SUBJECTS_DIR if it is not set in the environment.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ src : list
+ The source space for each hemisphere.
+ """
+ cmd = ('setup_source_space(%s, fname=%s, spacing=%s, surface=%s, '
+ 'overwrite=%s, subjects_dir=%s, verbose=%s)'
+ % (subject, fname, spacing, surface, overwrite,
+ subjects_dir, verbose))
+ # check to make sure our parameters are good, parse 'spacing'
+ space_err = ('"spacing" must be a string with values '
+ '"ico#", "oct#", or "all", and "ico" and "oct"'
+ 'numbers must be integers')
+ if not isinstance(spacing, basestring) or len(spacing) < 3:
+ raise ValueError(space_err)
+ if spacing == 'all':
+ stype = 'all'
+ sval = ''
+ elif spacing[:3] == 'ico':
+ stype = 'ico'
+ sval = spacing[3:]
+ elif spacing[:3] == 'oct':
+ stype = 'oct'
+ sval = spacing[3:]
+ else:
+ raise ValueError(space_err)
+ try:
+ if stype in ['ico', 'oct']:
+ sval = int(sval)
+ elif stype == 'spacing': # spacing
+ sval = float(sval)
+ except:
+ raise ValueError(space_err)
+ subjects_dir = get_subjects_dir(subjects_dir)
+ surfs = [op.join(subjects_dir, subject, 'surf', hemi + surface)
+ for hemi in ['lh.', 'rh.']]
+ bem_dir = op.join(subjects_dir, subject, 'bem')
+
+ for surf, hemi in zip(surfs, ['LH', 'RH']):
+ if surf is not None and not op.isfile(surf):
+ raise IOError('Could not find the %s surface %s'
+ % (hemi, surf))
+
+ if not (fname is True or fname is None or isinstance(fname, basestring)):
+ raise ValueError('"fname" must be a string, True, or None')
+ if fname is True:
+ extra = '%s-%s' % (stype, sval) if sval != '' else stype
+ fname = op.join(bem_dir, '%s-%s-src.fif' % (subject, extra))
+ if fname is not None and op.isfile(fname) and overwrite is False:
+ raise IOError('file "%s" exists, use overwrite=True if you want '
+ 'to overwrite the file' % fname)
+
+ logger.info('Setting up the source space with the following parameters:\n')
+ logger.info('SUBJECTS_DIR = %s' % subjects_dir)
+ logger.info('Subject = %s' % subject)
+ logger.info('Surface = %s' % surface)
+ if stype == 'ico':
+ src_type_str = 'ico = %s' % sval
+ logger.info('Icosahedron subdivision grade %s\n' % sval)
+ elif stype == 'oct':
+ src_type_str = 'oct = %s' % sval
+ logger.info('Octahedron subdivision grade %s\n' % sval)
+ else:
+ src_type_str = 'all'
+ logger.info('Include all vertices\n')
+
+ # Create the fif file
+ if fname is not None:
+ logger.info('>>> 1. Creating the source space file %s...' % fname)
+ else:
+ logger.info('>>> 1. Creating the source space...\n')
+
+ # mne_make_source_space ... actually make the source spaces
+ src = []
+
+ # pre-load ico/oct surf (once) for speed, if necessary
+ if stype in ['ico', 'oct']:
+ ### from mne_ico_downsample.c ###
+ if stype == 'ico':
+ logger.info('Doing the icosahedral vertex picking...')
+ ico_surf = _get_ico_surface(sval)
+ else:
+ logger.info('Doing the octahedral vertex picking...')
+ ico_surf = _tessellate_sphere_surf(sval)
+ else:
+ ico_surf = None
+
+ for hemi, surf in zip(['lh', 'rh'], surfs):
+ logger.info('Loading %s...' % surf)
+ s = _create_surf_spacing(surf, hemi, subject, stype, sval, ico_surf,
+ subjects_dir)
+ logger.info('loaded %s %d/%d selected to source space (%s)'
+ % (op.split(surf)[1], s['nuse'], s['np'], src_type_str))
+ src.append(s)
+ logger.info('') # newline after both subject types are run
+
+ # Fill in source space info
+ hemi_ids = [FIFF.FIFFV_MNE_SURF_LEFT_HEMI, FIFF.FIFFV_MNE_SURF_RIGHT_HEMI]
+ for s, s_id in zip(src, hemi_ids):
+ # Add missing fields
+ s.update(dict(dist=None, dist_limit=None, nearest=None, type='surf',
+ nearest_dist=None, pinfo=None, patch_inds=None, id=s_id,
+ coord_frame=np.array((FIFF.FIFFV_COORD_MRI,), np.int32)))
+ s['rr'] /= 1000.0
+ del s['tri_area']
+ del s['tri_cent']
+ del s['tri_nn']
+ del s['neighbor_tri']
+
+ # upconvert to object format from lists
+ src = SourceSpaces(src, dict(working_dir=os.getcwd(), command_line=cmd))
+
+ # write out if requested, then return the data
+ if fname is not None:
+ write_source_spaces(fname, src)
+ logger.info('Wrote %s' % fname)
+ logger.info('You are now one step closer to computing the gain matrix')
+ return src
+
+
+ at verbose
+def setup_volume_source_space(subject, fname=None, pos=5.0, mri=None,
+ sphere=(0.0, 0.0, 0.0, 90.0), bem=None,
+ surface=None, mindist=5.0, exclude=0.0,
+ overwrite=False, subjects_dir=None,
+ verbose=None):
+ """Setup a volume source space with grid spacing or discrete source space
+
+ Parameters
+ ----------
+ subject : str
+ Subject to process.
+ fname : str | None
+ Filename to use. If None, the source space will not be saved
+ (only returned).
+ pos : float | dict
+ Positions to use for sources. If float, a grid will be constructed
+ with the spacing given by `pos` in mm, generating a volume source
+ space. If dict, pos['rr'] and pos['nn'] will be used as the source
+ space locations (in meters) and normals, respectively, creating a
+ discrete source space.
+ mri : str | None
+ The filename of an MRI volume (mgh or mgz) to create the
+ interpolation matrix over. Source estimates obtained in the
+ volume source space can then be morphed onto the MRI volume
+ using this interpolator. If pos is a dict, this can be None.
+ sphere : array_like (length 4)
+ Define spherical source space bounds using origin and radius given
+ by (ox, oy, oz, rad) in mm. Only used if `bem` and `surface` are
+ both None.
+ bem : str | None
+ Define source space bounds using a BEM file (specifically the inner
+ skull surface).
+ surface : str | dict | None
+ Define source space bounds using a FreeSurfer surface file. Can
+ also be a dictionary with entries `'rr'` and `'tris'`, such as
+ those returned by `read_surface()`.
+ mindist : float
+ Exclude points closer than this distance (mm) to the bounding surface.
+ exclude : float
+ Exclude points closer than this distance (mm) from the center of mass
+ of the bounding surface.
+ overwrite: bool
+ If True, overwrite output file (if it exists).
+ subjects_dir : string, or None
+ Path to SUBJECTS_DIR if it is not set in the environment.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ src : list
+ The source space. Note that this list will have length 1 for
+ compatibility reasons, as most functions expect source spaces
+ to be provided as lists).
+
+ Notes
+ -----
+ To create a discrete source space, `pos` must be a dict. To create a
+ volume source space, `pos` must be a float. Note that if a discrete
+ source space is created, then `mri` is optional (can be None), whereas
+ for a volume source space, `mri` must be provided.
+ """
+ if bem is not None and surface is not None:
+ raise ValueError('Only one of "bem" and "surface" should be '
+ 'specified')
+ if mri is not None:
+ if not op.isfile(mri):
+ raise IOError('mri file "%s" not found' % mri)
+ if not has_nibabel(vox2ras_tkr=True):
+ raise RuntimeError('nibabel with "vox2ras_tkr" property is '
+ 'required to process mri data, consider '
+ 'installing and/or updating nibabel')
+ elif not isinstance(pos, dict):
+ # "pos" will create a discrete src, so we don't need "mri"
+ # if "pos" is None, we must have "mri" b/c it will be vol src
+ raise RuntimeError('"mri" must be provided if "pos" is not a dict '
+ '(i.e., if a volume instead of discrete source '
+ 'space is desired)')
+
+ sphere = np.asarray(sphere)
+ if sphere.size != 4:
+ raise ValueError('"sphere" must be array_like with 4 elements')
+
+ # triage bounding argument
+ if bem is not None:
+ logger.info('BEM file : %s', bem)
+ elif surface is not None:
+ if isinstance(surface, dict):
+ if not all([key in surface for key in ['rr', 'tris']]):
+ raise KeyError('surface, if dict, must have entries "rr" '
+ 'and "tris"')
+ # let's make sure we have geom info
+ surface = _read_surface_geom(surface, verbose=False)
+ surf_extra = 'dict()'
+ elif isinstance(surface, basestring):
+ if not op.isfile(surface):
+ raise IOError('surface file "%s" not found' % surface)
+ surf_extra = surface
+ logger.info('Boundary surface file : %s', surf_extra)
+ else:
+ logger.info('Sphere : origin at (%.1f %.1f %.1f) mm'
+ % (sphere[0], sphere[1], sphere[2]))
+ logger.info(' radius : %.1f mm' % sphere[3])
+
+ # triage pos argument
+ if isinstance(pos, dict):
+ if not all([key in pos for key in ['rr', 'nn']]):
+ raise KeyError('pos, if dict, must contain "rr" and "nn"')
+ pos_extra = 'dict()'
+ else: # pos should be float-like
+ try:
+ pos = float(pos)
+ except (TypeError, ValueError):
+ raise ValueError('pos must be a dict, or something that can be '
+ 'cast to float()')
+ if not isinstance(pos, float):
+ logger.info('Source location file : %s', pos_extra)
+ logger.info('Assuming input in millimeters')
+ logger.info('Assuming input in MRI coordinates')
+
+ logger.info('Output file : %s', fname)
+ if isinstance(pos, float):
+ logger.info('grid : %.1f mm' % pos)
+ logger.info('mindist : %.1f mm' % mindist)
+ pos /= 1000.0
+ if exclude > 0.0:
+ logger.info('Exclude : %.1f mm' % exclude)
+ if mri is not None:
+ logger.info('MRI volume : %s' % mri)
+ exclude /= 1000.0
+ logger.info('')
+
+ # Explicit list of points
+ if not isinstance(pos, float):
+ # Make the grid of sources
+ sp = _make_discrete_source_space(pos)
+ else:
+ # Load the brain surface as a template
+ if bem is not None:
+ surf = read_bem_surfaces(bem, s_id=FIFF.FIFFV_BEM_SURF_ID_BRAIN,
+ verbose=False)
+ logger.info('Loaded inner skull from %s (%d nodes)'
+ % (bem, surf['np']))
+ elif surface is not None:
+ if isinstance(surf, basestring):
+ surf = _read_surface_geom(surface)
+ else:
+ surf = surface
+ logger.info('Loaded bounding surface from %s (%d nodes)'
+ % (surface, surf['np']))
+ else: # Load an icosahedron and use that as the surface
+ logger.info('Setting up the sphere...')
+ surf = _get_ico_surface(3)
+
+ # Scale and shift
+ _normalize_vectors(surf['rr'])
+ surf['rr'] *= sphere[3] / 1000.0 # scale by radius
+ surf['rr'] += sphere[:3] / 1000.0 # move by center
+ _complete_surface_info(surf, True)
+ # Make the grid of sources
+ sp = _make_volume_source_space(surf, pos, exclude, mindist)
+
+ # Compute an interpolation matrix to show data in an MRI volume
+ if mri is not None:
+ _add_interpolator(sp, mri)
+
+ if 'vol_dims' in sp:
+ del sp['vol_dims']
+
+ # Save it
+ sp.update(dict(nearest=None, dist=None, use_tris=None, patch_inds=None,
+ dist_limit=None, pinfo=None, ntri=0, nearest_dist=None,
+ nuse_tri=0, tris=None))
+ sp = SourceSpaces([sp], dict(working_dir=os.getcwd(), command_line='None'))
+ if fname is not None:
+ write_source_spaces(fname, sp, verbose=False)
+ return sp
+
+
+def _make_voxel_ras_trans(move, ras, voxel_size):
+ """Make a transformation for MRI voxel to MRI surface RAS"""
+ assert voxel_size.ndim == 1
+ assert voxel_size.size == 3
+ rot = ras.T * voxel_size[np.newaxis, :]
+ assert rot.ndim == 2
+ assert rot.shape[0] == 3
+ assert rot.shape[1] == 3
+ trans = np.c_[np.r_[rot, np.zeros((1, 3))], np.r_[move, 1.0]]
+ t = {'from': FIFF.FIFFV_MNE_COORD_MRI_VOXEL, 'to': FIFF.FIFFV_COORD_MRI,
+ 'trans': trans}
+ return t
+
+
+def _make_discrete_source_space(pos):
+ """Use a discrete set of source locs/oris to make src space
+
+ Parameters
+ ----------
+ pos : dict
+ Must have entries "rr" and "nn". Data should be in meters.
+
+ Returns
+ -------
+ src : dict
+ The source space.
+ """
+ # process points
+ rr = pos['rr'].copy()
+ nn = pos['nn'].copy()
+ if not (rr.ndim == nn.ndim == 2 and nn.shape[0] == nn.shape[0] and
+ rr.shape[1] == nn.shape[1]):
+ raise RuntimeError('"rr" and "nn" must both be 2D arrays with '
+ 'the same number of rows and 3 columns')
+ npts = rr.shape[0]
+ _normalize_vectors(nn)
+ nz = np.sum(np.sum(nn * nn, axis=1) == 0)
+ if nz != 0:
+ raise RuntimeError('%d sources have zero length normal' % nz)
+ logger.info('Positions (in meters) and orientations')
+ logger.info('%d sources' % npts)
+
+ # Ready to make the source space
+ coord_frame = FIFF.FIFFV_COORD_MRI
+ sp = dict(coord_frame=coord_frame, type='discrete', nuse=npts, np=npts,
+ inuse=np.ones(npts, int), vertno=np.arange(npts), rr=rr, nn=nn,
+ id=-1)
+ return sp
+
+
+def _make_volume_source_space(surf, grid, exclude, mindist):
+ """Make a source space which covers the volume bounded by surf"""
+
+ # Figure out the grid size
+ mins = np.min(surf['rr'], axis=0)
+ maxs = np.max(surf['rr'], axis=0)
+ cm = np.mean(surf['rr'], axis=0) # center of mass
+
+ # Define the sphere which fits the surface
+ maxdist = np.sqrt(np.max(np.sum((surf['rr'] - cm) ** 2, axis=1)))
+
+ logger.info('Surface CM = (%6.1f %6.1f %6.1f) mm'
+ % (1000 * cm[0], 1000 * cm[1], 1000 * cm[2]))
+ logger.info('Surface fits inside a sphere with radius %6.1f mm'
+ % (1000 * maxdist))
+ logger.info('Surface extent:')
+ for c, mi, ma in zip('xyz', mins, maxs):
+ logger.info(' %s = %6.1f ... %6.1f mm' % (c, 1000 * mi, 1000 * ma))
+ maxn = np.zeros(3, int)
+ minn = np.zeros(3, int)
+ for c in range(3):
+ if maxs[c] > 0:
+ maxn[c] = np.floor(np.abs(maxs[c]) / grid) + 1
+ else:
+ maxn[c] = -np.floor(np.abs(maxs[c]) / grid) - 1
+ if mins[c] > 0:
+ minn[c] = np.floor(np.abs(mins[c]) / grid) + 1
+ else:
+ minn[c] = -np.floor(np.abs(mins[c]) / grid) - 1
+
+ logger.info('Grid extent:')
+ for c, mi, ma in zip('xyz', minn, maxn):
+ logger.info(' %s = %6.1f ... %6.1f mm'
+ % (c, 1000 * mi * grid, 1000 * ma * grid))
+
+ # Now make the initial grid
+ ns = maxn - minn + 1
+ npts = np.prod(ns)
+ nrow = ns[0]
+ ncol = ns[1]
+ nplane = nrow * ncol
+ sp = dict(np=npts, rr=np.zeros((npts, 3)), nn=np.zeros((npts, 3)),
+ inuse=np.ones(npts, int), type='vol', nuse=npts,
+ coord_frame=FIFF.FIFFV_COORD_MRI, id=-1, shape=ns)
+ sp['nn'][:, 2] = 1.0 # Source orientation is immaterial
+
+ x = np.arange(minn[0], maxn[0] + 1)[np.newaxis, np.newaxis, :]
+ y = np.arange(minn[1], maxn[1] + 1)[np.newaxis, :, np.newaxis]
+ z = np.arange(minn[2], maxn[2] + 1)[:, np.newaxis, np.newaxis]
+ z = np.tile(z, (1, ns[1], ns[0])).ravel()
+ y = np.tile(y, (ns[2], 1, ns[0])).ravel()
+ x = np.tile(x, (ns[2], ns[1], 1)).ravel()
+ k = np.arange(npts)
+ sp['rr'] = np.c_[x, y, z] * grid
+ neigh = np.empty((26, npts), int)
+ neigh.fill(-1)
+
+ # Figure out each neighborhood:
+ # 6-neighborhood first
+ idxs = [z > minn[2], x < maxn[0], y < maxn[1],
+ x > minn[0], y > minn[1], z < maxn[2]]
+ offsets = [-nplane, 1, nrow, -1, -nrow, nplane]
+ for n, idx, offset in zip(neigh[:6], idxs, offsets):
+ n[idx] = k[idx] + offset
+
+ # Then the rest to complete the 26-neighborhood
+
+ # First the plane below
+ idx1 = z > minn[2]
+
+ idx2 = np.logical_and(idx1, x < maxn[0])
+ neigh[6, idx2] = k[idx2] + 1 - nplane
+ idx3 = np.logical_and(idx2, y < maxn[1])
+ neigh[7, idx3] = k[idx3] + 1 + nrow - nplane
+
+ idx2 = np.logical_and(idx1, y < maxn[1])
+ neigh[8, idx2] = k[idx2] + nrow - nplane
+
+ idx2 = np.logical_and(idx1, x > minn[0])
+ idx3 = np.logical_and(idx2, y < maxn[1])
+ neigh[9, idx3] = k[idx3] - 1 + nrow - nplane
+ neigh[10, idx2] = k[idx2] - 1 - nplane
+ idx3 = np.logical_and(idx2, y > minn[1])
+ neigh[11, idx3] = k[idx3] - 1 - nrow - nplane
+
+ idx2 = np.logical_and(idx1, y > minn[1])
+ neigh[12, idx2] = k[idx2] - nrow - nplane
+ idx3 = np.logical_and(idx2, x < maxn[0])
+ neigh[13, idx3] = k[idx3] + 1 - nrow - nplane
+
+ # Then the same plane
+ idx1 = np.logical_and(x < maxn[0], y < maxn[1])
+ neigh[14, idx1] = k[idx1] + 1 + nrow
+
+ idx1 = x > minn[0]
+ idx2 = np.logical_and(idx1, y < maxn[1])
+ neigh[15, idx2] = k[idx2] - 1 + nrow
+ idx2 = np.logical_and(idx1, y > minn[1])
+ neigh[16, idx2] = k[idx2] - 1 - nrow
+
+ idx1 = np.logical_and(y > minn[1], x < maxn[0])
+ neigh[17, idx1] = k[idx1] + 1 - nrow - nplane
+
+ # Finally one plane above
+ idx1 = z < maxn[2]
+
+ idx2 = np.logical_and(idx1, x < maxn[0])
+ neigh[18, idx2] = k[idx2] + 1 + nplane
+ idx3 = np.logical_and(idx2, y < maxn[1])
+ neigh[19, idx3] = k[idx3] + 1 + nrow + nplane
+
+ idx2 = np.logical_and(idx1, y < maxn[1])
+ neigh[20, idx2] = k[idx2] + nrow + nplane
+
+ idx2 = np.logical_and(idx1, x > minn[0])
+ idx3 = np.logical_and(idx2, y < maxn[1])
+ neigh[21, idx3] = k[idx3] - 1 + nrow + nplane
+ neigh[22, idx2] = k[idx2] - 1 + nplane
+ idx3 = np.logical_and(idx2, y > minn[1])
+ neigh[23, idx3] = k[idx3] - 1 - nrow + nplane
+
+ idx2 = np.logical_and(idx1, y > minn[1])
+ neigh[24, idx2] = k[idx2] - nrow + nplane
+ idx3 = np.logical_and(idx2, x < maxn[0])
+ neigh[25, idx3] = k[idx3] + 1 - nrow + nplane
+
+ logger.info('%d sources before omitting any.', sp['nuse'])
+
+ # Exclude infeasible points
+ dists = np.sqrt(np.sum((sp['rr'] - cm) ** 2, axis=1))
+ bads = np.where(np.logical_or(dists < exclude, dists > maxdist))[0]
+ sp['inuse'][bads] = False
+ sp['nuse'] -= len(bads)
+ logger.info('%d sources after omitting infeasible sources.', sp['nuse'])
+
+ _filter_source_spaces(surf, mindist, None, [sp])
+ logger.info('%d sources remaining after excluding the sources outside '
+ 'the surface and less than %6.1f mm inside.'
+ % (sp['nuse'], mindist))
+
+ # Omit unused vertices from the neighborhoods
+ logger.info('Adjusting the neighborhood info...')
+ # remove non source-space points
+ log_inuse = sp['inuse'] > 0
+ neigh[:, np.logical_not(log_inuse)] = -1
+ # remove these points from neigh
+ vertno = np.where(log_inuse)[0]
+ sp['vertno'] = vertno
+ old_shape = neigh.shape
+ neigh = neigh.ravel()
+ checks = np.where(neigh >= 0)[0]
+ removes = np.logical_not(in1d(checks, vertno))
+ neigh[checks[removes]] = -1
+ neigh.shape = old_shape
+ neigh = neigh.T
+ # Thought we would need this, but C code keeps -1 vertices, so we will:
+ #neigh = [n[n >= 0] for n in enumerate(neigh[vertno])]
+ sp['neighbor_vert'] = neigh
+
+ # Set up the volume data (needed for creating the interpolation matrix)
+ r0 = minn * grid
+ voxel_size = grid * np.ones(3)
+ ras = np.eye(3)
+ sp['src_mri_t'] = _make_voxel_ras_trans(r0, ras, voxel_size)
+ sp['vol_dims'] = maxn - minn + 1
+ sp['voxel_dims'] = voxel_size
+ return sp
+
+
+def _vol_vertex(width, height, jj, kk, pp):
+ return jj + width * kk + pp * (width * height)
+
+
+def _add_interpolator(s, mri_name):
+ """Compute a sparse matrix to interpolate the data into an MRI volume"""
+ # extract transformation information from mri
+ logger.info('Reading %s...' % mri_name)
+ mri_hdr = nib.load(mri_name).get_header()
+ mri_width, mri_height, mri_depth = mri_hdr.get_data_shape()
+ s.update(dict(mri_width=mri_width, mri_height=mri_height,
+ mri_depth=mri_depth))
+ trans = mri_hdr.get_vox2ras_tkr()
+ trans[:3, :] /= 1000.0
+ s['vox_mri_t'] = {'trans': trans, 'from': FIFF.FIFFV_MNE_COORD_MRI_VOXEL,
+ 'to': FIFF.FIFFV_COORD_MRI} # ras_tkr
+ trans = linalg.inv(np.dot(mri_hdr.get_vox2ras_tkr(),
+ mri_hdr.get_ras2vox()))
+ trans[:3, 3] /= 1000.0
+ s['mri_ras_t'] = {'trans': trans, 'from': FIFF.FIFFV_COORD_MRI,
+ 'to': FIFF.FIFFV_MNE_COORD_RAS} # ras
+
+ _print_coord_trans(s['src_mri_t'], 'Source space : ')
+ _print_coord_trans(s['vox_mri_t'], 'MRI volume : ')
+ _print_coord_trans(s['mri_ras_t'], 'MRI volume : ')
+ # Convert from destination to source volume coords
+ combo_trans = combine_transforms(s['vox_mri_t'],
+ invert_transform(s['src_mri_t']),
+ FIFF.FIFFV_MNE_COORD_MRI_VOXEL,
+ FIFF.FIFFV_MNE_COORD_MRI_VOXEL)
+ combo_trans['trans'] = combo_trans['trans'].astype(np.float32)
+
+ logger.info('Setting up interpolation...')
+ js = np.arange(mri_width, dtype=np.float32)
+ js = np.tile(js[np.newaxis, np.newaxis, :],
+ (mri_depth, mri_height, 1)).ravel()
+ ks = np.arange(mri_height, dtype=np.float32)
+ ks = np.tile(ks[np.newaxis, :, np.newaxis],
+ (mri_depth, 1, mri_width)).ravel()
+ ps = np.arange(mri_depth, dtype=np.float32)
+ ps = np.tile(ps[:, np.newaxis, np.newaxis],
+ (1, mri_height, mri_width)).ravel()
+
+ r0 = apply_trans(combo_trans['trans'], np.c_[js, ks, ps])
+ del js, ks, ps
+ rn = np.floor(r0).astype(int)
+ maxs = (s['vol_dims'] - 1)[np.newaxis, :]
+ good = np.logical_and(np.all(rn >= 0, axis=1), np.all(rn < maxs, axis=1))
+ rn = rn[good]
+ r0 = r0[good]
+ jj = rn[:, 0]
+ kk = rn[:, 1]
+ pp = rn[:, 2]
+ vss = np.empty((8, len(jj)), int)
+ width = s['vol_dims'][0]
+ height = s['vol_dims'][1]
+ vss[0, :] = _vol_vertex(width, height, jj, kk, pp)
+ vss[1, :] = _vol_vertex(width, height, jj + 1, kk, pp)
+ vss[2, :] = _vol_vertex(width, height, jj + 1, kk + 1, pp)
+ vss[3, :] = _vol_vertex(width, height, jj, kk + 1, pp)
+ vss[4, :] = _vol_vertex(width, height, jj, kk, pp + 1)
+ vss[5, :] = _vol_vertex(width, height, jj + 1, kk, pp + 1)
+ vss[6, :] = _vol_vertex(width, height, jj + 1, kk + 1, pp + 1)
+ vss[7, :] = _vol_vertex(width, height, jj, kk + 1, pp + 1)
+ del jj, kk, pp
+ uses = np.any(s['inuse'][vss], axis=0)
+
+ verts = vss[:, uses].ravel() # vertex (col) numbers in csr matrix
+ row_idx = np.tile(np.where(good)[0][uses], (8, 1)).ravel()
+
+ # figure out weights for each vertex
+ r0 = r0[uses]
+ rn = rn[uses]
+ xf = r0[:, 0] - rn[:, 0].astype(np.float32)
+ yf = r0[:, 1] - rn[:, 1].astype(np.float32)
+ zf = r0[:, 2] - rn[:, 2].astype(np.float32)
+ omxf = 1.0 - xf
+ omyf = 1.0 - yf
+ omzf = 1.0 - zf
+ weights = np.concatenate([omxf * omyf * omzf, # correspond to rows of vss
+ xf * omyf * omzf,
+ xf * yf * omzf,
+ omxf * yf * omzf,
+ omxf * omyf * zf,
+ xf * omyf * zf,
+ xf * yf * zf,
+ omxf * yf * zf])
+ del xf, yf, zf, omxf, omyf, omzf
+
+ # Compose the sparse matrix
+ ij = (row_idx, verts)
+ nvox = mri_width * mri_height * mri_depth
+ interp = sparse.csr_matrix((weights, ij), shape=(nvox, s['np']))
+ s['interpolator'] = interp
+ s['mri_volume_name'] = mri_name
+ logger.info(' %d/%d nonzero values [done]' % (len(weights), nvox))
+
+
+ at verbose
+def _filter_source_spaces(surf, limit, mri_head_t, src, n_jobs=1,
+ verbose=None):
+ """Remove all source space points closer than a given limit"""
+ if src[0]['coord_frame'] == FIFF.FIFFV_COORD_HEAD and mri_head_t is None:
+ raise RuntimeError('Source spaces are in head coordinates and no '
+ 'coordinate transform was provided!')
+
+ # How close are the source points to the surface?
+ out_str = 'Source spaces are in '
+
+ if src[0]['coord_frame'] == FIFF.FIFFV_COORD_HEAD:
+ inv_trans = invert_transform(mri_head_t)
+ out_str += 'head coordinates.'
+ elif src[0]['coord_frame'] == FIFF.FIFFV_COORD_MRI:
+ out_str += 'MRI coordinates.'
+ else:
+ out_str += 'unknown (%d) coordinates.' % src[0]['coord_frame']
+ logger.info(out_str)
+ out_str = 'Checking that the sources are inside the bounding surface'
+ if limit > 0.0:
+ out_str += ' and at least %6.1f mm away' % (limit)
+ logger.info(out_str + ' (will take a few...)')
+
+ for s in src:
+ vertno = np.where(s['inuse'])[0] # can't trust s['vertno'] this deep
+ # Convert all points here first to save time
+ r1s = s['rr'][vertno]
+ if s['coord_frame'] == FIFF.FIFFV_COORD_HEAD:
+ r1s = apply_trans(inv_trans['trans'], r1s)
+
+ # Check that the source is inside surface (often the inner skull)
+ x = _sum_solids_div(r1s, surf, n_jobs)
+ outside = np.abs(x - 1.0) > 1e-5
+ omit_outside = np.sum(outside)
+
+ # vectorized nearest using BallTree (or cdist)
+ omit = 0
+ if limit > 0.0:
+ dists = _compute_nearest(surf['rr'], r1s, return_dists=True)[1]
+ close = np.logical_and(dists < limit / 1000.0,
+ np.logical_not(outside))
+ omit = np.sum(close)
+ outside = np.logical_or(outside, close)
+ s['inuse'][vertno[outside]] = False
+ s['nuse'] -= (omit + omit_outside)
+ s['vertno'] = np.where(s['inuse'])[0]
+
+ if omit_outside > 0:
+ extras = [omit_outside]
+ extras += ['s', 'they are'] if omit_outside > 1 else ['', 'it is']
+ logger.info('%d source space point%s omitted because %s '
+ 'outside the inner skull surface.' % tuple(extras))
+ if omit > 0:
+ extras = [omit]
+ extras += ['s'] if omit_outside > 1 else ['']
+ extras += [limit]
+ logger.info('%d source space point%s omitted because of the '
+ '%6.1f-mm distance limit.' % tuple(extras))
+ logger.info('Thank you for waiting.')
+
+
+def _sum_solids_div(fros, surf, n_jobs):
+ """Compute sum of solid angles according to van Oosterom for all tris"""
+ parallel, p_fun, _ = parallel_func(_get_solids, n_jobs)
+ tot_angles = parallel(p_fun(surf['rr'][tris], fros)
+ for tris in np.array_split(surf['tris'], n_jobs))
+ return np.sum(tot_angles, axis=0) / (2 * np.pi)
+
+
+def _get_solids(tri_rrs, fros):
+ """Helper for computing _sum_solids_div total angle in chunks"""
+ # NOTE: This incorporates the division by 4PI that used to be separate
+ tot_angle = np.zeros((len(fros)))
+ for tri_rr in tri_rrs:
+ v1 = fros - tri_rr[0]
+ v2 = fros - tri_rr[1]
+ v3 = fros - tri_rr[2]
+ triple = np.sum(fast_cross_3d(v1, v2) * v3, axis=1)
+ l1 = np.sqrt(np.sum(v1 * v1, axis=1))
+ l2 = np.sqrt(np.sum(v2 * v2, axis=1))
+ l3 = np.sqrt(np.sum(v3 * v3, axis=1))
+ s = (l1 * l2 * l3 +
+ np.sum(v1 * v2, axis=1) * l3 +
+ np.sum(v1 * v3, axis=1) * l2 +
+ np.sum(v2 * v3, axis=1) * l1)
+ tot_angle -= np.arctan2(triple, s)
+ return tot_angle
+
+
+ at verbose
+def add_source_space_distances(src, dist_limit=np.inf, n_jobs=1, verbose=None):
+ """Compute inter-source distances along the cortical surface
+
+ Parameters
+ ----------
+ src : instance of SourceSpaces
+ The source spaces to compute distances for.
+ dist_limit : float
+ The upper limit of distances to include (in meters).
+ Note: if limit < np.inf, scipy > 0.13 (bleeding edge as of
+ 10/2013) must be installed.
+ n_jobs : int
+ Number of jobs to run in parallel. Will only use (up to) as many
+ cores as there are source spaces.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ src : instance of SourceSpaces
+ The original source spaces, with distance information added.
+ The distances are stored in src[n]['dist'].
+ Note: this function operates in-place.
+
+ Notes
+ -----
+ Requires scipy >= 0.11 (> 0.13 for `dist_limit < np.inf`).
+
+ This function can be memory- and CPU-intensive. On a high-end machine
+ (2012) running 6 jobs in parallel, an ico-5 (10242 per hemi) source space
+ takes about 10 minutes to compute all distances (`dist_limit = np.inf`).
+ With `dist_limit = 0.007`, computing distances takes about 1 minute.
+
+ We recommend computing distances once per source space and then saving
+ the source space to disk, as the computed distances will automatically be
+ stored along with the source space data for future use.
+ """
+ n_jobs = check_n_jobs(n_jobs)
+ if not isinstance(src, SourceSpaces):
+ raise ValueError('"src" must be an instance of SourceSpaces')
+ if not np.isscalar(dist_limit):
+ raise ValueError('limit must be a scalar')
+ if not check_scipy_version('0.11'):
+ raise RuntimeError('scipy >= 0.11 must be installed (or > 0.13 '
+ 'if dist_limit < np.inf')
+
+ if not all([s['type'] == 'surf' for s in src]):
+ raise RuntimeError('Currently all source spaces must be of surface '
+ 'type')
+
+ if dist_limit < np.inf:
+ # can't do introspection on dijkstra function because it's Cython,
+ # so we'll just try quickly here
+ try:
+ sparse.csgraph.dijkstra(sparse.csr_matrix(np.zeros((2, 2))),
+ limit=1.0)
+ except TypeError:
+ raise RuntimeError('Cannot use "limit < np.inf" unless scipy '
+ '> 0.13 is installed')
+
+ parallel, p_fun, _ = parallel_func(_do_src_distances, n_jobs)
+ for s in src:
+ connectivity = mesh_dist(s['tris'], s['rr'])
+ d = parallel(p_fun(connectivity, s['vertno'], r, dist_limit)
+ for r in np.array_split(np.arange(len(s['vertno'])),
+ n_jobs))
+ d = np.concatenate(d, axis=0)
+ # convert to sparse representation
+ i, j = np.meshgrid(s['vertno'], s['vertno'])
+ d = d.ravel()
+ i = i.ravel()
+ j = j.ravel()
+ idx = d > 0
+ d = sparse.csr_matrix((d[idx], (i[idx], j[idx])),
+ shape=(s['np'], s['np']), dtype=np.float32)
+ s['dist'] = d
+ s['dist_limit'] = np.array([dist_limit], np.float32)
+ return src
+
+
+def _do_src_distances(con, vertno, run_inds, limit):
+ """Helper to compute source space distances in chunks"""
+ if limit < np.inf:
+ func = partial(sparse.csgraph.dijkstra, limit=limit)
+ else:
+ func = sparse.csgraph.dijkstra
+ chunk_size = 100 # save memory by chunking (only a little slower)
+ lims = np.r_[np.arange(0, len(run_inds), chunk_size), len(run_inds)]
+ d = np.empty((len(run_inds), len(vertno)))
+ for l1, l2 in zip(lims[:-1], lims[1:]):
+ idx = vertno[run_inds[l1:l2]]
+ d[l1:l2] = func(con, indices=idx)[:, vertno]
+ d[d == np.inf] = 0 # scipy will give us np.inf for uncalc. distances
+ return d
diff --git a/mne/stats/__init__.py b/mne/stats/__init__.py
index 08f4323..17fb8a9 100644
--- a/mne/stats/__init__.py
+++ b/mne/stats/__init__.py
@@ -2,11 +2,11 @@
from .parametric import f_threshold_twoway_rm, f_twoway_rm
from .permutations import permutation_t_test
-from .cluster_level import permutation_cluster_test, \
- permutation_cluster_1samp_test, \
- spatio_temporal_cluster_1samp_test, \
- spatio_temporal_cluster_test, \
- _st_mask_from_s_inds, \
- ttest_1samp_no_p,\
- summarize_clusters_stc
+from .cluster_level import (permutation_cluster_test,
+ permutation_cluster_1samp_test,
+ spatio_temporal_cluster_1samp_test,
+ spatio_temporal_cluster_test,
+ _st_mask_from_s_inds,
+ ttest_1samp_no_p,
+ summarize_clusters_stc)
from .multi_comp import fdr_correction, bonferroni_correction
diff --git a/mne/stats/cluster_level.py b/mne/stats/cluster_level.py
index 5ed2776..9cb5c95 100755
--- a/mne/stats/cluster_level.py
+++ b/mne/stats/cluster_level.py
@@ -13,15 +13,11 @@ import numpy as np
from scipy import stats, sparse, ndimage
import warnings
-import logging
-logger = logging.getLogger('mne')
-
from .parametric import f_oneway
from ..parallel import parallel_func, check_n_jobs
-from ..utils import split_list
+from ..utils import split_list, logger, verbose
from ..fixes import in1d, unravel_index
-from .. import SourceEstimate
-from .. import verbose
+from ..source_estimate import SourceEstimate
def _get_clusters_spatial(s, neighbors):
@@ -123,11 +119,12 @@ def _get_clusters_st_multistep(keepers, neighbors, max_step=1):
compared to with the square for the standard (graph) algorithm."""
n_src = len(neighbors)
n_times = len(keepers)
- t_border = [0]
+ t_border = list()
+ t_border.append(0)
for ki, k in enumerate(keepers):
keepers[ki] = k + ki * n_src
- t_border += [t_border[ki] + len(k)]
- t_border = np.array(t_border)[:, np.newaxis]
+ t_border.append(t_border[ki] + len(k))
+ t_border = np.array(t_border)
keepers = np.concatenate(keepers)
v = keepers
t, s = divmod(v, n_src)
@@ -180,8 +177,8 @@ def _get_clusters_st(x_in, neighbors, max_step=1):
keepers = [np.array([], dtype=int)] * n_times
row, col = unravel_index(cl_goods, (n_times, n_src))
if isinstance(row, int):
- row = [row]
- col = [col]
+ row = [row]
+ col = [col]
lims = [0]
else:
order = np.argsort(row)
@@ -189,7 +186,7 @@ def _get_clusters_st(x_in, neighbors, max_step=1):
col = col[order]
lims = [0] + (np.where(np.diff(row) > 0)[0]
+ 1).tolist() + [len(row)]
-
+
for start, end in zip(lims[:-1], lims[1:]):
keepers[row[start]] = np.sort(col[start:end])
if max_step == 1:
@@ -205,15 +202,19 @@ def _get_components(x_in, connectivity, return_list=True):
"""get connected components from a mask and a connectivity matrix"""
try:
from sklearn.utils._csgraph import cs_graph_components
- except:
+ except ImportError:
try:
from scikits.learn.utils._csgraph import cs_graph_components
- except:
- # in theory we might be able to shoehorn this into using
- # _get_clusters_spatial if we transform connectivity into
- # a neighbor list, and it might end up being faster anyway,
- # but for now:
- raise ValueError('scikits-learn must be installed')
+ except ImportError:
+ try:
+ from sklearn.utils.sparsetools import connected_components
+ cs_graph_components = connected_components
+ except ImportError:
+ # in theory we might be able to shoehorn this into using
+ # _get_clusters_spatial if we transform connectivity into
+ # a neighbor list, and it might end up being faster anyway,
+ # but for now:
+ raise ImportError('scikit-learn must be installed')
mask = np.logical_and(x_in[connectivity.row], x_in[connectivity.col])
data = connectivity.data[mask]
@@ -378,6 +379,8 @@ def _find_clusters(x, threshold, tail=0, connectivity=None, max_step=1,
# triage based on cluster storage type
if isinstance(c, slice):
len_c = c.stop - c.start
+ elif isinstance(c, tuple):
+ len_c = len(c)
elif c.dtype == bool:
len_c = np.sum(c)
else:
@@ -523,13 +526,21 @@ def _setup_connectivity(connectivity, n_vertices, n_times):
def _do_permutations(X_full, slices, threshold, tail, connectivity, stat_fun,
max_step, include, partitions, t_power, seeds,
- sample_shape):
+ sample_shape, buffer_size):
+
+ n_samp, n_vars = X_full.shape
- n_samp = X_full.shape[0]
+ if buffer_size is not None and n_vars <= buffer_size:
+ buffer_size = None # don't use buffer for few variables
# allocate space for output
max_cluster_sums = np.empty(len(seeds), dtype=np.double)
+ if buffer_size is not None:
+ # allocate buffer, so we don't need to allocate memory during loop
+ X_buffer = [np.empty((len(X_full[s]), buffer_size), dtype=X_full.dtype)
+ for s in slices]
+
for seed_idx, seed in enumerate(seeds):
# shuffle sample indices
rng = np.random.RandomState(seed)
@@ -537,9 +548,26 @@ def _do_permutations(X_full, slices, threshold, tail, connectivity, stat_fun,
rng.shuffle(idx_shuffled)
idx_shuffle_list = [idx_shuffled[s] for s in slices]
- # shuffle all data at once
- X_shuffle_list = [X_full[idx, :] for idx in idx_shuffle_list]
- T_obs_surr = stat_fun(*X_shuffle_list)
+ if buffer_size is None:
+ # shuffle all data at once
+ X_shuffle_list = [X_full[idx, :] for idx in idx_shuffle_list]
+ T_obs_surr = stat_fun(*X_shuffle_list)
+ else:
+ # only shuffle a small data buffer, so we need less memory
+ T_obs_surr = np.empty(n_vars, dtype=X_full.dtype)
+
+ for pos in xrange(0, n_vars, buffer_size):
+ # number of variables for this loop
+ n_var_loop = min(pos + buffer_size, n_vars) - pos
+
+ # fill buffer
+ for i, idx in enumerate(idx_shuffle_list):
+ X_buffer[i][:, :n_var_loop] =\
+ X_full[idx, pos: pos + n_var_loop]
+
+ # apply stat_fun and store result
+ tmp = stat_fun(*X_buffer)
+ T_obs_surr[pos: pos + n_var_loop] = tmp[:n_var_loop]
# The stat should have the same shape as the samples for no conn.
if connectivity is None:
@@ -562,13 +590,20 @@ def _do_permutations(X_full, slices, threshold, tail, connectivity, stat_fun,
def _do_1samp_permutations(X, slices, threshold, tail, connectivity, stat_fun,
max_step, include, partitions, t_power, seeds,
- sample_shape):
- n_samp = X.shape[0]
+ sample_shape, buffer_size):
+ n_samp, n_vars = X.shape
assert slices is None # should be None for the 1 sample case
+ if buffer_size is not None and n_vars <= buffer_size:
+ buffer_size = None # don't use buffer for few variables
+
# allocate space for output
max_cluster_sums = np.empty(len(seeds), dtype=np.double)
+ if buffer_size is not None:
+ # allocate a buffer so we don't need to allocate memory in loop
+ X_flip_buffer = np.empty((n_samp, buffer_size), dtype=X.dtype)
+
for seed_idx, seed in enumerate(seeds):
if isinstance(seed, np.ndarray):
# new surrogate data with specified sign flip
@@ -583,13 +618,26 @@ def _do_1samp_permutations(X, slices, threshold, tail, connectivity, stat_fun,
signs = np.sign(0.5 - rng.rand(n_samp))
signs = signs[:, np.newaxis]
- X *= signs
+ if buffer_size is None:
+ X *= signs
+ # Recompute statistic on randomized data
+ T_obs_surr = stat_fun(X)
+ # Set X back to previous state (trade memory eff. for CPU use)
+ X *= signs
+ else:
+ # only sign-flip a small data buffer, so we need less memory
+ T_obs_surr = np.empty(n_vars, dtype=X.dtype)
- # Recompute statistic on randomized data
- T_obs_surr = stat_fun(X)
+ for pos in xrange(0, n_vars, buffer_size):
+ # number of variables for this loop
+ n_var_loop = min(pos + buffer_size, n_vars) - pos
- # Set X back to previous state (trade memory efficiency for CPU use)
- X *= signs
+ X_flip_buffer[:, :n_var_loop] =\
+ signs * X[:, pos: pos + n_var_loop]
+
+ # apply stat_fun and store result
+ tmp = stat_fun(X_flip_buffer)
+ T_obs_surr[pos: pos + n_var_loop] = tmp[:n_var_loop]
# The stat should have the same shape as the samples for no conn.
if connectivity is None:
@@ -615,7 +663,7 @@ def _do_1samp_permutations(X, slices, threshold, tail, connectivity, stat_fun,
def _permutation_cluster_test(X, threshold, n_permutations, tail, stat_fun,
connectivity, verbose, n_jobs, seed, max_step,
exclude, step_down_p, t_power, out_type,
- check_disjoint):
+ check_disjoint, buffer_size):
n_jobs = check_n_jobs(n_jobs)
""" Aux Function
@@ -652,6 +700,18 @@ def _permutation_cluster_test(X, threshold, n_permutations, tail, stat_fun,
T_obs = stat_fun(*X)
logger.info('stat_fun(H1): min=%f max=%f' % (np.min(T_obs), np.max(T_obs)))
+ # test if stat_fun treats variables independently
+ if buffer_size is not None:
+ T_obs_buffer = np.zeros_like(T_obs)
+ for pos in xrange(0, n_tests, buffer_size):
+ T_obs_buffer[pos: pos + buffer_size] =\
+ stat_fun(*[x[:, pos: pos + buffer_size] for x in X])
+
+ if not np.alltrue(T_obs == T_obs_buffer):
+ logger.warn('Provided stat_fun does not treat variables '
+ 'independently. Setting buffer_size to None.')
+ buffer_size = None
+
# The stat should have the same shape as the samples for no conn.
if connectivity is None:
T_obs.shape = sample_shape
@@ -741,7 +801,7 @@ def _permutation_cluster_test(X, threshold, n_permutations, tail, stat_fun,
this_include = step_down_include
H0 = parallel(my_do_perm_func(X_full, slices, threshold, tail,
connectivity, stat_fun, max_step, this_include,
- partitions, t_power, s, sample_shape)
+ partitions, t_power, s, sample_shape, buffer_size)
for s in split_list(seeds, n_jobs))
H0 = np.concatenate(H0)
cluster_pv = _pval_from_histogram(cluster_stats, H0, tail)
@@ -825,7 +885,7 @@ def permutation_cluster_test(X, threshold=None, n_permutations=1024,
connectivity=None, verbose=None, n_jobs=1,
seed=None, max_step=1, exclude=None,
step_down_p=0, t_power=1, out_type='mask',
- check_disjoint=False):
+ check_disjoint=False, buffer_size=1000):
"""Cluster-level statistical permutation test
For a list of 2d-arrays of data, e.g. power values, calculate some
@@ -894,6 +954,13 @@ def permutation_cluster_test(X, threshold=None, n_permutations=1024,
determine of it can be separated into disjoint sets. In some cases
(usually with connectivity as a list and many "time" points), this
can lead to faster clustering, but results should be identical.
+ buffer_size: int or None
+ The statistics will be computed for blocks of variables of size
+ "buffer_size" at a time. This is option significantly reduces the
+ memory requirements when n_jobs > 1 and memory sharing between
+ processes is enabled (see set_cache_dir()), as X will be shared
+ between processes and each process only needs to allocate space
+ for a small block of variables.
Returns
-------
@@ -930,7 +997,7 @@ def permutation_cluster_test(X, threshold=None, n_permutations=1024,
n_jobs=n_jobs, seed=seed, max_step=max_step,
exclude=exclude, step_down_p=step_down_p,
t_power=t_power, out_type=out_type,
- check_disjoint=check_disjoint)
+ check_disjoint=check_disjoint, buffer_size=buffer_size)
permutation_cluster_test.__test__ = False
@@ -942,7 +1009,7 @@ def permutation_cluster_1samp_test(X, threshold=None, n_permutations=1024,
connectivity=None, verbose=None, n_jobs=1,
seed=None, max_step=1, exclude=None,
step_down_p=0, t_power=1, out_type='mask',
- check_disjoint=False):
+ check_disjoint=False, buffer_size=1000):
"""Non-parametric cluster-level 1 sample T-test
From a array of observations, e.g. signal amplitudes or power spectrum
@@ -1018,6 +1085,13 @@ def permutation_cluster_1samp_test(X, threshold=None, n_permutations=1024,
determine of it can be separated into disjoint sets. In some cases
(usually with connectivity as a list and many "time" points), this
can lead to faster clustering, but results should be identical.
+ buffer_size: int or None
+ The statistics will be computed for blocks of variables of size
+ "buffer_size" at a time. This is option significantly reduces the
+ memory requirements when n_jobs > 1 and memory sharing between
+ processes is enabled (see set_cache_dir()), as X will be shared
+ between processes and each process only needs to allocate space
+ for a small block of variables.
Returns
-------
@@ -1054,7 +1128,7 @@ def permutation_cluster_1samp_test(X, threshold=None, n_permutations=1024,
n_jobs=n_jobs, seed=seed, max_step=max_step,
exclude=exclude, step_down_p=step_down_p,
t_power=t_power, out_type=out_type,
- check_disjoint=check_disjoint)
+ check_disjoint=check_disjoint, buffer_size=buffer_size)
permutation_cluster_1samp_test.__test__ = False
@@ -1065,7 +1139,7 @@ def spatio_temporal_cluster_1samp_test(X, threshold=None,
n_permutations=1024, tail=0, stat_fun=ttest_1samp_no_p,
connectivity=None, verbose=None, n_jobs=1, seed=None, max_step=1,
spatial_exclude=None, step_down_p=0, t_power=1, out_type='indices',
- check_disjoint=False):
+ check_disjoint=False, buffer_size=1000):
"""Non-parametric cluster-level 1 sample T-test for spatio-temporal data
This function provides a convenient wrapper for data organized in the form
@@ -1134,6 +1208,13 @@ def spatio_temporal_cluster_1samp_test(X, threshold=None,
determine of it can be separated into disjoint sets. In some cases
(usually with connectivity as a list and many "time" points), this
can lead to faster clustering, but results should be identical.
+ buffer_size: int or None
+ The statistics will be computed for blocks of variables of size
+ "buffer_size" at a time. This is option significantly reduces the
+ memory requirements when n_jobs > 1 and memory sharing between
+ processes is enabled (see set_cache_dir()), as X will be shared
+ between processes and each process only needs to allocate space
+ for a small block of variables.
Returns
-------
@@ -1175,7 +1256,7 @@ def spatio_temporal_cluster_1samp_test(X, threshold=None,
connectivity=connectivity, n_jobs=n_jobs, seed=seed,
max_step=max_step, exclude=exclude, step_down_p=step_down_p,
t_power=t_power, out_type=out_type,
- check_disjoint=check_disjoint)
+ check_disjoint=check_disjoint, buffer_size=buffer_size)
return out
@@ -1187,7 +1268,7 @@ def spatio_temporal_cluster_test(X, threshold=1.67,
n_permutations=1024, tail=0, stat_fun=f_oneway,
connectivity=None, verbose=None, n_jobs=1, seed=None, max_step=1,
spatial_exclude=None, step_down_p=0, t_power=1, out_type='indices',
- check_disjoint=False):
+ check_disjoint=False, buffer_size=1000):
"""Non-parametric cluster-level test for spatio-temporal data
This function provides a convenient wrapper for data organized in the form
@@ -1245,6 +1326,13 @@ def spatio_temporal_cluster_test(X, threshold=1.67,
determine of it can be separated into disjoint sets. In some cases
(usually with connectivity as a list and many "time" points), this
can lead to faster clustering, but results should be identical.
+ buffer_size: int or None
+ The statistics will be computed for blocks of variables of size
+ "buffer_size" at a time. This is option significantly reduces the
+ memory requirements when n_jobs > 1 and memory sharing between
+ processes is enabled (see set_cache_dir()), as X will be shared
+ between processes and each process only needs to allocate space
+ for a small block of variables.
Returns
-------
@@ -1281,7 +1369,7 @@ def spatio_temporal_cluster_test(X, threshold=1.67,
connectivity=connectivity, n_jobs=n_jobs, seed=seed,
max_step=max_step, exclude=exclude, step_down_p=step_down_p,
t_power=t_power, out_type=out_type,
- check_disjoint=check_disjoint)
+ check_disjoint=check_disjoint, buffer_size=buffer_size)
return out
@@ -1408,7 +1496,7 @@ def summarize_clusters_stc(clu, p_thresh=0.05, tstep=1e-3, tmin=0,
data_summary[:, 0] = np.sum(data_summary, axis=1)
return SourceEstimate(data_summary, vertno, tmin=tmin, tstep=tstep,
- subject=subject)
+ subject=subject)
else:
raise RuntimeError('No significant clusters available. Please adjust '
'your threshold or check your statistical analysis.')
diff --git a/mne/stats/parametric.py b/mne/stats/parametric.py
index 943ab35..ff25374 100644
--- a/mne/stats/parametric.py
+++ b/mne/stats/parametric.py
@@ -110,15 +110,28 @@ def _check_effects(effects):
def _iter_contrasts(n_subjects, factor_levels, effect_picks):
- """ Aux Function """
- sc, sy, = [], [] # setup contrasts
+ """ Aux Function: Setup contrasts """
+ sc, sy, = [], []
+
+ # prepare computation of Kronecker products
for n_levels in factor_levels:
+ # for each factor append
+ # 1) column vector of length == number of levels,
+ # 2) square matrix with diagonal == number of levels
+
+ # main + interaction effects for contrasts
sc.append([np.ones([n_levels, 1]),
- detrend(np.eye(n_levels), type='constant')])
+ detrend(np.eye(n_levels), type='constant')])
+ # main + interaction effects for component means
sy.append([np.ones([n_levels, 1]) / n_levels, np.eye(n_levels)])
+ # XXX component means not returned at the moment
for (c1, c2, c3) in defaults_twoway_rm['iter_contrasts'][effect_picks]:
+ # c1 selects the first factors' level in the column vector
+ # c3 selects the actual factor
+ # c2 selects either its column vector or diag matrix
c_ = np.kron(sc[0][c1], sc[c3][c2])
+ # for 3 way anova accumulation of c_ across factors required
df1 = matrix_rank(c_)
df2 = df1 * (n_subjects - 1)
yield c_, df1, df2
diff --git a/mne/stats/tests/test_cluster_level.py b/mne/stats/tests/test_cluster_level.py
index 823b955..90ee37a 100644
--- a/mne/stats/tests/test_cluster_level.py
+++ b/mne/stats/tests/test_cluster_level.py
@@ -1,91 +1,120 @@
import numpy as np
-from numpy.testing import assert_equal, assert_array_equal,\
- assert_array_almost_equal
+from numpy.testing import (assert_equal, assert_array_equal,
+ assert_array_almost_equal)
from nose.tools import assert_true, assert_raises
from scipy import sparse, linalg, stats
-from functools import partial
+from mne.fixes import partial
import warnings
+from mne.parallel import _force_serial
+from mne.stats.cluster_level import (permutation_cluster_test,
+ permutation_cluster_1samp_test,
+ spatio_temporal_cluster_test,
+ spatio_temporal_cluster_1samp_test,
+ ttest_1samp_no_p, summarize_clusters_stc)
-from mne.stats.cluster_level import permutation_cluster_test, \
- permutation_cluster_1samp_test, \
- spatio_temporal_cluster_test, \
- spatio_temporal_cluster_1samp_test, \
- ttest_1samp_no_p, summarize_clusters_stc
+warnings.simplefilter('always') # enable b/c these tests throw warnings
-noise_level = 20
-normfactor = np.hanning(20).sum()
+def _get_conditions():
+ noise_level = 20
-rng = np.random.RandomState(42)
-condition1_1d = rng.randn(40, 350) * noise_level
-for c in condition1_1d:
- c[:] = np.convolve(c, np.hanning(20), mode="same") / normfactor
+ normfactor = np.hanning(20).sum()
+ rng = np.random.RandomState(42)
+ condition1_1d = rng.randn(40, 350) * noise_level
+ for c in condition1_1d:
+ c[:] = np.convolve(c, np.hanning(20), mode="same") / normfactor
-condition2_1d = rng.randn(33, 350) * noise_level
-for c in condition2_1d:
- c[:] = np.convolve(c, np.hanning(20), mode="same") / normfactor
+ condition2_1d = rng.randn(33, 350) * noise_level
+ for c in condition2_1d:
+ c[:] = np.convolve(c, np.hanning(20), mode="same") / normfactor
-pseudoekp = 5 * np.hanning(150)[None, :]
-condition1_1d[:, 100:250] += pseudoekp
-condition2_1d[:, 100:250] -= pseudoekp
+ pseudoekp = 5 * np.hanning(150)[None, :]
+ condition1_1d[:, 100:250] += pseudoekp
+ condition2_1d[:, 100:250] -= pseudoekp
-condition1_2d = condition1_1d[:, :, np.newaxis]
-condition2_2d = condition2_1d[:, :, np.newaxis]
+ condition1_2d = condition1_1d[:, :, np.newaxis]
+ condition2_2d = condition2_1d[:, :, np.newaxis]
+ return condition1_1d, condition2_1d, condition1_2d, condition2_2d
def test_cluster_permutation_test():
- """Test cluster level permutations tests."""
+ """Test cluster level permutations tests
+ """
+ condition1_1d, condition2_1d, condition1_2d, condition2_2d = \
+ _get_conditions()
for condition1, condition2 in zip((condition1_1d, condition1_2d),
(condition2_1d, condition2_2d)):
T_obs, clusters, cluster_p_values, hist = permutation_cluster_test(
[condition1, condition2],
- n_permutations=100, tail=1, seed=1)
+ n_permutations=100, tail=1, seed=1,
+ buffer_size=None)
assert_equal(np.sum(cluster_p_values < 0.05), 1)
T_obs, clusters, cluster_p_values, hist = permutation_cluster_test(
[condition1, condition2],
- n_permutations=100, tail=0, seed=1)
+ n_permutations=100, tail=0, seed=1,
+ buffer_size=None)
assert_equal(np.sum(cluster_p_values < 0.05), 1)
- # test with 2 jobs
+ # test with 2 jobs and buffer_size enabled
+ buffer_size = condition1.shape[1] // 10
T_obs, clusters, cluster_p_values_buff, hist =\
permutation_cluster_test([condition1, condition2],
- n_permutations=100, tail=0, seed=1,
- n_jobs=2)
+ n_permutations=100, tail=0, seed=1,
+ n_jobs=2, buffer_size=buffer_size)
assert_array_equal(cluster_p_values, cluster_p_values_buff)
def test_cluster_permutation_t_test():
- """Test cluster level permutations T-test."""
- for condition1 in (condition1_1d, condition1_2d):
- # these are so significant we can get away with fewer perms
- T_obs, clusters, cluster_p_values, hist =\
- permutation_cluster_1samp_test(condition1, n_permutations=100,
- tail=0, seed=1)
- assert_equal(np.sum(cluster_p_values < 0.05), 1)
-
- T_obs_pos, c_1, cluster_p_values_pos, _ =\
- permutation_cluster_1samp_test(condition1, n_permutations=100,
- tail=1, threshold=1.67, seed=1)
-
- T_obs_neg, _, cluster_p_values_neg, _ =\
- permutation_cluster_1samp_test(-condition1, n_permutations=100,
- tail=-1, threshold=-1.67, seed=1)
- assert_array_equal(T_obs_pos, -T_obs_neg)
- assert_array_equal(cluster_p_values_pos < 0.05,
- cluster_p_values_neg < 0.05)
-
- # test with 2 jobs
- T_obs_neg, _, cluster_p_values_neg_buff, _ = \
- permutation_cluster_1samp_test(-condition1, n_permutations=100,
- tail=-1, threshold=-1.67, seed=1,
- n_jobs=2)
-
- assert_array_equal(cluster_p_values_neg, cluster_p_values_neg_buff)
+ """Test cluster level permutations T-test
+ """
+ condition1_1d, condition2_1d, condition1_2d, condition2_2d = \
+ _get_conditions()
+
+ # use a very large sigma to make sure Ts are not independent
+ stat_funs = [ttest_1samp_no_p,
+ partial(ttest_1samp_no_p, sigma=1e-1)]
+
+ for stat_fun in stat_funs:
+ for condition1 in (condition1_1d, condition1_2d):
+ # these are so significant we can get away with fewer perms
+ T_obs, clusters, cluster_p_values, hist =\
+ permutation_cluster_1samp_test(condition1, n_permutations=100,
+ tail=0, seed=1,
+ buffer_size=None)
+ assert_equal(np.sum(cluster_p_values < 0.05), 1)
+
+ T_obs_pos, c_1, cluster_p_values_pos, _ =\
+ permutation_cluster_1samp_test(condition1, n_permutations=100,
+ tail=1, threshold=1.67, seed=1,
+ stat_fun=stat_fun,
+ buffer_size=None)
+
+ T_obs_neg, _, cluster_p_values_neg, _ =\
+ permutation_cluster_1samp_test(-condition1, n_permutations=100,
+ tail=-1, threshold=-1.67,
+ seed=1, stat_fun=stat_fun,
+ buffer_size=None)
+ assert_array_equal(T_obs_pos, -T_obs_neg)
+ assert_array_equal(cluster_p_values_pos < 0.05,
+ cluster_p_values_neg < 0.05)
+
+ # test with 2 jobs and buffer_size enabled
+ buffer_size = condition1.shape[1] // 10
+ T_obs_neg_buff, _, cluster_p_values_neg_buff, _ = \
+ permutation_cluster_1samp_test(-condition1, n_permutations=100,
+ tail=-1, threshold=-1.67,
+ seed=1, n_jobs=2,
+ stat_fun=stat_fun,
+ buffer_size=buffer_size)
+
+ assert_array_equal(T_obs_neg, T_obs_neg_buff)
+ assert_array_equal(cluster_p_values_neg, cluster_p_values_neg_buff)
def test_cluster_permutation_with_connectivity():
- """Test cluster level permutations with connectivity matrix."""
+ """Test cluster level permutations with connectivity matrix
+ """
try:
try:
from sklearn.feature_extraction.image import grid_to_graph
@@ -93,6 +122,8 @@ def test_cluster_permutation_with_connectivity():
from scikits.learn.feature_extraction.image import grid_to_graph
except ImportError:
return
+ condition1_1d, condition2_1d, condition1_2d, condition2_2d = \
+ _get_conditions()
n_pts = condition1_1d.shape[1]
# we don't care about p-values in any of these, so do fewer permutations
@@ -105,10 +136,10 @@ def test_cluster_permutation_with_connectivity():
[(condition1_1d, condition1_2d,
permutation_cluster_1samp_test,
spatio_temporal_cluster_1samp_test),
- ([condition1_1d, condition2_1d],
- [condition1_2d, condition2_2d],
- permutation_cluster_test,
- spatio_temporal_cluster_test)]:
+ ([condition1_1d, condition2_1d],
+ [condition1_2d, condition2_2d],
+ permutation_cluster_test,
+ spatio_temporal_cluster_test)]:
out = func(X1d, **args)
connectivity = grid_to_graph(1, n_pts)
out_connectivity = func(X1d, connectivity=connectivity, **args)
@@ -140,7 +171,7 @@ def test_cluster_permutation_with_connectivity():
# Make sure that we got the old ones back
data_1 = set([np.sum(out[0][b[:n_pts]]) for b in out[1]])
data_2 = set([np.sum(out_connectivity_2[0][a[:n_pts]]) for a in
- out_connectivity_2[1][:]])
+ out_connectivity_2[1][:]])
assert_true(len(data_1.intersection(data_2)) == len(data_1))
# now use the other algorithm
@@ -149,10 +180,10 @@ def test_cluster_permutation_with_connectivity():
else:
X1d_3 = np.reshape(X1d_2, (-1, 2, 350))
- out_connectivity_3 = spatio_temporal_func(
- X1d_3, n_permutations=50,
- connectivity=connectivity, max_step=0,
- threshold=1.67, check_disjoint=True)
+ out_connectivity_3 = spatio_temporal_func(X1d_3, n_permutations=50,
+ connectivity=connectivity,
+ max_step=0, threshold=1.67,
+ check_disjoint=True)
# make sure we were operating on the same values
split = len(out[0])
assert_array_equal(out[0], out_connectivity_3[0][0])
@@ -164,18 +195,16 @@ def test_cluster_permutation_with_connectivity():
# Make sure that we got the old ones back
data_1 = set([np.sum(out[0][b[:n_pts]]) for b in out[1]])
data_2 = set([np.sum(out_connectivity_3[0][a[0], a[1]]) for a in
- out_connectivity_3[1]])
+ out_connectivity_3[1]])
assert_true(len(data_1.intersection(data_2)) == len(data_1))
# test new versus old method
- out_connectivity_4 = spatio_temporal_func(
- X1d_3, n_permutations=50,
- connectivity=connectivity, max_step=2,
- threshold=1.67)
- out_connectivity_5 = spatio_temporal_func(
- X1d_3, n_permutations=50,
- connectivity=connectivity, max_step=1,
- threshold=1.67)
+ out_connectivity_4 = spatio_temporal_func(X1d_3, n_permutations=50,
+ connectivity=connectivity,
+ max_step=2, threshold=1.67)
+ out_connectivity_5 = spatio_temporal_func(X1d_3, n_permutations=50,
+ connectivity=connectivity,
+ max_step=1, threshold=1.67)
# clusters could be in a different order
sums_4 = [np.sum(out_connectivity_4[0][a])
@@ -186,10 +215,10 @@ def test_cluster_permutation_with_connectivity():
sums_5 = np.sort(sums_5)
assert_array_almost_equal(sums_4, sums_5)
- assert_raises(ValueError, spatio_temporal_func,
- X1d_3, n_permutations=1,
- connectivity=connectivity, max_step=1,
- threshold=1.67, n_jobs=-1000)
+ if not _force_serial:
+ assert_raises(ValueError, spatio_temporal_func, X1d_3,
+ n_permutations=1, connectivity=connectivity, max_step=1,
+ threshold=1.67, n_jobs=-1000)
# not enough TFCE params
assert_raises(KeyError, spatio_temporal_func, X1d_3,
@@ -220,10 +249,11 @@ def test_cluster_permutation_with_connectivity():
connectivity=connectivity, tail=2)
# make sure it actually found a significant point
- out_connectivity_6 = spatio_temporal_func(
- X1d_3, n_permutations=50,
- connectivity=connectivity, max_step=1,
- threshold=dict(start=1, step=1))
+ out_connectivity_6 = spatio_temporal_func(X1d_3, n_permutations=50,
+ connectivity=connectivity,
+ max_step=1,
+ threshold=dict(start=1,
+ step=1))
assert_true(np.min(out_connectivity_6[2]) < 0.05)
@@ -308,7 +338,8 @@ def test_permutation_connectivity_equiv():
def spatio_temporal_cluster_test_connectivity():
- """Test cluster level permutations with and without connectivity """
+ """Test cluster level permutations with and without connectivity
+ """
try:
try:
from sklearn.feature_extraction.image import grid_to_graph
@@ -316,13 +347,15 @@ def spatio_temporal_cluster_test_connectivity():
from scikits.learn.feature_extraction.image import grid_to_graph
except ImportError:
return
+ condition1_1d, condition2_1d, condition1_2d, condition2_2d = \
+ _get_conditions()
rng = np.random.RandomState(0)
noise1_2d = rng.randn(condition1_2d.shape[0], condition1_2d.shape[1], 10)
- data1_2d = np.transpose(np.dstack((condition1_2d, noise1_2d)), [0, 2, 1])
-
+ data1_2d = np.transpose(np.dstack((condition1_2d, noise1_2d)), [0, 2, 1])
+
noise2_d2 = rng.randn(condition2_2d.shape[0], condition2_2d.shape[1], 10)
- data2_2d = np.transpose(np.dstack((condition2_2d, noise2_d2)), [0, 2, 1])
+ data2_2d = np.transpose(np.dstack((condition2_2d, noise2_d2)), [0, 2, 1])
conn = grid_to_graph(data1_2d.shape[-1], 1)
@@ -330,15 +363,25 @@ def spatio_temporal_cluster_test_connectivity():
T_obs, clusters, p_values_conn, hist = \
spatio_temporal_cluster_test([data1_2d, data2_2d], connectivity=conn,
n_permutations=50, tail=1, seed=1,
- threshold=threshold)
+ threshold=threshold, buffer_size=None)
+ buffer_size = data1_2d.size // 10
T_obs, clusters, p_values_no_conn, hist = \
spatio_temporal_cluster_test([data1_2d, data2_2d],
n_permutations=50, tail=1, seed=1,
- threshold=threshold)
+ threshold=threshold, n_jobs=2,
+ buffer_size=buffer_size)
assert_equal(np.sum(p_values_conn < 0.05), np.sum(p_values_no_conn < 0.05))
+ # make sure results are the same without buffer_size
+ T_obs, clusters, p_values2, hist2 = \
+ spatio_temporal_cluster_test([data1_2d, data2_2d],
+ n_permutations=50, tail=1, seed=1,
+ threshold=threshold, n_jobs=2,
+ buffer_size=None)
+ assert_array_equal(p_values_no_conn, p_values2)
+
def ttest_1samp(X):
"""Returns T-values
@@ -347,12 +390,12 @@ def ttest_1samp(X):
def test_summarize_clusters():
- """ test summary stcs
+ """Test cluster summary stcs
"""
clu = (np.random.random([1, 20484]),
[(np.array([0]), np.array([0, 2, 4]))],
- np.array([0.02, 0.1]),
- np.array([12, -14, 30]))
+ np.array([0.02, 0.1]),
+ np.array([12, -14, 30]))
stc_sum = summarize_clusters_stc(clu)
assert_true(stc_sum.data.shape[1] == 2)
clu[2][0] = 0.3
diff --git a/mne/stats/tests/test_parametric.py b/mne/stats/tests/test_parametric.py
index 1f7f0b0..9b98ce5 100644
--- a/mne/stats/tests/test_parametric.py
+++ b/mne/stats/tests/test_parametric.py
@@ -1,6 +1,6 @@
from itertools import product
-from ..parametric import f_twoway_rm, f_threshold_twoway_rm, \
- defaults_twoway_rm
+from ..parametric import (f_twoway_rm, f_threshold_twoway_rm,
+ defaults_twoway_rm)
from nose.tools import assert_raises, assert_true
from numpy.testing import assert_array_almost_equal
diff --git a/mne/surface.py b/mne/surface.py
index eeacd37..395dc5a 100644
--- a/mne/surface.py
+++ b/mne/surface.py
@@ -1,38 +1,30 @@
# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
# Matti Hamalainen <msh at nmr.mgh.harvard.edu>
+# Denis A. Engemann <d.engemann at fz-juelich.de>
#
# License: BSD (3-clause)
-import numpy as np
+import os
+from os import path as op
+import sys
from struct import pack
-
-import logging
-logger = logging.getLogger('mne')
+import numpy as np
+from scipy.spatial.distance import cdist
+from scipy import sparse
from .fiff.constants import FIFF
from .fiff.open import fiff_open
from .fiff.tree import dir_tree_find
from .fiff.tag import find_tag
-from .fiff.write import write_int, write_float, write_float_matrix, \
- write_int_matrix, start_file, end_block, \
- start_block, end_file
-from . import verbose
+from .fiff.write import (write_int, write_float, write_float_matrix,
+ write_int_matrix, start_file, end_block,
+ start_block, end_file, write_string,
+ write_float_sparse_rcs)
+from .utils import logger, verbose, get_subjects_dir
-#
-# These fiff definitions are not needed elsewhere
-#
-FIFFB_BEM = 310 # BEM data
-FIFFB_BEM_SURF = 311 # One of the surfaces
-FIFF_BEM_SURF_ID = 3101 # int surface number
-FIFF_BEM_SURF_NAME = 3102 # string surface name
-FIFF_BEM_SURF_NNODE = 3103 # int number of nodes on a surface
-FIFF_BEM_SURF_NTRI = 3104 # int number of triangles on a surface
-FIFF_BEM_SURF_NODES = 3105 # float surface nodes (nnode,3)
-FIFF_BEM_SURF_TRIANGLES = 3106 # int surface triangles (ntri,3)
-FIFF_BEM_SURF_NORMALS = 3107 # float surface node normal unit vectors
-FIFF_BEM_COORD_FRAME = 3112 # The coordinate frame of the mode
-FIFF_BEM_SIGMA = 3113 # Conductivity of a compartment
+##############################################################################
+# BEM
@verbose
def read_bem_surfaces(fname, add_geom=False, s_id=None, verbose=None):
@@ -68,7 +60,7 @@ def read_bem_surfaces(fname, add_geom=False, s_id=None, verbose=None):
#
# Find BEM
#
- bem = dir_tree_find(tree, FIFFB_BEM)
+ bem = dir_tree_find(tree, FIFF.FIFFB_BEM)
if bem is None:
fid.close()
raise ValueError('BEM data not found')
@@ -77,7 +69,7 @@ def read_bem_surfaces(fname, add_geom=False, s_id=None, verbose=None):
#
# Locate all surfaces
#
- bemsurf = dir_tree_find(bem, FIFFB_BEM_SURF)
+ bemsurf = dir_tree_find(bem, FIFF.FIFFB_BEM_SURF)
if bemsurf is None:
fid.close()
raise ValueError('BEM surface data not found')
@@ -86,7 +78,7 @@ def read_bem_surfaces(fname, add_geom=False, s_id=None, verbose=None):
#
# Coordinate frame possibly at the top level
#
- tag = find_tag(fid, bem, FIFF_BEM_COORD_FRAME)
+ tag = find_tag(fid, bem, FIFF.FIFF_BEM_COORD_FRAME)
if tag is not None:
coord_frame = tag.data
#
@@ -124,7 +116,7 @@ def _read_bem_surface(fid, this, def_coord_frame, s_id=None):
#
# Read all the interesting stuff
#
- tag = find_tag(fid, this, FIFF_BEM_SURF_ID)
+ tag = find_tag(fid, this, FIFF.FIFF_BEM_SURF_ID)
if tag is None:
res['id'] = FIFF.FIFFV_BEM_SURF_ID_UNKNOWN
@@ -135,20 +127,20 @@ def _read_bem_surface(fid, this, def_coord_frame, s_id=None):
if res['id'] != s_id:
return None
- tag = find_tag(fid, this, FIFF_BEM_SIGMA)
+ tag = find_tag(fid, this, FIFF.FIFF_BEM_SIGMA)
if tag is None:
res['sigma'] = 1.0
else:
res['sigma'] = float(tag.data)
- tag = find_tag(fid, this, FIFF_BEM_SURF_NNODE)
+ tag = find_tag(fid, this, FIFF.FIFF_BEM_SURF_NNODE)
if tag is None:
fid.close()
raise ValueError('Number of vertices not found')
res['np'] = int(tag.data)
- tag = find_tag(fid, this, FIFF_BEM_SURF_NTRI)
+ tag = find_tag(fid, this, FIFF.FIFF_BEM_SURF_NTRI)
if tag is None:
fid.close()
raise ValueError('Number of triangles not found')
@@ -157,7 +149,7 @@ def _read_bem_surface(fid, this, def_coord_frame, s_id=None):
tag = find_tag(fid, this, FIFF.FIFF_MNE_COORD_FRAME)
if tag is None:
- tag = find_tag(fid, this, FIFF_BEM_COORD_FRAME)
+ tag = find_tag(fid, this, FIFF.FIFF_BEM_COORD_FRAME)
if tag is None:
res['coord_frame'] = def_coord_frame
else:
@@ -167,7 +159,7 @@ def _read_bem_surface(fid, this, def_coord_frame, s_id=None):
#
# Vertices, normals, and triangles
#
- tag = find_tag(fid, this, FIFF_BEM_SURF_NODES)
+ tag = find_tag(fid, this, FIFF.FIFF_BEM_SURF_NODES)
if tag is None:
fid.close()
raise ValueError('Vertex data not found')
@@ -186,7 +178,7 @@ def _read_bem_surface(fid, this, def_coord_frame, s_id=None):
fid.close()
raise ValueError('Vertex normal information is incorrect')
- tag = find_tag(fid, this, FIFF_BEM_SURF_TRIANGLES)
+ tag = find_tag(fid, this, FIFF.FIFF_BEM_SURF_TRIANGLES)
if tag is None:
fid.close()
raise ValueError('Triangulation not found')
@@ -200,42 +192,325 @@ def _read_bem_surface(fid, this, def_coord_frame, s_id=None):
@verbose
-def _complete_surface_info(this, verbose=None):
- """Complete surface info"""
+def read_bem_solution(fname, verbose=None):
+ """Read the BEM solution from a file
+
+ Parameters
+ ----------
+ fname : string
+ The file containing the BEM solution.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ bem : dict
+ The BEM solution.
+ """
+ logger.info('Loading surfaces...')
+ bem_surfs = read_bem_surfaces(fname, add_geom=True, verbose=False)
+ if len(bem_surfs) == 3:
+ logger.info('Three-layer model surfaces loaded.')
+ needed = np.array([FIFF.FIFFV_BEM_SURF_ID_HEAD,
+ FIFF.FIFFV_BEM_SURF_ID_SKULL,
+ FIFF.FIFFV_BEM_SURF_ID_BRAIN])
+ if not all([x['id'] in needed for x in bem_surfs]):
+ raise RuntimeError('Could not find necessary BEM surfaces')
+ # reorder surfaces as necessary (shouldn't need to?)
+ reorder = [None] * 3
+ for x in bem_surfs:
+ reorder[np.where(x['id'] == needed)[0][0]] = x
+ bem_surfs = reorder
+ elif len(bem_surfs) == 1:
+ if not bem_surfs[0]['id'] == FIFF.FIFFV_BEM_SURF_ID_BRAIN:
+ raise RuntimeError('BEM Surfaces not found')
+ logger.info('Homogeneous model surface loaded.')
+
+ # convert from surfaces to solution
+ bem = dict(surfs=bem_surfs)
+ logger.info('\nLoading the solution matrix...\n')
+ f, tree, _ = fiff_open(fname)
+ with f as fid:
+ # Find the BEM data
+ nodes = dir_tree_find(tree, FIFF.FIFFB_BEM)
+ if len(nodes) == 0:
+ raise RuntimeError('No BEM data in %s' % fname)
+ bem_node = nodes[0]
+
+ # Approximation method
+ tag = find_tag(f, bem_node, FIFF.FIFF_BEM_APPROX)
+ method = tag.data[0]
+ if method == FIFF.FIFFV_BEM_APPROX_CONST:
+ method = 'constant collocation'
+ elif method == FIFF.FIFFV_BEM_APPROX_LINEAR:
+ method = 'linear collocation'
+ else:
+ raise RuntimeError('Cannot handle BEM approximation method : %d'
+ % method)
+
+ tag = find_tag(fid, bem_node, FIFF.FIFF_BEM_POT_SOLUTION)
+ dims = tag.data.shape
+ if len(dims) != 2:
+ raise RuntimeError('Expected a two-dimensional solution matrix '
+ 'instead of a %d dimensional one' % dims[0])
+
+ dim = 0
+ for surf in bem['surfs']:
+ if method == 'linear collocation':
+ dim += surf['np']
+ else:
+ dim += surf['ntri']
+
+ if dims[0] != dim or dims[1] != dim:
+ raise RuntimeError('Expected a %d x %d solution matrix instead of '
+ 'a %d x %d one' % (dim, dim, dims[1], dims[0]))
+ sol = tag.data
+ nsol = dims[0]
+
+ # Gamma factors and multipliers
+ bem['sigma'] = np.array([surf['sigma'] for surf in bem['surfs']])
+ # Dirty trick for the zero conductivity outside
+ sigma = np.r_[0.0, bem['sigma']]
+ bem['source_mult'] = 2.0 / (sigma[1:] + sigma[:-1])
+ bem['field_mult'] = sigma[1:] - sigma[:-1]
+ # make sure subsequent "zip"s work correctly
+ assert len(bem['surfs']) == len(bem['field_mult'])
+ bem['gamma'] = ((sigma[1:] - sigma[:-1])[np.newaxis, :] /
+ (sigma[1:] + sigma[:-1])[:, np.newaxis])
+ bem['sol_name'] = fname
+ bem['solution'] = sol
+ bem['nsol'] = nsol
+ bem['bem_method'] = method
+ logger.info('Loaded %s BEM solution from %s', bem['bem_method'], fname)
+ return bem
+
+
+###############################################################################
+# EFFICIENCY UTILITIES
+
+def fast_cross_3d(x, y):
+ """Compute cross product between list of 3D vectors
+
+ Much faster than np.cross() when the number of cross products
+ becomes large (>500). This is because np.cross() methods become
+ less memory efficient at this stage.
+
+ Parameters
+ ----------
+ x : array
+ Input array 1.
+ y : array
+ Input array 2.
+
+ Returns
+ -------
+ z : array
+ Cross product of x and y.
+
+ Notes
+ -----
+ x and y must both be 2D row vectors. One must have length 1, or both
+ lengths must match.
+ """
+ assert x.ndim == 2
+ assert y.ndim == 2
+ assert x.shape[1] == 3
+ assert y.shape[1] == 3
+ assert (x.shape[0] == 1 or y.shape[0] == 1) or x.shape[0] == y.shape[0]
+ if max([x.shape[0], y.shape[0]]) >= 500:
+ return np.c_[x[:, 1] * y[:, 2] - x[:, 2] * y[:, 1],
+ x[:, 2] * y[:, 0] - x[:, 0] * y[:, 2],
+ x[:, 0] * y[:, 1] - x[:, 1] * y[:, 0]]
+ else:
+ return np.cross(x, y)
+
+
+def _accumulate_normals(tris, tri_nn, npts):
+ """Efficiently accumulate triangle normals"""
+ # this code replaces the following, but is faster (vectorized):
#
- # Main triangulation
+ # this['nn'] = np.zeros((this['np'], 3))
+ # for p in xrange(this['ntri']):
+ # verts = this['tris'][p]
+ # this['nn'][verts, :] += this['tri_nn'][p, :]
#
- logger.info(' Completing triangulation info...')
- logger.info('triangle normals...')
+ nn = np.zeros((npts, 3))
+ for verts in tris.T: # note this only loops 3x (number of verts per tri)
+ counts = np.bincount(verts, minlength=npts)
+ reord = np.argsort(verts)
+ vals = np.r_[np.zeros((1, 3)), np.cumsum(tri_nn[reord, :], 0)]
+ idx = np.cumsum(np.r_[0, counts])
+ nn += vals[idx[1:], :] - vals[idx[:-1], :]
+ return nn
+
+
+def _triangle_neighbors(tris, npts):
+ """Efficiently compute vertex neighboring triangles"""
+ # this code replaces the following, but is faster (vectorized):
+ #
+ # this['neighbor_tri'] = [list() for _ in xrange(this['np'])]
+ # for p in xrange(this['ntri']):
+ # verts = this['tris'][p]
+ # this['neighbor_tri'][verts[0]].append(p)
+ # this['neighbor_tri'][verts[1]].append(p)
+ # this['neighbor_tri'][verts[2]].append(p)
+ # this['neighbor_tri'] = [np.array(nb, int) for nb in this['neighbor_tri']]
+ #
+ verts = tris.ravel()
+ counts = np.bincount(verts, minlength=npts)
+ reord = np.argsort(verts)
+ tri_idx = np.unravel_index(reord, (len(tris), 3))[0]
+ idx = np.cumsum(np.r_[0, counts])
+ # the sort below slows it down a bit, but is needed for equivalence
+ neighbor_tri = [np.sort(tri_idx[v1:v2])
+ for v1, v2 in zip(idx[:-1], idx[1:])]
+ return neighbor_tri
+
+
+def _triangle_coords(r, geom, best):
+ """Get coordinates of a vertex projected to a triangle"""
+ r1 = geom['r1'][best]
+ tri_nn = geom['nn'][best]
+ r12 = geom['r12'][best]
+ r13 = geom['r13'][best]
+ a = geom['a'][best]
+ b = geom['b'][best]
+ c = geom['c'][best]
+ rr = r - r1
+ z = np.sum(rr * tri_nn)
+ v1 = np.sum(rr * r12)
+ v2 = np.sum(rr * r13)
+ det = a * b - c * c
+ x = (b * v1 - c * v2) / det
+ y = (a * v2 - c * v1) / det
+ return x, y, z
+
+
+def _complete_surface_info(this, do_neighbor_vert=False):
+ """Complete surface info"""
+ # based on mne_source_space_add_geometry_info() in mne_add_geometry_info.c
+
+ # Main triangulation [mne_add_triangle_data()]
this['tri_area'] = np.zeros(this['ntri'])
r1 = this['rr'][this['tris'][:, 0], :]
r2 = this['rr'][this['tris'][:, 1], :]
r3 = this['rr'][this['tris'][:, 2], :]
this['tri_cent'] = (r1 + r2 + r3) / 3.0
- this['tri_nn'] = np.cross((r2 - r1), (r3 - r1))
- #
+ this['tri_nn'] = fast_cross_3d((r2 - r1), (r3 - r1))
+
# Triangle normals and areas
- #
size = np.sqrt(np.sum(this['tri_nn'] ** 2, axis=1))
this['tri_area'] = size / 2.0
+ zidx = np.where(size == 0)[0]
+ for idx in zidx:
+ logger.info(' Warning: zero size triangle # %s' % idx)
+ size[zidx] = 1.0 # prevent ugly divide-by-zero
this['tri_nn'] /= size[:, None]
- #
- # Accumulate the vertex normals
- #
- logger.info('vertex normals...')
- this['nn'] = np.zeros((this['np'], 3))
- for p in range(this['ntri']):
- this['nn'][this['tris'][p, :], :] += this['tri_nn'][p, :]
- #
- # Compute the lengths of the vertex normals and scale
- #
- logger.info('normalize...')
- this['nn'] /= np.sqrt(np.sum(this['nn'] ** 2, axis=1))[:, None]
- logger.info('[done]')
+ # Find neighboring triangles, accumulate vertex normals, normalize
+ logger.info(' Triangle neighbors and vertex normals...')
+ this['neighbor_tri'] = _triangle_neighbors(this['tris'], this['np'])
+ this['nn'] = _accumulate_normals(this['tris'], this['tri_nn'], this['np'])
+ _normalize_vectors(this['nn'])
+
+ # Check for topological defects
+ idx = np.where([len(n) == 0 for n in this['neighbor_tri']])[0]
+ if len(idx) > 0:
+ logger.info(' Vertices [%s] do not have any neighboring'
+ 'triangles!' % ','.join([str(ii) for ii in idx]))
+ idx = np.where([len(n) < 3 for n in this['neighbor_tri']])[0]
+ if len(idx) > 0:
+ logger.info(' Vertices [%s] have fewer than three neighboring '
+ 'tris, omitted' % ','.join([str(ii) for ii in idx]))
+ for k in idx:
+ this['neighbor_tri'] = np.array([], int)
+
+ # Determine the neighboring vertices and fix errors
+ if do_neighbor_vert is True:
+ this['neighbor_vert'] = [_get_surf_neighbors(this, k)
+ for k in xrange(this['np'])]
+
return this
+def _get_surf_neighbors(surf, k):
+ """Calculate the surface neighbors based on triangulation"""
+ verts = np.concatenate([surf['tris'][nt]
+ for nt in surf['neighbor_tri'][k]])
+ verts = np.setdiff1d(verts, [k], assume_unique=False)
+ if np.any(verts >= surf['np']):
+ raise RuntimeError
+ nneighbors = len(verts)
+ nneigh_max = len(surf['neighbor_tri'][k])
+ if nneighbors > nneigh_max:
+ raise RuntimeError('Too many neighbors for vertex %d' % k)
+ elif nneighbors != nneigh_max:
+ logger.info(' Incorrect number of distinct neighbors for vertex'
+ ' %d (%d instead of %d) [fixed].' % (k, nneighbors,
+ nneigh_max))
+ return verts
+
+
+def _normalize_vectors(rr):
+ """Normalize surface vertices"""
+ size = np.sqrt(np.sum(rr * rr, axis=1))
+ size[size == 0] = 1.0 # avoid divide-by-zero
+ rr /= size[:, np.newaxis] # operate in-place
+
+
+def _compute_nearest(xhs, rr, use_balltree=True, return_dists=False):
+ """Find nearest neighbors
+
+ Note: The rows in xhs and rr must all be unit-length vectors, otherwise
+ the result will be incorrect.
+
+ Parameters
+ ----------
+ xhs : array, shape=(n_samples, n_dim)
+ Points of data set.
+ rr : array, shape=(n_query, n_dim)
+ Points to find nearest neighbors for.
+ use_balltree : bool
+ Use fast BallTree based search from scikit-learn. If scikit-learn
+ is not installed it will fall back to the slow brute force search.
+
+ Returns
+ -------
+ nearest : array, shape=(n_query,)
+ Index of nearest neighbor in xhs for every point in rr.
+ """
+ if use_balltree:
+ try:
+ from sklearn.neighbors import BallTree
+ except ImportError:
+ logger.info('Nearest-neighbor searches will be significantly '
+ 'faster if scikit-learn is installed.')
+ use_balltree = False
+
+ if use_balltree is True:
+ ball_tree = BallTree(xhs)
+ if return_dists:
+ out = ball_tree.query(rr, k=1, return_distance=True)
+ return out[1][:, 0], out[0][:, 0]
+ else:
+ nearest = ball_tree.query(rr, k=1, return_distance=False)[:, 0]
+ return nearest
+ else:
+ if return_dists:
+ nearest = list()
+ dists = list()
+ for r in rr:
+ d = cdist(r[np.newaxis, :], xhs)
+ idx = np.argmin(d)
+ nearest.append(idx)
+ dists.append(d[0, idx])
+ return (np.array(nearest), np.array(dists))
+ else:
+ nearest = np.array([np.argmin(cdist(r[np.newaxis, :], xhs))
+ for r in rr])
+ return nearest
+
+
###############################################################################
# Handle freesurfer
@@ -267,19 +542,22 @@ def read_curvature(filepath):
return bin_curv
-def read_surface(fname):
+ at verbose
+def read_surface(fname, verbose=None):
"""Load a Freesurfer surface mesh in triangular format
Parameters
----------
fname : str
The name of the file containing the surface.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
Returns
-------
- coords : array, shape=(n_vertices, 3)
+ rr : array, shape=(n_vertices, 3)
Coordinate points.
- faces : int array, shape=(n_faces, 3)
+ tris : int array, shape=(n_faces, 3)
Triangulation (each line contains indexes for three points which
together form a face).
"""
@@ -319,11 +597,207 @@ def read_surface(fname):
else:
raise ValueError("%s does not appear to be a Freesurfer surface"
% fname)
+ logger.info('Triangle file: %s nvert = %s ntri = %s'
+ % (create_stamp.strip(), len(coords), len(faces)))
coords = coords.astype(np.float) # XXX: due to mayavi bug on mac 32bits
return coords, faces
+ at verbose
+def _read_surface_geom(fname, add_geom=True, norm_rr=False, verbose=None):
+ """Load the surface as dict, optionally add the geometry information"""
+ # based on mne_load_surface_geom() in mne_surface_io.c
+ if isinstance(fname, basestring):
+ rr, tris = read_surface(fname) # mne_read_triangle_file()
+ nvert = len(rr)
+ ntri = len(tris)
+ s = dict(rr=rr, tris=tris, use_tris=tris, ntri=ntri,
+ np=nvert)
+ elif isinstance(fname, dict):
+ s = fname
+ else:
+ raise RuntimeError('fname cannot be understood as str or dict')
+ if add_geom is True:
+ s = _complete_surface_info(s)
+ if norm_rr is True:
+ _normalize_vectors(s['rr'])
+ return s
+
+
+##############################################################################
+# SURFACE CREATION
+
+def _get_ico_surface(grade):
+ """Return an icosahedral surface of the desired grade"""
+ # always use verbose=False since users don't need to know we're pulling
+ # these from a file
+ ico_file_name = op.join(op.dirname(__file__), 'data',
+ 'icos.fif.gz')
+ ico = read_bem_surfaces(ico_file_name, s_id=9000 + grade, verbose=False)
+ return ico
+
+
+def _tessellate_sphere_surf(level, rad=1.0):
+ """Return a surface structure instead of the details"""
+ rr, tris = _tessellate_sphere(level)
+ npt = len(rr) # called "npt" instead of "np" because of numpy...
+ ntri = len(tris)
+ nn = rr.copy()
+ rr *= rad
+ s = dict(rr=rr, np=npt, tris=tris, use_tris=tris, ntri=ntri, nuse=np,
+ nn=nn, inuse=np.ones(npt, int))
+ return s
+
+
+def _norm_midpt(ai, bi, rr):
+ a = np.array([rr[aii] for aii in ai])
+ b = np.array([rr[bii] for bii in bi])
+ c = (a + b) / 2.
+ return c / np.sqrt(np.sum(c ** 2, 1))[:, np.newaxis]
+
+
+def _tessellate_sphere(mylevel):
+ """Create a tessellation of a unit sphere"""
+ # Vertices of a unit octahedron
+ rr = np.array([[1, 0, 0], [-1, 0, 0], # xplus, xminus
+ [0, 1, 0], [0, -1, 0], # yplus, yminus
+ [0, 0, 1], [0, 0, -1]], float) # zplus, zminus
+ tris = np.array([[0, 4, 2], [2, 4, 1], [1, 4, 3], [3, 4, 0],
+ [0, 2, 5], [2, 1, 5], [1, 3, 5], [3, 0, 5]], int)
+
+ # A unit octahedron
+ if mylevel < 1:
+ raise ValueError('# of levels must be >= 1')
+
+ # Reverse order of points in each triangle
+ # for counter-clockwise ordering
+ tris = tris[:, [2, 1, 0]]
+
+ # Subdivide each starting triangle (mylevel - 1) times
+ for _ in range(1, mylevel):
+ """
+ Subdivide each triangle in the old approximation and normalize
+ the new points thus generated to lie on the surface of the unit
+ sphere.
+
+ Each input triangle with vertices labelled [0,1,2] as shown
+ below will be turned into four new triangles:
+
+ Make new points
+ a = (0+2)/2
+ b = (0+1)/2
+ c = (1+2)/2
+ 1
+ /\ Normalize a, b, c
+ / \
+ b/____\c Construct new triangles
+ /\ /\ [0,b,a]
+ / \ / \ [b,1,c]
+ /____\/____\ [a,b,c]
+ 0 a 2 [a,c,2]
+
+ """
+ # use new method: first make new points (rr)
+ a = _norm_midpt(tris[:, 0], tris[:, 2], rr)
+ b = _norm_midpt(tris[:, 0], tris[:, 1], rr)
+ c = _norm_midpt(tris[:, 1], tris[:, 2], rr)
+ lims = np.cumsum([len(rr), len(a), len(b), len(c)])
+ aidx = np.arange(lims[0], lims[1])
+ bidx = np.arange(lims[1], lims[2])
+ cidx = np.arange(lims[2], lims[3])
+ rr = np.concatenate((rr, a, b, c))
+
+ # now that we have our points, make new triangle definitions
+ tris = np.array((np.c_[tris[:, 0], bidx, aidx],
+ np.c_[bidx, tris[:, 1], cidx],
+ np.c_[aidx, bidx, cidx],
+ np.c_[aidx, cidx, tris[:, 2]]), int).swapaxes(0, 1)
+ tris = np.reshape(tris, (np.prod(tris.shape[:2]), 3))
+
+ # Copy the resulting approximation into standard table
+ rr_orig = rr
+ rr = np.empty_like(rr)
+ nnode = 0
+ for k, tri in enumerate(tris):
+ for j in range(3):
+ coord = rr_orig[tri[j]]
+ # this is faster than cdist (no need for sqrt)
+ similarity = np.dot(rr[:nnode], coord)
+ idx = np.where(similarity > 0.99999)[0]
+ if len(idx) > 0:
+ tris[k, j] = idx[0]
+ else:
+ rr[nnode] = coord
+ tris[k, j] = nnode
+ nnode += 1
+ rr = rr[:nnode].copy()
+ return rr, tris
+
+
+def _create_surf_spacing(surf, hemi, subject, stype, sval, ico_surf,
+ subjects_dir):
+ """Load a surf and use the subdivided icosahedron to get points"""
+ # Based on load_source_space_surf_spacing() in load_source_space.c
+ surf = _read_surface_geom(surf)
+
+ if stype in ['ico', 'oct']:
+ ### from mne_ico_downsample.c ###
+ surf_name = op.join(subjects_dir, subject, 'surf', hemi + '.sphere')
+ logger.info('Loading geometry from %s...' % surf_name)
+ from_surf = _read_surface_geom(surf_name, norm_rr=True, add_geom=False)
+ _normalize_vectors(ico_surf['rr'])
+
+ # Make the maps
+ logger.info('Mapping %s %s -> %s (%d) ...'
+ % (hemi, subject, stype, sval))
+ mmap = _compute_nearest(from_surf['rr'], ico_surf['rr'])
+ nmap = len(mmap)
+ surf['inuse'] = np.zeros(surf['np'], int)
+ for k in xrange(nmap):
+ if surf['inuse'][mmap[k]]:
+ # Try the nearest neighbors
+ neigh = _get_surf_neighbors(surf, mmap[k])
+ was = mmap[k]
+ inds = np.where(np.logical_not(surf['inuse'][neigh]))[0]
+ if len(inds) == 0:
+ raise RuntimeError('Could not find neighbor for vertex '
+ '%d / %d' % (k, nmap))
+ else:
+ mmap[k] = neigh[inds[-1]]
+ logger.info(' Source space vertex moved from %d to %d '
+ 'because of double occupation', was, mmap[k])
+ elif mmap[k] < 0 or mmap[k] > surf['np']:
+ raise RuntimeError('Map number out of range (%d), this is '
+ 'probably due to inconsistent surfaces. '
+ 'Parts of the FreeSurfer reconstruction '
+ 'need to be redone.' % mmap[k])
+ surf['inuse'][mmap[k]] = True
+
+ logger.info('Setting up the triangulation for the decimated '
+ 'surface...')
+ surf['use_tris'] = np.array([mmap[ist] for ist in ico_surf['tris']],
+ np.int32)
+ else: # use_all is True
+ surf['inuse'] = np.ones(surf['np'], int)
+ surf['use_tris'] = None
+ if surf['use_tris'] is not None:
+ surf['nuse_tri'] = len(surf['use_tris'])
+ else:
+ surf['nuse_tri'] = 0
+ surf['nuse'] = np.sum(surf['inuse'])
+ surf['vertno'] = np.where(surf['inuse'])[0]
+
+ # set some final params
+ inds = np.arange(surf['np'])
+ sizes = np.sqrt(np.sum(surf['nn'] ** 2, axis=1))
+ surf['nn'][inds] = surf['nn'][inds] / sizes[:, np.newaxis]
+ surf['inuse'][sizes <= 0] = False
+ surf['nuse'] = np.sum(surf['inuse'])
+ surf['subject_his_id'] = subject
+ return surf
+
+
def write_surface(fname, coords, faces, create_stamp=''):
"""Write a triangular Freesurfer surface mesh
@@ -372,23 +846,376 @@ def write_bem_surface(fname, surf):
# Create the file and save the essentials
fid = start_file(fname)
- start_block(fid, FIFFB_BEM)
- start_block(fid, FIFFB_BEM_SURF)
+ start_block(fid, FIFF.FIFFB_BEM)
+ start_block(fid, FIFF.FIFFB_BEM_SURF)
- write_int(fid, FIFF_BEM_SURF_ID, surf['id'])
- write_float(fid, FIFF_BEM_SIGMA, surf['sigma'])
- write_int(fid, FIFF_BEM_SURF_NNODE, surf['np'])
- write_int(fid, FIFF_BEM_SURF_NTRI, surf['ntri'])
- write_int(fid, FIFF_BEM_COORD_FRAME, surf['coord_frame'])
- write_float_matrix(fid, FIFF_BEM_SURF_NODES, surf['rr'])
+ write_int(fid, FIFF.FIFF_BEM_SURF_ID, surf['id'])
+ write_float(fid, FIFF.FIFF_BEM_SIGMA, surf['sigma'])
+ write_int(fid, FIFF.FIFF_BEM_SURF_NNODE, surf['np'])
+ write_int(fid, FIFF.FIFF_BEM_SURF_NTRI, surf['ntri'])
+ write_int(fid, FIFF.FIFF_BEM_COORD_FRAME, surf['coord_frame'])
+ write_float_matrix(fid, FIFF.FIFF_BEM_SURF_NODES, surf['rr'])
if 'nn' in surf and surf['nn'] is not None and len(surf['nn']) > 0:
write_float_matrix(fid, FIFF.FIFF_MNE_SOURCE_SPACE_NORMALS, surf['nn'])
# index start at 0 in Python
- write_int_matrix(fid, FIFF_BEM_SURF_TRIANGLES, surf['tris'] + 1)
+ write_int_matrix(fid, FIFF.FIFF_BEM_SURF_TRIANGLES, surf['tris'] + 1)
- end_block(fid, FIFFB_BEM_SURF)
- end_block(fid, FIFFB_BEM)
+ end_block(fid, FIFF.FIFFB_BEM_SURF)
+ end_block(fid, FIFF.FIFFB_BEM)
end_file(fid)
+
+
+def _decimate_surface(points, triangles, reduction):
+ """Aux function"""
+ if 'DISPLAY' not in os.environ and sys.platform != 'win32':
+ os.environ['ETS_TOOLKIT'] = 'null'
+ try:
+ from tvtk.api import tvtk
+ except ImportError:
+ raise ValueError('This function requires the TVTK package to be '
+ 'installed')
+ if triangles.max() > len(points) - 1:
+ raise ValueError('The triangles refer to undefined points. '
+ 'Please check your mesh.')
+ src = tvtk.PolyData(points=points, polys=triangles)
+ decimate = tvtk.QuadricDecimation(input=src, target_reduction=reduction)
+ decimate.update()
+ out = decimate.output
+ tris = out.polys.to_array()
+ # n-tuples + interleaved n-next -- reshape trick
+ return out.points.to_array(), tris.reshape(tris.size / 4, 4)[:, 1:]
+
+
+def decimate_surface(points, triangles, n_triangles):
+ """ Decimate surface data
+
+ Note. Requires TVTK to be installed for this to function.
+
+ Note. If an if an odd target number was requested,
+ the ``quadric decimation`` algorithm used results in the
+ next even number of triangles. For example a reduction request to 30001
+ triangles will result in 30000 triangles.
+
+ Parameters
+ ----------
+ points : ndarray
+ The surface to be decimated, a 3 x number of points array.
+ triangles : ndarray
+ The surface to be decimated, a 3 x number of triangles array.
+ n_triangles : int
+ The desired number of triangles.
+
+ Returns
+ -------
+ points : ndarray
+ The decimated points.
+ triangles : ndarray
+ The decimated triangles.
+ """
+
+ reduction = 1 - (float(n_triangles) / len(triangles))
+ return _decimate_surface(points, triangles, reduction)
+
+
+###############################################################################
+# Morph maps
+
+ at verbose
+def read_morph_map(subject_from, subject_to, subjects_dir=None,
+ verbose=None):
+ """Read morph map
+
+ Morph maps can be generated with mne_make_morph_maps. If one isn't
+ available, it will be generated automatically and saved to the
+ ``subjects_dir/morph_maps`` directory.
+
+ Parameters
+ ----------
+ subject_from : string
+ Name of the original subject as named in the SUBJECTS_DIR.
+ subject_to : string
+ Name of the subject on which to morph as named in the SUBJECTS_DIR.
+ subjects_dir : string
+ Path to SUBJECTS_DIR is not set in the environment.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ left_map, right_map : sparse matrix
+ The morph maps for the 2 hemispheres.
+ """
+ subjects_dir = get_subjects_dir(subjects_dir)
+
+ # First check for morph-map dir existence
+ mmap_dir = op.join(subjects_dir, 'morph-maps')
+ if not op.isdir(mmap_dir):
+ try:
+ os.mkdir(mmap_dir)
+ except:
+ logger.warn('Could not find or make morph map directory "%s"'
+ % mmap_dir)
+
+ # Does the file exist
+ fname = op.join(mmap_dir, '%s-%s-morph.fif' % (subject_from, subject_to))
+ if not op.exists(fname):
+ fname = op.join(mmap_dir, '%s-%s-morph.fif'
+ % (subject_to, subject_from))
+ if not op.exists(fname):
+ logger.warning('Morph map "%s" does not exist, '
+ 'creating it and saving it to disk (this may take '
+ 'a few minutes)' % fname)
+ logger.info('Creating morph map %s -> %s'
+ % (subject_from, subject_to))
+ mmap_1 = _make_morph_map(subject_from, subject_to, subjects_dir)
+ logger.info('Creating morph map %s -> %s'
+ % (subject_to, subject_from))
+ mmap_2 = _make_morph_map(subject_to, subject_from, subjects_dir)
+ try:
+ _write_morph_map(fname, subject_from, subject_to,
+ mmap_1, mmap_2)
+ except Exception as exp:
+ logger.warn('Could not write morph-map file "%s" (error: %s)'
+ % (fname, exp))
+ return mmap_1
+
+ f, tree, _ = fiff_open(fname)
+ with f as fid:
+ # Locate all maps
+ maps = dir_tree_find(tree, FIFF.FIFFB_MNE_MORPH_MAP)
+ if len(maps) == 0:
+ raise ValueError('Morphing map data not found')
+
+ # Find the correct ones
+ left_map = None
+ right_map = None
+ for m in maps:
+ tag = find_tag(fid, m, FIFF.FIFF_MNE_MORPH_MAP_FROM)
+ if tag.data == subject_from:
+ tag = find_tag(fid, m, FIFF.FIFF_MNE_MORPH_MAP_TO)
+ if tag.data == subject_to:
+ # Names match: which hemishere is this?
+ tag = find_tag(fid, m, FIFF.FIFF_MNE_HEMI)
+ if tag.data == FIFF.FIFFV_MNE_SURF_LEFT_HEMI:
+ tag = find_tag(fid, m, FIFF.FIFF_MNE_MORPH_MAP)
+ left_map = tag.data
+ logger.info(' Left-hemisphere map read.')
+ elif tag.data == FIFF.FIFFV_MNE_SURF_RIGHT_HEMI:
+ tag = find_tag(fid, m, FIFF.FIFF_MNE_MORPH_MAP)
+ right_map = tag.data
+ logger.info(' Right-hemisphere map read.')
+
+ if left_map is None:
+ raise ValueError('Left hemisphere map not found in %s' % fname)
+
+ if right_map is None:
+ raise ValueError('Left hemisphere map not found in %s' % fname)
+
+ return left_map, right_map
+
+
+def _write_morph_map(fname, subject_from, subject_to, mmap_1, mmap_2):
+ """Write a morph map to disk"""
+ fid = start_file(fname)
+ assert len(mmap_1) == 2
+ assert len(mmap_2) == 2
+ hemis = [FIFF.FIFFV_MNE_SURF_LEFT_HEMI, FIFF.FIFFV_MNE_SURF_RIGHT_HEMI]
+ for m, hemi in zip(mmap_1, hemis):
+ start_block(fid, FIFF.FIFFB_MNE_MORPH_MAP)
+ write_string(fid, FIFF.FIFF_MNE_MORPH_MAP_FROM, subject_from)
+ write_string(fid, FIFF.FIFF_MNE_MORPH_MAP_TO, subject_to)
+ write_int(fid, FIFF.FIFF_MNE_HEMI, hemi)
+ write_float_sparse_rcs(fid, FIFF.FIFF_MNE_MORPH_MAP, m)
+ end_block(fid, FIFF.FIFFB_MNE_MORPH_MAP)
+ for m, hemi in zip(mmap_2, hemis):
+ start_block(fid, FIFF.FIFFB_MNE_MORPH_MAP)
+ write_string(fid, FIFF.FIFF_MNE_MORPH_MAP_FROM, subject_to)
+ write_string(fid, FIFF.FIFF_MNE_MORPH_MAP_TO, subject_from)
+ write_int(fid, FIFF.FIFF_MNE_HEMI, hemi)
+ write_float_sparse_rcs(fid, FIFF.FIFF_MNE_MORPH_MAP, m)
+ end_block(fid, FIFF.FIFFB_MNE_MORPH_MAP)
+ end_file(fid)
+
+
+def _get_tri_dist(p, q, p0, q0, a, b, c, dist):
+ """Auxiliary function for getting the distance to a triangle edge"""
+ return np.sqrt((p - p0) * (p - p0) * a +
+ (q - q0) * (q - q0) * b +
+ (p - p0) * (q - q0) * c +
+ dist * dist)
+
+
+def _get_tri_supp_geom(tris, rr):
+ """Create supplementary geometry information using tris and rrs"""
+ r1 = rr[tris[:, 0], :]
+ r12 = rr[tris[:, 1], :] - r1
+ r13 = rr[tris[:, 2], :] - r1
+ r1213 = np.array([r12, r13]).swapaxes(0, 1)
+ a = np.sum(r12 * r12, axis=1)
+ b = np.sum(r13 * r13, axis=1)
+ c = np.sum(r12 * r13, axis=1)
+ mat = np.rollaxis(np.array([[b, -c], [-c, a]]), 2)
+ mat /= (a * b - c * c)[:, np.newaxis, np.newaxis]
+ nn = fast_cross_3d(r12, r13)
+ _normalize_vectors(nn)
+ return dict(r1=r1, r12=r12, r13=r13, r1213=r1213,
+ a=a, b=b, c=c, mat=mat, nn=nn)
+
+
+ at verbose
+def _make_morph_map(subject_from, subject_to, subjects_dir=None):
+ """Construct morph map from one subject to another
+
+ Note that this is close, but not exactly like the C version.
+ For example, parts are more accurate due to double precision,
+ so expect some small morph-map differences!
+
+ Note: This seems easily parallelizable, but the overhead
+ of pickling all the data structures makes it less efficient
+ than just running on a single core :(
+ """
+ subjects_dir = get_subjects_dir(subjects_dir)
+ morph_maps = list()
+
+ # add speedy short-circuit for self-maps
+ if subject_from == subject_to:
+ for hemi in ['lh', 'rh']:
+ fname = op.join(subjects_dir, subject_from, 'surf',
+ '%s.sphere.reg' % hemi)
+ from_pts = read_surface(fname, verbose=False)[0]
+ n_pts = len(from_pts)
+ morph_maps.append(sparse.eye(n_pts, n_pts, format='csr'))
+ return morph_maps
+
+ for hemi in ['lh', 'rh']:
+ # load surfaces and normalize points to be on unit sphere
+ fname = op.join(subjects_dir, subject_from, 'surf',
+ '%s.sphere.reg' % hemi)
+ from_pts, from_tris = read_surface(fname, verbose=False)
+ n_from_pts = len(from_pts)
+ _normalize_vectors(from_pts)
+ tri_geom = _get_tri_supp_geom(from_tris, from_pts)
+
+ fname = op.join(subjects_dir, subject_to, 'surf',
+ '%s.sphere.reg' % hemi)
+ to_pts = read_surface(fname, verbose=False)[0]
+ n_to_pts = len(to_pts)
+ _normalize_vectors(to_pts)
+
+ # from surface: get nearest neighbors, find triangles for each vertex
+ nn_pts_idx = _compute_nearest(from_pts, to_pts)
+ from_pt_tris = _triangle_neighbors(from_tris, len(from_pts))
+ from_pt_tris = [from_pt_tris[pt_idx] for pt_idx in nn_pts_idx]
+
+ # find triangle in which point lies and assoc. weights
+ nn_tri_inds = []
+ nn_tris_weights = []
+ for pt_tris, to_pt in zip(from_pt_tris, to_pts):
+ p, q, idx, dist = _find_nearest_tri_pt(pt_tris, to_pt, tri_geom)
+ nn_tri_inds.append(idx)
+ nn_tris_weights.extend([1. - (p + q), p, q])
+
+ nn_tris = from_tris[nn_tri_inds]
+ row_ind = np.repeat(np.arange(n_to_pts), 3)
+ this_map = sparse.csr_matrix((nn_tris_weights,
+ (row_ind, nn_tris.ravel())),
+ shape=(n_to_pts, n_from_pts))
+ morph_maps.append(this_map)
+
+ return morph_maps
+
+
+def _find_nearest_tri_pt(pt_tris, to_pt, tri_geom, run_all=False):
+ """Find nearest point mapping to a set of triangles
+
+ If run_all is False, if the point lies within a triangle, it stops.
+ If run_all is True, edges of other triangles are checked in case
+ those (somehow) are closer.
+ """
+ # The following dense code is equivalent to the following:
+ # rr = r1[pt_tris] - to_pts[ii]
+ # v1s = np.sum(rr * r12[pt_tris], axis=1)
+ # v2s = np.sum(rr * r13[pt_tris], axis=1)
+ # aas = a[pt_tris]
+ # bbs = b[pt_tris]
+ # ccs = c[pt_tris]
+ # dets = aas * bbs - ccs * ccs
+ # pp = (bbs * v1s - ccs * v2s) / dets
+ # qq = (aas * v2s - ccs * v1s) / dets
+ # pqs = np.array(pp, qq)
+
+ # This einsum is equivalent to doing:
+ # pqs = np.array([np.dot(x, y) for x, y in zip(r1213, r1-to_pt)])
+ r1 = tri_geom['r1'][pt_tris]
+ rrs = to_pt - r1
+ tri_nn = tri_geom['nn'][pt_tris]
+ vect = np.einsum('ijk,ik->ij', tri_geom['r1213'][pt_tris], rrs)
+ mats = tri_geom['mat'][pt_tris]
+ # This einsum is equivalent to doing:
+ # pqs = np.array([np.dot(m, v) for m, v in zip(mats, vect)]).T
+ pqs = np.einsum('ijk,ik->ji', mats, vect)
+ found = False
+ dists = np.sum(rrs * tri_nn, axis=1)
+
+ # There can be multiple (sadness), find closest
+ idx = np.where(np.all(pqs >= 0., axis=0))[0]
+ idx = idx[np.where(np.all(pqs[:, idx] <= 1., axis=0))[0]]
+ idx = idx[np.where(np.sum(pqs[:, idx], axis=0) < 1.)[0]]
+ dist = np.inf
+ if len(idx) > 0:
+ found = True
+ pt = idx[np.argmin(np.abs(dists[idx]))]
+ p, q = pqs[:, pt]
+ dist = dists[pt]
+ # re-reference back to original numbers
+ pt = pt_tris[pt]
+
+ if found is False or run_all is True:
+ # don't include ones that we might have found before
+ s = np.setdiff1d(np.arange(len(pt_tris)), idx) # ones to check sides
+ # Tough: must investigate the sides
+ pp, qq, ptt, distt = _nearest_tri_edge(pt_tris[s], to_pt, pqs[:, s],
+ dists[s], tri_geom)
+ if np.abs(distt) < np.abs(dist):
+ p, q, pt, dist = pp, qq, ptt, distt
+ return p, q, pt, dist
+
+
+def _nearest_tri_edge(pt_tris, to_pt, pqs, dist, tri_geom):
+ """Get nearest location from a point to the edge of a set of triangles"""
+ # We might do something intelligent here. However, for now
+ # it is ok to do it in the hard way
+ aa = tri_geom['a'][pt_tris]
+ bb = tri_geom['b'][pt_tris]
+ cc = tri_geom['c'][pt_tris]
+ pp = pqs[0]
+ qq = pqs[1]
+ # Find the nearest point from a triangle:
+ # Side 1 -> 2
+ p0 = np.minimum(np.maximum(pp + 0.5 * (qq * cc) / aa,
+ 0.0), 1.0)
+ q0 = np.zeros_like(p0)
+ # Side 2 -> 3
+ t1 = (0.5 * ((2.0 * aa - cc) * (1.0 - pp)
+ + (2.0 * bb - cc) * qq) / (aa + bb - cc))
+ t1 = np.minimum(np.maximum(t1, 0.0), 1.0)
+ p1 = 1.0 - t1
+ q1 = t1
+ # Side 1 -> 3
+ q2 = np.minimum(np.maximum(qq + 0.5 * (pp * cc)
+ / bb, 0.0), 1.0)
+ p2 = np.zeros_like(q2)
+
+ # figure out which one had the lowest distance
+ dist0 = _get_tri_dist(pp, qq, p0, q0, aa, bb, cc, dist)
+ dist1 = _get_tri_dist(pp, qq, p1, q1, aa, bb, cc, dist)
+ dist2 = _get_tri_dist(pp, qq, p2, q2, aa, bb, cc, dist)
+ pp = np.r_[p0, p1, p2]
+ qq = np.r_[q0, q1, q2]
+ dists = np.r_[dist0, dist1, dist2]
+ ii = np.argmin(np.abs(dists))
+ p, q, pt, dist = pp[ii], qq[ii], pt_tris[ii % len(pt_tris)], dists[ii]
+ return p, q, pt, dist
diff --git a/mne/tests/__init__.py b/mne/tests/__init__.py
index e69de29..bf0f249 100644
--- a/mne/tests/__init__.py
+++ b/mne/tests/__init__.py
@@ -0,0 +1,3 @@
+# need this for forward/test_make_forward.py
+from . import test_source_space
+
diff --git a/mne/tests/test_coreg.py b/mne/tests/test_coreg.py
new file mode 100644
index 0000000..844f09f
--- /dev/null
+++ b/mne/tests/test_coreg.py
@@ -0,0 +1,154 @@
+import os
+
+from nose.tools import assert_raises, assert_true
+import numpy as np
+from numpy.testing import assert_array_almost_equal, assert_array_less
+
+from mne.transforms import apply_trans, rotation, translation, scaling
+from mne.coreg import (fit_matched_points, fit_point_cloud,
+ _point_cloud_error, _decimate_points,
+ create_default_subject, scale_mri,
+ _is_mri_subject, scale_labels, scale_source_space)
+from mne.utils import requires_mne_fs_in_env, _TempDir, run_subprocess
+
+
+tempdir = _TempDir()
+
+
+ at requires_mne_fs_in_env
+def test_scale_mri():
+ """Test creating fsaverage and scaling it"""
+ # create fsaverage
+ create_default_subject(subjects_dir=tempdir)
+ is_mri = _is_mri_subject('fsaverage', tempdir)
+ assert_true(is_mri, "Creating fsaverage failed")
+
+ fid_path = os.path.join(tempdir, 'fsaverage', 'bem',
+ 'fsaverage-fiducials.fif')
+ os.remove(fid_path)
+ create_default_subject(update=True, subjects_dir=tempdir)
+ assert_true(os.path.exists(fid_path), "Updating fsaverage")
+
+ # create source space
+ path = os.path.join(tempdir, 'fsaverage', 'bem', 'fsaverage-ico-6-src.fif')
+ if not os.path.exists(path):
+ cmd = ['mne_setup_source_space', '--subject', 'fsaverage', '--ico',
+ '6']
+ env = os.environ.copy()
+ env['SUBJECTS_DIR'] = tempdir
+ run_subprocess(cmd, env=env)
+
+ # scale fsaverage
+ scale_mri('fsaverage', 'flachkopf', [1, .2, .8], True, subjects_dir=tempdir)
+ is_mri = _is_mri_subject('flachkopf', tempdir)
+ assert_true(is_mri, "Scaling fsaverage failed")
+ src_path = os.path.join(tempdir, 'flachkopf', 'bem',
+ 'flachkopf-ico-6-src.fif')
+ assert_true(os.path.exists(src_path), "Source space was not scaled")
+ scale_labels('flachkopf', subjects_dir=tempdir)
+
+ # scale source space separately
+ os.remove(src_path)
+ scale_source_space('flachkopf', 'ico-6', subjects_dir=tempdir)
+ assert_true(os.path.exists(src_path), "Source space was not scaled")
+
+
+
+def test_fit_matched_points():
+ """Test fit_matched_points: fitting two matching sets of points"""
+ tgt_pts = np.random.uniform(size=(6, 3))
+
+ # rotation only
+ trans = rotation(2, 6, 3)
+ src_pts = apply_trans(trans, tgt_pts)
+ trans_est = fit_matched_points(src_pts, tgt_pts, translate=False,
+ out='trans')
+ est_pts = apply_trans(trans_est, src_pts)
+ assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with "
+ "rotation")
+
+ # rotation & scaling
+ trans = np.dot(rotation(2, 6, 3), scaling(.5, .5, .5))
+ src_pts = apply_trans(trans, tgt_pts)
+ trans_est = fit_matched_points(src_pts, tgt_pts, translate=False, scale=1,
+ out='trans')
+ est_pts = apply_trans(trans_est, src_pts)
+ assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with "
+ "rotation and scaling.")
+
+ # rotation & translation
+ trans = np.dot(translation(2, -6, 3), rotation(2, 6, 3))
+ src_pts = apply_trans(trans, tgt_pts)
+ trans_est = fit_matched_points(src_pts, tgt_pts, out='trans')
+ est_pts = apply_trans(trans_est, src_pts)
+ assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with "
+ "rotation and translation.")
+
+ # rotation & translation & scaling
+ trans = reduce(np.dot, (translation(2, -6, 3), rotation(1.5, .3, 1.4),
+ scaling(.5, .5, .5)))
+ src_pts = apply_trans(trans, tgt_pts)
+ trans_est = fit_matched_points(src_pts, tgt_pts, scale=1, out='trans')
+ est_pts = apply_trans(trans_est, src_pts)
+ assert_array_almost_equal(tgt_pts, est_pts, 2, "fit_matched_points with "
+ "rotation, translation and scaling.")
+
+ # test exceeding tolerance
+ tgt_pts[0, :] += 20
+ assert_raises(RuntimeError, fit_matched_points, tgt_pts, src_pts, tol=10)
+
+
+def test_fit_point_cloud():
+ """Test fit_point_cloud: fitting a set of points to a point cloud"""
+ # evenly spaced target points on a sphere
+ u = np.linspace(0, np.pi, 150)
+ v = np.linspace(0, np.pi, 150)
+
+ x = np.outer(np.cos(u), np.sin(v)).reshape((-1, 1))
+ y = np.outer(np.sin(u), np.sin(v)).reshape((-1, 1))
+ z = np.outer(np.ones(np.size(u)), np.cos(v)).reshape((-1, 1)) * 3
+
+ tgt_pts = np.hstack((x, y, z))
+ tgt_pts = _decimate_points(tgt_pts, .05)
+
+ # pick some points to fit
+ some_tgt_pts = tgt_pts[::362]
+
+ # rotation only
+ trans = rotation(1.5, .3, -0.4)
+ src_pts = apply_trans(trans, some_tgt_pts)
+ trans_est = fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=False,
+ scale=0, out='trans')
+ est_pts = apply_trans(trans_est, src_pts)
+ err = _point_cloud_error(est_pts, tgt_pts)
+ assert_array_less(err, .1, "fit_point_cloud with rotation.")
+
+ # rotation and translation
+ trans = np.dot(rotation(0.5, .3, -0.4), translation(.3, .2, -.2))
+ src_pts = apply_trans(trans, some_tgt_pts)
+ trans_est = fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=True,
+ scale=0, out='trans')
+ est_pts = apply_trans(trans_est, src_pts)
+ err = _point_cloud_error(est_pts, tgt_pts)
+ assert_array_less(err, .1, "fit_point_cloud with rotation and "
+ "translation.")
+
+ # rotation and 1 scale parameter
+ trans = np.dot(rotation(0.5, .3, -0.4), scaling(1.5, 1.5, 1.5))
+ src_pts = apply_trans(trans, some_tgt_pts)
+ trans_est = fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=False,
+ scale=1, out='trans')
+ est_pts = apply_trans(trans_est, src_pts)
+ err = _point_cloud_error(est_pts, tgt_pts)
+ assert_array_less(err, .1, "fit_point_cloud with rotation and 1 scaling "
+ "parameter.")
+
+ # rotation and 3 scale parameter
+ trans = np.dot(rotation(0.5, .3, -0.4), scaling(1.5, 1.7, 1.1))
+ src_pts = apply_trans(trans, some_tgt_pts)
+ trans_est = fit_point_cloud(src_pts, tgt_pts, rotate=True, translate=False,
+ scale=3, out='trans')
+ est_pts = apply_trans(trans_est, src_pts)
+ err = _point_cloud_error(est_pts, tgt_pts)
+ assert_array_less(err, .1, "fit_point_cloud with rotation and 3 scaling "
+ "parameters.")
diff --git a/mne/tests/test_cov.py b/mne/tests/test_cov.py
index 0c3e8a3..b7b231a 100644
--- a/mne/tests/test_cov.py
+++ b/mne/tests/test_cov.py
@@ -12,12 +12,14 @@ from scipy import linalg
import warnings
from mne.cov import regularize, whiten_evoked
-from mne import read_cov, Epochs, merge_events, \
- find_events, compute_raw_data_covariance, \
- compute_covariance
+from mne import (read_cov, Epochs, merge_events,
+ find_events, compute_raw_data_covariance,
+ compute_covariance)
from mne.fiff import Raw, pick_channels_cov, pick_channels, Evoked, pick_types
from mne.utils import _TempDir
+warnings.simplefilter('always') # enable b/c these tests throw warnings
+
base_dir = op.join(op.dirname(__file__), '..', 'fiff', 'tests', 'data')
cov_fname = op.join(base_dir, 'test-cov.fif')
cov_gz_fname = op.join(base_dir, 'test-cov.fif.gz')
@@ -26,8 +28,6 @@ raw_fname = op.join(base_dir, 'test_raw.fif')
ave_fname = op.join(base_dir, 'test-ave.fif')
erm_cov_fname = op.join(base_dir, 'test_erm-cov.fif')
-raw = Raw(raw_fname, preload=True)
-
tempdir = _TempDir()
@@ -61,6 +61,7 @@ def test_io_cov():
def test_cov_estimation_on_raw_segment():
"""Test estimation from raw on continuous recordings (typically empty room)
"""
+ raw = Raw(raw_fname, preload=False)
cov = compute_raw_data_covariance(raw)
cov_mne = read_cov(erm_cov_fname)
assert_true(cov_mne.ch_names == cov.ch_names)
@@ -90,6 +91,7 @@ def test_cov_estimation_on_raw_segment():
def test_cov_estimation_with_triggers():
"""Test estimation from raw with triggers
"""
+ raw = Raw(raw_fname, preload=False)
events = find_events(raw, stim_channel='STI 014')
event_ids = [1, 2, 3, 4]
reject = dict(grad=10000e-13, mag=4e-12, eeg=80e-6, eog=150e-6)
@@ -145,10 +147,10 @@ def test_cov_estimation_with_triggers():
assert_raises(ValueError, compute_covariance, epochs)
assert_raises(ValueError, compute_covariance, epochs, projs=None)
# these should work, but won't be equal to above
- with warnings.catch_warnings(True) as w:
+ with warnings.catch_warnings(True) as w: # too few samples warning
cov = compute_covariance(epochs, projs=epochs[0].info['projs'])
cov = compute_covariance(epochs, projs=[])
- assert_true(len(w) == 1)
+ assert_true(len(w) == 2)
# test new dict support
epochs = Epochs(raw, events, dict(a=1, b=2, c=3, d=4), tmin=-0.2, tmax=0,
@@ -174,6 +176,7 @@ def test_arithmetic_cov():
def test_regularize_cov():
"""Test cov regularization
"""
+ raw = Raw(raw_fname, preload=False)
noise_cov = read_cov(cov_fname)
# Regularize noise cov
reg_noise_cov = regularize(noise_cov, raw.info,
@@ -190,7 +193,8 @@ def test_evoked_whiten():
###########################################################################
# Show result
- picks = pick_types(evoked.info, meg=True, eeg=True, exclude='bads')
+ picks = pick_types(evoked.info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
noise_cov = regularize(cov, evoked.info, grad=0.1, mag=0.1, eeg=0.1)
diff --git a/mne/tests/test_dipole.py b/mne/tests/test_dipole.py
index 5df53a1..d5314f4 100644
--- a/mne/tests/test_dipole.py
+++ b/mne/tests/test_dipole.py
@@ -4,10 +4,12 @@ from nose.tools import assert_true
from mne import read_dip
from mne.datasets import sample
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
dip_fname = op.join(data_path, 'MEG', 'sample',
'sample_audvis_set1.dip')
+
+ at sample.requires_sample_data
def test_io_dip():
"""Test IO for .dip files
"""
diff --git a/mne/tests/test_epochs.py b/mne/tests/test_epochs.py
index 222831f..ca7b03c 100644
--- a/mne/tests/test_epochs.py
+++ b/mne/tests/test_epochs.py
@@ -7,8 +7,9 @@ import os.path as op
from copy import deepcopy
from nose.tools import assert_true, assert_equal, assert_raises
-from numpy.testing import assert_array_equal, assert_array_almost_equal, \
- assert_allclose
+
+from numpy.testing import (assert_array_equal, assert_array_almost_equal,
+ assert_allclose)
import numpy as np
import copy as cp
import warnings
@@ -20,6 +21,8 @@ from mne.fiff import read_evoked
from mne.fiff.proj import _has_eeg_average_ref_proj
from mne.event import merge_events
+warnings.simplefilter('always') # enable b/c these tests throw warnings
+
base_dir = op.join(op.dirname(__file__), '..', 'fiff', 'tests', 'data')
raw_fname = op.join(base_dir, 'test_raw.fif')
event_name = op.join(base_dir, 'test-eve.fif')
@@ -27,7 +30,7 @@ evoked_nf_name = op.join(base_dir, 'test-nf-ave.fif')
event_id, tmin, tmax = 1, -0.2, 0.5
event_id_2 = 2
-raw = fiff.Raw(raw_fname)
+raw = fiff.Raw(raw_fname, add_eeg_ref=False)
events = read_events(event_name)
picks = fiff.pick_types(raw.info, meg=True, eeg=True, stim=True,
ecg=True, eog=True, include=['STI 014'],
@@ -69,6 +72,7 @@ def test_read_epochs_bad_events():
epochs = Epochs(raw, np.array([[raw.last_samp, 0, event_id]]),
event_id, tmin, tmax, picks=picks, baseline=(None, 0))
evoked = epochs.average()
+ assert evoked
def test_read_write_epochs():
@@ -148,6 +152,8 @@ def test_read_write_epochs():
# test copying loaded one (raw property)
epochs_read4 = epochs_read3.copy()
assert_array_almost_equal(epochs_read4.get_data(), data)
+ # test equalizing loaded one (drop_log property)
+ epochs_read4.equalize_event_counts(epochs.event_id)
def test_epochs_proj():
@@ -158,9 +164,9 @@ def test_epochs_proj():
eog=True, exclude=exclude)
epochs = Epochs(raw, events[:4], event_id, tmin, tmax, picks=this_picks,
baseline=(None, 0), proj=True)
- assert_true(all(p['active'] == True for p in epochs.info['projs']))
+ assert_true(all(p['active'] is True for p in epochs.info['projs']))
evoked = epochs.average()
- assert_true(all(p['active'] == True for p in evoked.info['projs']))
+ assert_true(all(p['active'] is True for p in evoked.info['projs']))
data = epochs.get_data()
raw_proj = fiff.Raw(raw_fname, proj=True)
@@ -168,10 +174,10 @@ def test_epochs_proj():
picks=this_picks, baseline=(None, 0), proj=False)
data_no_proj = epochs_no_proj.get_data()
- assert_true(all(p['active'] == True for p in epochs_no_proj.info['projs']))
+ assert_true(all(p['active'] is True for p in epochs_no_proj.info['projs']))
evoked_no_proj = epochs_no_proj.average()
- assert_true(all(p['active'] == True for p in evoked_no_proj.info['projs']))
- assert_true(epochs_no_proj.proj == True) # as projs are active from Raw
+ assert_true(all(p['active'] is True for p in evoked_no_proj.info['projs']))
+ assert_true(epochs_no_proj.proj is True) # as projs are active from Raw
assert_array_almost_equal(data, data_no_proj, decimal=8)
@@ -520,6 +526,50 @@ def test_epochs_copy():
assert_array_equal(data, copied_data)
+def test_iter_evoked():
+ """Test the iterator for epochs -> evoked
+ """
+ epochs = Epochs(raw, events[:5], event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0))
+
+ for ii, ev in enumerate(epochs.iter_evoked()):
+ x = ev.data
+ y = epochs.get_data()[ii, :, :]
+ assert_array_equal(x, y)
+
+
+def test_subtract_evoked():
+ """Test subtraction of Evoked from Epochs
+ """
+ epochs = Epochs(raw, events[:10], event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0))
+
+ # make sure subraction fails if data channels are missing
+ assert_raises(ValueError, epochs.subtract_evoked,
+ epochs.average(picks[:5]))
+
+ # do the subraction using the default argument
+ epochs.subtract_evoked()
+
+ # apply SSP now
+ epochs.apply_proj()
+
+ # use preloading and SSP from the start
+ epochs2 = Epochs(raw, events[:10], event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0), preload=True, proj=True)
+
+ evoked = epochs2.average()
+ epochs2.subtract_evoked(evoked)
+
+ # this gives the same result
+ assert_allclose(epochs.get_data(), epochs2.get_data())
+
+ # if we compute the evoked response after subtracting it we get zero
+ zero_evoked = epochs.average()
+ data = zero_evoked.data
+ assert_array_almost_equal(data, np.zeros_like(data), decimal=20)
+
+
@requires_nitime
def test_epochs_to_nitime():
"""Test test_to_nitime
@@ -728,8 +778,8 @@ def test_epochs_proj_mixin():
baseline=(None, 0), proj='delayed', preload=preload,
add_eeg_ref=True, verbose=True, reject=reject)
epochs2 = Epochs(raw, events[:4], event_id, tmin, tmax, picks=picks,
- baseline=(None, 0), proj=True, preload=preload,
- add_eeg_ref=True, reject=reject)
+ baseline=(None, 0), proj=True, preload=preload,
+ add_eeg_ref=True, reject=reject)
assert_allclose(epochs.copy().apply_proj().get_data()[0],
epochs2.get_data()[0])
@@ -754,3 +804,17 @@ def test_epochs_proj_mixin():
data = epochs.get_data().copy()
epochs.apply_proj()
assert_allclose(np.dot(epochs._projector, data[0]), epochs._data[0])
+
+
+def test_event_ordering():
+ """Test event order"""
+ events2 = events.copy()
+ np.random.shuffle(events2)
+ for ii, eve in enumerate([events, events2]):
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always', RuntimeWarning)
+ Epochs(raw, eve, event_id, tmin, tmax,
+ baseline=(None, 0), reject=reject, flat=flat)
+ assert_equal(len(w), ii)
+ if ii > 0:
+ assert_true('chronologically' in '%s' % w[-1].message)
diff --git a/mne/tests/test_event.py b/mne/tests/test_event.py
index 59396f7..73cf618 100644
--- a/mne/tests/test_event.py
+++ b/mne/tests/test_event.py
@@ -111,23 +111,26 @@ def test_find_events():
# Reset some data for ease of comparison
raw.first_samp = 0
raw.info['sfreq'] = 1000
- stim_channel = fiff.pick_channels(raw.info['ch_names'], include='STI 014')
+
+ stim_channel = 'STI 014'
+ stim_channel_idx = fiff.pick_channels(raw.info['ch_names'],
+ include=stim_channel)
# test empty events channel
- raw._data[stim_channel, :] = 0
+ raw._data[stim_channel_idx, :] = 0
assert_array_equal(find_events(raw), np.empty((0, 3), dtype='int32'))
- raw._data[stim_channel, :4] = 1
+ raw._data[stim_channel_idx, :4] = 1
assert_array_equal(find_events(raw), np.empty((0, 3), dtype='int32'))
- raw._data[stim_channel, -1:] = 9
+ raw._data[stim_channel_idx, -1:] = 9
assert_array_equal(find_events(raw), [[14399, 0, 9]])
# Test that we can handle consecutive events with no gap
- raw._data[stim_channel, 10:20] = 5
- raw._data[stim_channel, 20:30] = 6
- raw._data[stim_channel, 30:32] = 5
- raw._data[stim_channel, 40] = 6
+ raw._data[stim_channel_idx, 10:20] = 5
+ raw._data[stim_channel_idx, 20:30] = 6
+ raw._data[stim_channel_idx, 30:32] = 5
+ raw._data[stim_channel_idx, 40] = 6
assert_array_equal(find_events(raw, consecutive=False),
[[10, 0, 5],
@@ -187,22 +190,25 @@ def test_find_events():
[20, 5, 6]])
# test find_stim_steps merge parameter
- raw._data[stim_channel, :] = 0
- raw._data[stim_channel, 0] = 1
- raw._data[stim_channel, 10] = 4
- raw._data[stim_channel, 11:20] = 5
- assert_array_equal(find_stim_steps(raw, pad_start=0, merge=0),
- [[ 0, 0, 1],
- [ 1, 1, 0],
+ raw._data[stim_channel_idx, :] = 0
+ raw._data[stim_channel_idx, 0] = 1
+ raw._data[stim_channel_idx, 10] = 4
+ raw._data[stim_channel_idx, 11:20] = 5
+ assert_array_equal(find_stim_steps(raw, pad_start=0, merge=0,
+ stim_channel=stim_channel),
+ [[0, 0, 1],
+ [1, 1, 0],
[10, 0, 4],
[11, 4, 5],
[20, 5, 0]])
- assert_array_equal(find_stim_steps(raw, merge= -1),
- [[ 1, 1, 0],
+ assert_array_equal(find_stim_steps(raw, merge=-1,
+ stim_channel=stim_channel),
+ [[1, 1, 0],
[10, 0, 5],
[20, 5, 0]])
- assert_array_equal(find_stim_steps(raw, merge=1),
- [[ 1, 1, 0],
+ assert_array_equal(find_stim_steps(raw, merge=1,
+ stim_channel=stim_channel),
+ [[1, 1, 0],
[11, 0, 5],
[20, 5, 0]])
diff --git a/mne/tests/test_filter.py b/mne/tests/test_filter.py
index cafb690..56b0230 100644
--- a/mne/tests/test_filter.py
+++ b/mne/tests/test_filter.py
@@ -5,14 +5,15 @@ import os.path as op
import warnings
from scipy.signal import resample as sp_resample
-from mne.filter import band_pass_filter, high_pass_filter, low_pass_filter, \
- band_stop_filter, resample, construct_iir_filter, \
- notch_filter, detrend
+from mne.filter import (band_pass_filter, high_pass_filter, low_pass_filter,
+ band_stop_filter, resample, construct_iir_filter,
+ notch_filter, detrend)
from mne import set_log_file
-from mne.utils import _TempDir
+from mne.utils import _TempDir, sum_squared
from mne.cuda import requires_cuda
+warnings.simplefilter('always') # enable b/c these tests throw warnings
tempdir = _TempDir()
log_file = op.join(tempdir, 'temp_log.txt')
@@ -24,12 +25,12 @@ def test_notch_filters():
# let's use an ugly, prime Fs for fun
Fs = 487.0
sig_len_secs = 20
- t = np.arange(0, sig_len_secs * Fs) / Fs
+ t = np.arange(0, int(sig_len_secs * Fs)) / Fs
freqs = np.arange(60, 241, 60)
# make a "signal"
rng = np.random.RandomState(0)
- a = rng.randn(sig_len_secs * Fs)
+ a = rng.randn(int(sig_len_secs * Fs))
orig_power = np.sqrt(np.mean(a ** 2))
# make line noise
a += np.sum([np.sin(2 * np.pi * f * t) for f in freqs], axis=0)
@@ -55,7 +56,7 @@ def test_notch_filters():
raise ValueError('Detected frequencies not logged properly')
out = np.fromstring(out[1], sep=', ')
assert_array_almost_equal(out, freqs)
- new_power = np.sqrt(np.mean(b ** 2))
+ new_power = np.sqrt(sum_squared(b) / b.size)
assert_almost_equal(new_power, orig_power, tol)
@@ -73,6 +74,8 @@ def test_filters():
filter_length=fl)
for nj in ['blah', 0.5, 0]:
assert_raises(ValueError, band_pass_filter, a, Fs, 4, 8, n_jobs=nj)
+ assert_raises(ValueError, band_pass_filter, a, Fs, 4, Fs / 2.) # > Nyq/2
+ assert_raises(ValueError, low_pass_filter, a, Fs, Fs / 2.) # > Nyq/2
# check our short-filter warning:
with warnings.catch_warnings(record=True) as w:
# Warning for low attenuation
diff --git a/mne/tests/test_label.py b/mne/tests/test_label.py
index df217e8..b7fd56b 100644
--- a/mne/tests/test_label.py
+++ b/mne/tests/test_label.py
@@ -2,31 +2,43 @@ import os
import os.path as op
import cPickle as pickle
import glob
+import warnings
import numpy as np
from numpy.testing import assert_array_equal, assert_array_almost_equal
from nose.tools import assert_true, assert_raises
from mne.datasets import sample
-from mne import label_time_courses, read_label, stc_to_label, \
- read_source_estimate, read_source_spaces, grow_labels, \
- labels_from_parc
+from mne import (label_time_courses, read_label, stc_to_label,
+ read_source_estimate, read_source_spaces, grow_labels,
+ labels_from_parc, parc_from_labels)
from mne.label import Label
from mne.utils import requires_mne, run_subprocess, _TempDir
from mne.fixes import in1d
+warnings.simplefilter('always') # enable b/c these tests throw warnings
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
subjects_dir = op.join(data_path, 'subjects')
stc_fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis-meg-lh.stc')
-label = 'Aud-lh'
-label_fname = op.join(data_path, 'MEG', 'sample', 'labels', '%s.label' % label)
-label_rh_fname = op.join(data_path, 'MEG', 'sample', 'labels', 'Aud-rh.label')
+real_label_fname = op.join(data_path, 'MEG', 'sample', 'labels',
+ 'Aud-lh.label')
+real_label_rh_fname = op.join(data_path, 'MEG', 'sample', 'labels',
+ 'Aud-rh.label')
src_fname = op.join(data_path, 'MEG', 'sample',
'sample_audvis-eeg-oct-6p-fwd.fif')
+test_path = op.join(op.split(__file__)[0], '..', 'fiff', 'tests', 'data')
+label_fname = op.join(test_path, 'test-lh.label')
+label_rh_fname = op.join(test_path, 'test-rh.label')
tempdir = _TempDir()
+# This code was used to generate the "fake" test labels:
+#for hemi in ['lh', 'rh']:
+# label = Label(np.unique((np.random.rand(100) * 10242).astype(int)),
+# hemi=hemi, comment='Test ' + hemi, subject='fsaverage')
+# label.save(op.join(test_path, 'test-%s.label' % hemi))
+
def assert_labels_equal(l0, l1, decimal=5):
for attr in ['comment', 'hemi', 'subject']:
@@ -87,10 +99,11 @@ def test_label_addition():
assert_labels_equal(bhl.lh, l01)
+ at sample.requires_sample_data
def test_label_io_and_time_course_estimates():
"""Test IO for label + stc files
"""
- values, times, vertices = label_time_courses(label_fname, stc_fname)
+ values, times, vertices = label_time_courses(real_label_fname, stc_fname)
assert_true(len(times) == values.shape[1])
assert_true(len(vertices) == values.shape[0])
@@ -122,8 +135,9 @@ def _assert_labels_equal(labels_a, labels_b, ignore_pos=False):
assert_array_equal(label_a.pos, label_b.pos)
+ at sample.requires_sample_data
def test_labels_from_parc():
- """Test reading labels from parcellation
+ """Test reading labels from FreeSurfer parcellation
"""
# test some invalid inputs
assert_raises(ValueError, labels_from_parc, 'sample', hemi='bla',
@@ -172,17 +186,19 @@ def test_labels_from_parc():
# test regexp
label = labels_from_parc('sample', parc='aparc.a2009s', regexp='Angu',
- subjects_dir=subjects_dir)[0][0]
+ subjects_dir=subjects_dir)[0][0]
assert_true(label.name == 'G_pariet_inf-Angular-lh')
+ # silly, but real regexp:
label = labels_from_parc('sample', parc='aparc.a2009s',
- regexp='.*-.{4,}_.{3,3}-L', # silly, but real regexp
- subjects_dir=subjects_dir)[0][0]
+ regexp='.*-.{4,}_.{3,3}-L',
+ subjects_dir=subjects_dir)[0][0]
assert_true(label.name == 'G_oc-temp_med-Lingual-lh')
assert_raises(RuntimeError, labels_from_parc, 'sample', parc='aparc',
- annot_fname=annot_fname, regexp='JackTheRipper',
- subjects_dir=subjects_dir)
+ annot_fname=annot_fname, regexp='JackTheRipper',
+ subjects_dir=subjects_dir)
+ at sample.requires_sample_data
@requires_mne
def test_labels_from_parc_annot2labels():
"""Test reading labels from parc. by comparing with mne_annot2labels
@@ -214,6 +230,53 @@ def test_labels_from_parc_annot2labels():
_assert_labels_equal(labels, labels_mne, ignore_pos=True)
+ at sample.requires_sample_data
+def test_parc_from_labels():
+ """Test writing FreeSurfer parcellation from labels"""
+
+ labels, colors = labels_from_parc('sample', subjects_dir=subjects_dir)
+
+ # write left and right hemi labels:
+ fnames = ['%s/%s-myparc' % (tempdir, hemi) for hemi in ['lh', 'rh']]
+
+ for fname in fnames:
+ parc_from_labels(labels, colors, annot_fname=fname)
+
+ # read it back
+ labels2, colors2 = labels_from_parc('sample', subjects_dir=subjects_dir,
+ annot_fname=fnames[0])
+ labels22, colors22 = labels_from_parc('sample', subjects_dir=subjects_dir,
+ annot_fname=fnames[1])
+ labels2.extend(labels22)
+ colors2.extend(colors22)
+
+ names = [label.name for label in labels2]
+
+ for label, color in zip(labels, colors):
+ idx = names.index(label.name)
+ assert_labels_equal(label, labels2[idx])
+ assert_array_almost_equal(np.array(color), np.array(colors2[idx]))
+
+ # make sure we can't overwrite things
+ assert_raises(ValueError, parc_from_labels, labels, colors,
+ annot_fname=fnames[0])
+
+ # however, this works
+ parc_from_labels(labels, colors=None, annot_fname=fnames[0],
+ overwrite=True)
+
+ # test some other invalid inputs
+ assert_raises(ValueError, parc_from_labels, labels[:-1], colors,
+ annot_fname=fnames[0], overwrite=True)
+ colors2 = np.asarray(colors)
+ assert_raises(ValueError, parc_from_labels, labels, colors2[:, :3],
+ annot_fname=fnames[0], overwrite=True)
+ colors2[0] = 1.1
+ assert_raises(ValueError, parc_from_labels, labels, colors2,
+ annot_fname=fnames[0], overwrite=True)
+
+
+ at sample.requires_sample_data
def test_stc_to_label():
"""Test stc_to_label
"""
@@ -221,16 +284,28 @@ def test_stc_to_label():
stc = read_source_estimate(stc_fname, 'sample')
os.environ['SUBJECTS_DIR'] = op.join(data_path, 'subjects')
labels1 = stc_to_label(stc, src='sample', smooth=3)
- labels2 = stc_to_label(stc, src=src, smooth=3)
+ with warnings.catch_warnings(True) as w: # connectedness warning
+ labels2 = stc_to_label(stc, src=src, smooth=3)
+ assert_true(len(w) == 1)
assert_true(len(labels1) == len(labels2))
for l1, l2 in zip(labels1, labels2):
assert_labels_equal(l1, l2, decimal=4)
+ with warnings.catch_warnings(True) as w: # connectedness warning
+ labels_lh, labels_rh = stc_to_label(stc, src=src, smooth=3,
+ connected=True)
+ assert_true(len(w) == 1)
+ assert_raises(ValueError, stc_to_label, stc, 'sample', smooth=3,
+ connected=True)
+ assert_true(len(labels_lh) == 1)
+ assert_true(len(labels_rh) == 1)
+
+ at sample.requires_sample_data
def test_morph():
"""Test inter-subject label morphing
"""
- label_orig = read_label(label_fname)
+ label_orig = read_label(real_label_fname)
label_orig.subject = 'sample'
# should work for specifying vertices for both hemis, or just the
# hemi of the given label
@@ -251,36 +326,41 @@ def test_morph():
# make sure label smoothing can run
label.morph(label.subject, 'fsaverage', 5,
[np.arange(10242), np.arange(10242)], subjects_dir, 2,
- copy=False)
+ copy=False)
# subject name should be inferred now
- label.smooth()
+ label.smooth(subjects_dir=subjects_dir)
+ at sample.requires_sample_data
def test_grow_labels():
"""Test generation of circular source labels"""
seeds = [0, 50000]
+ # these were chosen manually in mne_analyze
+ should_be_in = [[49, 227], [51207, 48794]]
hemis = [0, 1]
- labels = grow_labels('sample', seeds, 3, hemis)
+ labels = grow_labels('sample', seeds, 3, hemis, n_jobs=2)
- for label, seed, hemi in zip(labels, seeds, hemis):
+ for label, seed, hemi, sh in zip(labels, seeds, hemis, should_be_in):
assert(np.any(label.vertices == seed))
+ assert np.all(in1d(sh, label.vertices))
if hemi == 0:
assert(label.hemi == 'lh')
else:
assert(label.hemi == 'rh')
+ at sample.requires_sample_data
def test_label_time_course():
"""Test extracting label data from SourceEstimate"""
- values, times, vertices = label_time_courses(label_fname, stc_fname)
+ values, times, vertices = label_time_courses(real_label_fname, stc_fname)
stc = read_source_estimate(stc_fname)
- label_lh = read_label(label_fname)
+ label_lh = read_label(real_label_fname)
stc_lh = stc.in_label(label_lh)
assert_array_almost_equal(stc_lh.data, values)
assert_array_almost_equal(stc_lh.times, times)
assert_array_almost_equal(stc_lh.vertno[0], vertices)
- label_rh = read_label(label_rh_fname)
+ label_rh = read_label(real_label_rh_fname)
stc_rh = stc.in_label(label_rh)
label_bh = label_rh + label_lh
stc_bh = stc.in_label(label_bh)
diff --git a/mne/tests/test_misc.py b/mne/tests/test_misc.py
index 0c1008b..467d569 100644
--- a/mne/tests/test_misc.py
+++ b/mne/tests/test_misc.py
@@ -4,7 +4,7 @@ from nose.tools import assert_true
from mne.misc import parse_config
ave_fname = op.join(op.dirname(__file__), '..', 'fiff', 'tests', 'data',
- 'test.ave')
+ 'test.ave')
def test_parse_ave():
diff --git a/mne/tests/test_proj.py b/mne/tests/test_proj.py
index 6e7303a..2468ca7 100644
--- a/mne/tests/test_proj.py
+++ b/mne/tests/test_proj.py
@@ -12,10 +12,12 @@ from mne.datasets import sample
from mne.fiff import Raw, pick_types
from mne import compute_proj_epochs, compute_proj_evoked, compute_proj_raw
from mne.fiff.proj import make_projector, activate_proj
-from mne.proj import read_proj, write_proj
+from mne.proj import read_proj, write_proj, make_eeg_average_ref_proj
from mne import read_events, Epochs, sensitivity_map, read_source_estimate
from mne.utils import _TempDir
+warnings.simplefilter('always') # enable b/c these tests throw warnings
+
base_dir = op.join(op.dirname(__file__), '..', 'fiff', 'tests', 'data')
raw_fname = op.join(base_dir, 'test_raw.fif')
event_fname = op.join(base_dir, 'test-eve.fif')
@@ -23,7 +25,7 @@ proj_fname = op.join(base_dir, 'test_proj.fif')
proj_gz_fname = op.join(base_dir, 'test_proj.fif.gz')
bads_fname = op.join(base_dir, 'test_bads.txt')
-data_path = sample.data_path()
+data_path = sample.data_path(download=False)
sample_path = op.join(data_path, 'MEG', 'sample')
fwd_fname = op.join(sample_path, 'sample_audvis-meg-eeg-oct-6-fwd.fif')
sensmap_fname = op.join(sample_path, 'sample_audvis-%s-oct-6-fwd-sensmap-%s.w')
@@ -32,6 +34,7 @@ eog_fname = op.join(sample_path, 'sample_audvis_eog_proj.fif')
tempdir = _TempDir()
+ at sample.requires_sample_data
def test_sensitivity_maps():
"""Test sensitivity map computation"""
fwd = mne.read_forward_solution(fwd_fname, surf_ori=True)
@@ -66,6 +69,10 @@ def test_sensitivity_maps():
ch_type=ch_type, exclude='bads')
assert_array_almost_equal(stc.data, w, decim)
+ # test corner case for EEG
+ stc = sensitivity_map(fwd, projs=[make_eeg_average_ref_proj(fwd['info'])],
+ ch_type='eeg', exclude='bads')
+
def test_compute_proj_epochs():
"""Test SSP computation on epochs"""
diff --git a/mne/tests/test_source_estimate.py b/mne/tests/test_source_estimate.py
index cc98102..18f866a 100644
--- a/mne/tests/test_source_estimate.py
+++ b/mne/tests/test_source_estimate.py
@@ -4,35 +4,42 @@ import warnings
from copy import deepcopy
import numpy as np
-from numpy.testing import assert_array_almost_equal, assert_array_equal, \
- assert_allclose
+from numpy.testing import (assert_array_almost_equal, assert_array_equal,
+ assert_allclose, assert_equal)
from scipy.fftpack import fft
from mne.datasets import sample
-from mne import stats, SourceEstimate, Label
+from mne import (stats, SourceEstimate, VolSourceEstimate, Label,
+ read_source_spaces)
from mne import read_source_estimate, morph_data, extract_label_time_course
-from mne.source_estimate import spatio_temporal_tris_connectivity, \
- spatio_temporal_src_connectivity, \
- compute_morph_matrix, grade_to_vertices, \
- _compute_nearest
+from mne.source_estimate import (spatio_temporal_tris_connectivity,
+ spatio_temporal_src_connectivity,
+ compute_morph_matrix, grade_to_vertices)
from mne.minimum_norm import read_inverse_operator
from mne.label import labels_from_parc, label_sign_flip
-from mne.utils import _TempDir, requires_pandas
+from mne.utils import _TempDir, requires_pandas, requires_sklearn
-data_path = sample.data_path()
+warnings.simplefilter('always') # enable b/c these tests throw warnings
+
+data_path = sample.data_path(download=False)
subjects_dir = op.join(data_path, 'subjects')
fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis-meg-lh.stc')
fname_inv = op.join(data_path, 'MEG', 'sample',
'sample_audvis-meg-oct-6-meg-inv.fif')
fname_vol = op.join(data_path, 'MEG', 'sample',
'sample_audvis-grad-vol-7-fwd-sensmap-vol.w')
+fname_vsrc = op.join(data_path, 'MEG', 'sample',
+ 'sample_audvis-meg-vol-7-fwd.fif')
+fname_t1 = op.join(data_path, 'subjects', 'sample', 'mri', 'T1.mgz')
+
tempdir = _TempDir()
+ at sample.requires_sample_data
def test_volume_stc():
- """Test reading and writing volume STCs
+ """Test volume STCs
"""
N = 100
data = np.arange(N)[:, np.newaxis]
@@ -41,18 +48,19 @@ def test_volume_stc():
vertnos = [vertno, vertno[:, np.newaxis], np.arange(2)[:, np.newaxis]]
vertno_reads = [vertno, vertno, np.arange(2)]
for data, vertno, vertno_read in zip(datas, vertnos, vertno_reads):
- stc = SourceEstimate(data, vertno, 0, 1)
- assert_true(stc.is_surface() is False)
+ stc = VolSourceEstimate(data, vertno, 0, 1)
fname_temp = op.join(tempdir, 'temp-vl.stc')
stc_new = stc
for _ in xrange(2):
stc_new.save(fname_temp)
stc_new = read_source_estimate(fname_temp)
- assert_true(stc_new.is_surface() is False)
+ assert_true(isinstance(stc_new, VolSourceEstimate))
assert_array_equal(vertno_read, stc_new.vertno)
assert_array_almost_equal(stc.data, stc_new.data)
# now let's actually read a MNE-C processed file
stc = read_source_estimate(fname_vol, 'sample')
+ assert_true(isinstance(stc, VolSourceEstimate))
+
assert_true('sample' in repr(stc))
stc_new = stc
assert_raises(ValueError, stc.save, fname_vol, ftype='whatever')
@@ -60,11 +68,39 @@ def test_volume_stc():
fname_temp = op.join(tempdir, 'temp-vol.w')
stc_new.save(fname_temp, ftype='w')
stc_new = read_source_estimate(fname_temp)
- assert_true(stc_new.is_surface() is False)
+ assert_true(isinstance(stc_new, VolSourceEstimate))
assert_array_equal(stc.vertno, stc_new.vertno)
assert_array_almost_equal(stc.data, stc_new.data)
-
+ # save the stc as a nifti file and export
+ try:
+ import nibabel as nib
+ src = read_source_spaces(fname_vsrc)
+ vol_fname = op.join(tempdir, 'stc.nii.gz')
+ stc.save_as_volume(vol_fname, src,
+ dest='surf', mri_resolution=False)
+ img = nib.load(vol_fname)
+ assert_true(img.shape == src[0]['shape'] + (len(stc.times),))
+
+ t1_img = nib.load(fname_t1)
+ stc.save_as_volume(op.join(tempdir, 'stc.nii.gz'), src,
+ dest='mri', mri_resolution=True)
+ img = nib.load(vol_fname)
+ assert_true(img.shape == t1_img.shape + (len(stc.times),))
+ assert_array_almost_equal(img.get_affine(), t1_img.get_affine(),
+ decimal=5)
+
+ # export without saving
+ img = stc.as_volume(src, dest='mri', mri_resolution=True)
+ assert_true(img.shape == t1_img.shape + (len(stc.times),))
+ assert_array_almost_equal(img.get_affine(), t1_img.get_affine(),
+ decimal=5)
+
+ except ImportError:
+ print 'Save as nifti test skipped, needs NiBabel'
+
+
+ at sample.requires_sample_data
def test_expand():
"""Test stc expansion
"""
@@ -81,6 +117,7 @@ def test_expand():
assert_raises(ValueError, stc.__add__, stc.in_label(labels_lh[0]))
+ at sample.requires_sample_data
def test_io_stc():
"""Test IO for STC files
"""
@@ -96,6 +133,7 @@ def test_io_stc():
assert_array_almost_equal(stc.tstep, stc2.tstep)
+ at sample.requires_sample_data
def test_io_w():
"""Test IO for w files
"""
@@ -113,6 +151,7 @@ def test_io_w():
assert_array_almost_equal(src.rh_vertno, src2.rh_vertno)
+ at sample.requires_sample_data
def test_stc_arithmetic():
"""Test arithmetic for STC files
"""
@@ -139,7 +178,11 @@ def test_stc_arithmetic():
assert_array_equal(out[0], out[1].data)
assert_array_equal(stc.sqrt().data, np.sqrt(stc.data))
+ stc_mean = stc.mean()
+ assert_array_equal(stc_mean.data, np.mean(stc.data, 1)[:, None])
+
+ at sample.requires_sample_data
def test_stc_methods():
"""Test stc methods lh_data, rh_data, bin(), center_of_mass(), resample()
"""
@@ -158,7 +201,7 @@ def test_stc_methods():
assert_raises(ValueError, stc.center_of_mass, 'sample')
stc.lh_data[:] = 0
- vertex, hemi, t = stc.center_of_mass('sample')
+ vertex, hemi, t = stc.center_of_mass('sample', subjects_dir=subjects_dir)
assert_true(hemi == 1)
# XXX Should design a fool-proof test case, but here were the results:
assert_true(vertex == 90186)
@@ -177,6 +220,7 @@ def test_stc_methods():
assert_array_almost_equal(stc_new.data, stc.data, 5)
+ at sample.requires_sample_data
def test_extract_label_time_course():
"""Test extraction of label time courses from stc
"""
@@ -266,20 +310,7 @@ def test_extract_label_time_course():
assert_true(x.size == 0)
-def test_compute_nearest():
- """Test nearest neighbor searches"""
- x = np.random.randn(500, 3)
- x /= np.sqrt(np.sum(x ** 2, axis=1))[:, None]
- nn_true = np.random.permutation(np.arange(500, dtype=np.int))[:20]
- y = x[nn_true]
-
- nn1 = _compute_nearest(x, y, use_balltree=False)
- nn2 = _compute_nearest(x, y, use_balltree=True)
-
- assert_array_equal(nn_true, nn1)
- assert_array_equal(nn_true, nn2)
-
-
+ at sample.requires_sample_data
def test_morph_data():
"""Test morphing of data
"""
@@ -292,23 +323,26 @@ def test_morph_data():
# make sure we can specify grade
stc_from.crop(0.09, 0.1) # for faster computation
stc_to.crop(0.09, 0.1) # for faster computation
- stc_to1 = stc_from.morph(subject_to, grade=3, smooth=12, buffer_size=1000)
+ stc_to1 = stc_from.morph(subject_to, grade=3, smooth=12, buffer_size=1000,
+ subjects_dir=subjects_dir)
stc_to1.save(op.join(tempdir, '%s_audvis-meg' % subject_to))
# make sure we can specify vertices
vertices_to = grade_to_vertices(subject_to, grade=3)
stc_to2 = morph_data(subject_from, subject_to, stc_from,
- grade=vertices_to, smooth=12, buffer_size=1000)
+ grade=vertices_to, smooth=12, buffer_size=1000,
+ subjects_dir=subjects_dir)
# make sure we can use different buffer_size
stc_to3 = morph_data(subject_from, subject_to, stc_from,
- grade=vertices_to, smooth=12, buffer_size=3)
- # indexing silliness here due to mne_make_movie's indexing oddities
+ grade=vertices_to, smooth=12, buffer_size=3,
+ subjects_dir=subjects_dir)
+
assert_array_almost_equal(stc_to.data, stc_to1.data, 5)
assert_array_almost_equal(stc_to1.data, stc_to2.data)
assert_array_almost_equal(stc_to1.data, stc_to3.data)
# make sure precomputed morph matrices work
morph_mat = compute_morph_matrix(subject_from, subject_to,
stc_from.vertno, vertices_to,
- smooth=12)
+ smooth=12, subjects_dir=subjects_dir)
stc_to3 = stc_from.morph_precomputed(subject_to, vertices_to, morph_mat)
assert_array_almost_equal(stc_to1.data, stc_to3.data)
@@ -317,10 +351,19 @@ def test_morph_data():
assert_true(np.corrcoef(mean_to, mean_from).min() > 0.999)
# make sure we can fill by morphing
- stc_to5 = morph_data(subject_from, subject_to, stc_from,
- grade=None, smooth=12, buffer_size=3)
+ stc_to5 = morph_data(subject_from, subject_to, stc_from, grade=None,
+ smooth=12, buffer_size=3, subjects_dir=subjects_dir)
assert_true(stc_to5.data.shape[0] == 163842 + 163842)
+ # test morphing to the same subject
+ stc_to6 = stc_from.morph(subject_from, grade=stc_from.vertno, smooth=1,
+ subjects_dir=subjects_dir)
+ mask = np.ones(stc_from.data.shape[0], dtype=np.bool)
+ # XXX: there is a bug somewhere that causes a difference at 2 vertices..
+ mask[6799] = False
+ mask[6800] = False
+ assert_array_almost_equal(stc_from.data[mask], stc_to6.data[mask], 5)
+
def _my_trans(data):
"""FFT that adds an additional dimension by repeating result"""
@@ -351,14 +394,65 @@ def test_transform_data():
data_f, _ = _my_trans(data[idx_use, tmin_idx:tmax_idx])
for stc_data in (data, (kernel, sens_data)):
- stc = SourceEstimate(stc_data, vertices=vertices,
- tmin=0., tstep=1.)
+ stc = VolSourceEstimate(stc_data, vertices=vertices,
+ tmin=0., tstep=1.)
stc_data_t = stc.transform_data(_my_trans, idx=idx,
tmin_idx=tmin_idx,
tmax_idx=tmax_idx)
assert_allclose(data_f, stc_data_t)
+def test_transform():
+ """Test applying linear (time) transform to data"""
+ # make up some data
+ n_sensors, n_verts_lh, n_verts_rh, n_times = 10, 10, 10, 10
+ vertices = [np.arange(n_verts_lh), n_verts_lh + np.arange(n_verts_rh)]
+ data = np.random.randn(n_verts_lh + n_verts_rh, n_times)
+ stc = SourceEstimate(data, vertices=vertices, tmin=-0.1, tstep=0.1)
+
+ # data_t.ndim > 2 & copy is True
+ stcs_t = stc.transform(_my_trans, copy=True)
+ assert_true(isinstance(stcs_t, list))
+ assert_array_equal(stc.times, stcs_t[0].times)
+ assert_equal(stc.vertno, stcs_t[0].vertno)
+
+ data = np.concatenate((stcs_t[0].data[:, :, None],
+ stcs_t[1].data[:, :, None]), axis=2)
+ data_t = stc.transform_data(_my_trans)
+ assert_array_equal(data, data_t) # check against stc.transform_data()
+
+ # data_t.ndim > 2 & copy is False
+ assert_raises(ValueError, stc.transform, _my_trans, copy=False)
+
+ # data_t.ndim = 2 & copy is True
+ tmp = deepcopy(stc)
+ stc_t = stc.transform(np.abs, copy=True)
+ assert_true(isinstance(stc_t, SourceEstimate))
+ assert_array_equal(stc.data, tmp.data) # xfrm doesn't modify original?
+
+ # data_t.ndim = 2 & copy is False
+ times = np.round(1000 * stc.times)
+ verts = np.arange(len(stc.lh_vertno),
+ len(stc.lh_vertno) + len(stc.rh_vertno), 1)
+ verts_rh = stc.rh_vertno
+ t_idx = [np.where(times >= -50)[0][0], np.where(times <= 500)[0][-1]]
+ data_t = stc.transform_data(np.abs, idx=verts, tmin_idx=t_idx[0],
+ tmax_idx=t_idx[-1])
+ stc.transform(np.abs, idx=verts, tmin=-50, tmax=500, copy=False)
+ assert_true(isinstance(stc, SourceEstimate))
+ assert_true((stc.tmin == 0.) & (stc.times[-1] == 0.5))
+ assert_true(len(stc.vertno[0]) == 0)
+ assert_equal(stc.vertno[1], verts_rh)
+ assert_array_equal(stc.data, data_t)
+
+ times = np.round(1000 * stc.times)
+ t_idx = [np.where(times >= 0)[0][0], np.where(times <= 250)[0][-1]]
+ data_t = stc.transform_data(np.abs, tmin_idx=t_idx[0], tmax_idx=t_idx[-1])
+ stc.transform(np.abs, tmin=0, tmax=250, copy=False)
+ assert_true((stc.tmin == 0.) & (stc.times[-1] == 0.2))
+ assert_array_equal(stc.data, data_t)
+
+
def test_notify_array_source_estimate():
"""Test that modifying the stc data removes the kernel and sensor data"""
# make up some data
@@ -367,8 +461,8 @@ def test_notify_array_source_estimate():
sens_data = np.random.randn(n_sensors, n_times)
vertices = np.arange(n_vertices)
- stc = SourceEstimate((kernel, sens_data), vertices=vertices,
- tmin=0., tstep=1.)
+ stc = VolSourceEstimate((kernel, sens_data), vertices=vertices,
+ tmin=0., tstep=1.)
assert_true(stc._data is None)
assert_true(stc._kernel is not None)
@@ -384,6 +478,7 @@ def test_notify_array_source_estimate():
assert_true(stc._sens_data is None)
+ at requires_sklearn
def test_spatio_temporal_tris_connectivity():
"""Test spatio-temporal connectivity from triangles"""
tris = np.array([[0, 1, 2], [3, 4, 5]])
@@ -400,6 +495,7 @@ def test_spatio_temporal_tris_connectivity():
assert_array_equal(c, n)
+ at sample.requires_sample_data
def test_spatio_temporal_src_connectivity():
"""Test spatio-temporal connectivity from source spaces"""
tris = np.array([[0, 1, 2], [3, 4, 5]])
@@ -421,8 +517,8 @@ def test_spatio_temporal_src_connectivity():
# add test for source space connectivity with omitted vertices
inverse_operator = read_inverse_operator(fname_inv)
with warnings.catch_warnings(record=True) as w:
- connectivity = spatio_temporal_src_connectivity(
- inverse_operator['src'], n_times=2)
+ src_ = inverse_operator['src']
+ connectivity = spatio_temporal_src_connectivity(src_, n_times=2)
assert len(w) == 1
a = connectivity.shape[0] / 2
b = sum([s['nuse'] for s in inverse_operator['src']])
@@ -432,12 +528,19 @@ def test_spatio_temporal_src_connectivity():
@requires_pandas
def test_as_data_frame():
"""Test stc Pandas exporter"""
- fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis-meg')
- stc = read_source_estimate(fname, subject='sample')
- assert_raises(ValueError, stc.as_data_frame, index=['foo', 'bar'])
- for ncat, ind in zip([1, 0], ['time', ['subject', 'time']]):
- df = stc.as_data_frame(index=ind)
- assert_true(df.index.names == ind if isinstance(ind, list) else [ind])
- assert_array_equal(df.values.T[ncat:], stc.data)
- # test that non-indexed data were present as categorial variables
- df.reset_index().columns[:3] == ['subject', 'time']
+ n_vert, n_times = 10, 5
+ vertices = [np.arange(n_vert, dtype=np.int), np.empty(0, dtype=np.int)]
+ data = np.random.randn(n_vert, n_times)
+ stc_surf = SourceEstimate(data, vertices=vertices, tmin=0, tstep=1,
+ subject='sample')
+ stc_vol = VolSourceEstimate(data, vertices=vertices[0], tmin=0, tstep=1,
+ subject='sample')
+ for stc in [stc_surf, stc_vol]:
+ assert_raises(ValueError, stc.as_data_frame, index=['foo', 'bar'])
+ for ncat, ind in zip([1, 0], ['time', ['subject', 'time']]):
+ df = stc.as_data_frame(index=ind)
+ assert_true(df.index.names == ind
+ if isinstance(ind, list) else [ind])
+ assert_array_equal(df.values.T[ncat:], stc.data)
+ # test that non-indexed data were present as categorial variables
+ df.reset_index().columns[:3] == ['subject', 'time']
diff --git a/mne/tests/test_source_space.py b/mne/tests/test_source_space.py
index 4e291fa..a9a475e 100644
--- a/mne/tests/test_source_space.py
+++ b/mne/tests/test_source_space.py
@@ -1,26 +1,281 @@
+import os
import os.path as op
-from nose.tools import assert_true
+from nose.tools import assert_true, assert_raises
+from nose.plugins.skip import SkipTest
import numpy as np
-from numpy.testing import assert_array_equal, assert_allclose
+from numpy.testing import assert_array_equal, assert_allclose, assert_equal
+import warnings
from mne.datasets import sample
-from mne import read_source_spaces, vertex_to_mni, write_source_spaces
-from mne.utils import _TempDir, requires_fs_or_nibabel, requires_nibabel, \
- requires_freesurfer
+from mne import (read_source_spaces, vertex_to_mni, write_source_spaces,
+ setup_source_space, setup_volume_source_space,
+ add_source_space_distances)
+from mne.utils import (_TempDir, requires_fs_or_nibabel, requires_nibabel,
+ requires_freesurfer, run_subprocess,
+ requires_mne, requires_scipy_version)
+from mne.surface import _accumulate_normals, _triangle_neighbors
-data_path = sample.data_path()
-fname = op.join(data_path, 'subjects', 'sample', 'bem', 'sample-oct-6-src.fif')
-fname_nodist = op.join(data_path, 'subjects', 'sample', 'bem',
- 'sample-oct-6-orig-src.fif')
+from scipy.spatial.distance import cdist
+
+# WARNING: test_source_space is imported by forward, so download=False
+# is critical here, otherwise on first import of MNE users will have to
+# download the whole sample dataset!
+data_path = sample.data_path(download=False)
+subjects_dir = op.join(data_path, 'subjects')
+fname = op.join(subjects_dir, 'sample', 'bem', 'sample-oct-6-src.fif')
+fname_bem = op.join(data_path, 'subjects', 'sample', 'bem',
+ 'sample-5120-bem.fif')
+fname_mri = op.join(data_path, 'subjects', 'sample', 'mri', 'T1.mgz')
tempdir = _TempDir()
+ at sample.requires_sample_data
+ at requires_scipy_version('0.11')
+def test_add_source_space_distances_limited():
+ """Test adding distances to source space with a dist_limit"""
+ src = read_source_spaces(fname)
+ src_new = read_source_spaces(fname)
+ del src_new[0]['dist']
+ del src_new[1]['dist']
+ n_do = 200 # limit this for speed
+ src_new[0]['vertno'] = src_new[0]['vertno'][:n_do].copy()
+ src_new[1]['vertno'] = src_new[1]['vertno'][:n_do].copy()
+ out_name = op.join(tempdir, 'temp.src')
+ try:
+ add_source_space_distances(src_new, dist_limit=0.007)
+ except RuntimeError: # what we throw when scipy version is wrong
+ raise SkipTest('dist_limit requires scipy > 0.13')
+ write_source_spaces(out_name, src_new)
+ src_new = read_source_spaces(out_name)
+
+ for so, sn in zip(src, src_new):
+ assert_array_equal(so['dist_limit'], np.array([-0.007], np.float32))
+ assert_array_equal(sn['dist_limit'], np.array([0.007], np.float32))
+ do = so['dist']
+ dn = sn['dist']
+
+ # clean out distances > 0.007 in C code
+ do.data[do.data > 0.007] = 0
+ do.eliminate_zeros()
+
+ # make sure we have some comparable distances
+ assert_true(np.sum(do.data < 0.007) > 400)
+
+ # do comparison over the region computed
+ d = (do - dn)[:sn['vertno'][n_do - 1]][:, :sn['vertno'][n_do - 1]]
+ assert_allclose(np.zeros_like(d.data), d.data, rtol=0, atol=1e-6)
+
+
+ at sample.requires_sample_data
+ at requires_scipy_version('0.11')
+def test_add_source_space_distances():
+ """Test adding distances to source space"""
+ src = read_source_spaces(fname)
+ src_new = read_source_spaces(fname)
+ del src_new[0]['dist']
+ del src_new[1]['dist']
+ n_do = 20 # limit this for speed
+ src_new[0]['vertno'] = src_new[0]['vertno'][:n_do].copy()
+ src_new[1]['vertno'] = src_new[1]['vertno'][:n_do].copy()
+ out_name = op.join(tempdir, 'temp.src')
+ add_source_space_distances(src_new)
+ write_source_spaces(out_name, src_new)
+ src_new = read_source_spaces(out_name)
+
+ # iterate over both hemispheres
+ for so, sn in zip(src, src_new):
+ v = so['vertno'][:n_do]
+ assert_array_equal(so['dist_limit'], np.array([-0.007], np.float32))
+ assert_array_equal(sn['dist_limit'], np.array([np.inf], np.float32))
+ do = so['dist']
+ dn = sn['dist']
+
+ # clean out distances > 0.007 in C code (some residual), and Python
+ ds = list()
+ for d in [do, dn]:
+ d.data[d.data > 0.007] = 0
+ d = d[v][:, v]
+ d.eliminate_zeros()
+ ds.append(d)
+
+ # make sure we actually calculated some comparable distances
+ assert_true(np.sum(ds[0].data < 0.007) > 10)
+
+ # do comparison
+ d = ds[0] - ds[1]
+ assert_allclose(np.zeros_like(d.data), d.data, rtol=0, atol=1e-9)
+
+
+ at sample.requires_sample_data
+ at requires_mne
+def test_discrete_source_space():
+ """Test setting up (and reading/writing) discrete source spaces
+ """
+ src = read_source_spaces(fname)
+ v = src[0]['vertno']
+
+ # let's make a discrete version with the C code, and with ours
+ temp_name = op.join(tempdir, 'temp-src.fif')
+ try:
+ # save
+ temp_pos = op.join(tempdir, 'temp-pos.txt')
+ np.savetxt(temp_pos, np.c_[src[0]['rr'][v], src[0]['nn'][v]])
+ # let's try the spherical one (no bem or surf supplied)
+ run_subprocess(['mne_volume_source_space', '--meters',
+ '--pos', temp_pos, '--src', temp_name])
+ src_c = read_source_spaces(temp_name)
+ src_new = setup_volume_source_space('sample', None,
+ pos=dict(rr=src[0]['rr'][v],
+ nn=src[0]['nn'][v]),
+ subjects_dir=subjects_dir)
+ _compare_source_spaces(src_c, src_new, mode='approx')
+ assert_allclose(src[0]['rr'][v], src_new[0]['rr'],
+ rtol=1e-3, atol=1e-6)
+ assert_allclose(src[0]['nn'][v], src_new[0]['nn'],
+ rtol=1e-3, atol=1e-6)
+
+ # now do writing
+ write_source_spaces(temp_name, src_c)
+ src_c2 = read_source_spaces(temp_name)
+ _compare_source_spaces(src_c, src_c2)
+ finally:
+ if op.isfile(temp_name):
+ os.remove(temp_name)
+
+
+ at sample.requires_sample_data
+ at requires_mne
+ at requires_nibabel(vox2ras_tkr=True)
+def test_volume_source_space():
+ """Test setting up volume source spaces
+ """
+ fname_vol = op.join(data_path, 'subjects', 'sample', 'bem',
+ 'volume-7mm-src.fif')
+ src = read_source_spaces(fname_vol)
+ temp_name = op.join(tempdir, 'temp-src.fif')
+ try:
+ # The one in the sample dataset (uses bem as bounds)
+ src_new = setup_volume_source_space('sample', temp_name, pos=7.0,
+ bem=fname_bem, mri=fname_mri,
+ subjects_dir=subjects_dir)
+ _compare_source_spaces(src, src_new, mode='approx')
+ src_new = read_source_spaces(temp_name)
+ _compare_source_spaces(src, src_new, mode='approx')
+
+ # let's try the spherical one (no bem or surf supplied)
+ run_subprocess(['mne_volume_source_space',
+ '--grid', '15.0',
+ '--src', temp_name,
+ '--mri', fname_mri])
+ src = read_source_spaces(temp_name)
+ src_new = setup_volume_source_space('sample', temp_name, pos=15.0,
+ mri=fname_mri,
+ subjects_dir=subjects_dir)
+ _compare_source_spaces(src, src_new, mode='approx')
+
+ # now without MRI argument, it should give an error when we try
+ # to read it
+ run_subprocess(['mne_volume_source_space',
+ '--grid', '15.0',
+ '--src', temp_name])
+ assert_raises(ValueError, read_source_spaces, temp_name)
+ finally:
+ if op.isfile(temp_name):
+ os.remove(temp_name)
+
+
+ at sample.requires_sample_data
+def test_triangle_neighbors():
+ """Test efficient vertex neighboring triangles for surfaces"""
+ this = read_source_spaces(fname)[0]
+ this['neighbor_tri'] = [list() for _ in xrange(this['np'])]
+ for p in xrange(this['ntri']):
+ verts = this['tris'][p]
+ this['neighbor_tri'][verts[0]].append(p)
+ this['neighbor_tri'][verts[1]].append(p)
+ this['neighbor_tri'][verts[2]].append(p)
+ this['neighbor_tri'] = [np.array(nb, int) for nb in this['neighbor_tri']]
+
+ neighbor_tri = _triangle_neighbors(this['tris'], this['np'])
+ assert_true(np.array_equal(nt1, nt2)
+ for nt1, nt2 in zip(neighbor_tri, this['neighbor_tri']))
+
+
+def test_accumulate_normals():
+ """Test efficient normal accumulation for surfaces"""
+ # set up comparison
+ rng = np.random.RandomState(0)
+ n_pts = int(1.6e5) # approx number in sample source space
+ n_tris = int(3.2e5)
+ # use all positive to make a worst-case for cumulative summation
+ # (real "nn" vectors will have both positive and negative values)
+ tris = (rng.rand(n_tris, 1) * (n_pts - 2)).astype(int)
+ tris = np.c_[tris, tris + 1, tris + 2]
+ tri_nn = rng.rand(n_tris, 3)
+ this = dict(tris=tris, np=n_pts, ntri=n_tris, tri_nn=tri_nn)
+
+ # cut-and-paste from original code in surface.py:
+ # Find neighboring triangles and accumulate vertex normals
+ this['nn'] = np.zeros((this['np'], 3))
+ for p in xrange(this['ntri']):
+ # vertex normals
+ verts = this['tris'][p]
+ this['nn'][verts, :] += this['tri_nn'][p, :]
+ nn = _accumulate_normals(this['tris'], this['tri_nn'], this['np'])
+
+ # the moment of truth (or reckoning)
+ assert_allclose(nn, this['nn'], rtol=1e-7, atol=1e-7)
+
+
+ at sample.requires_sample_data
+def test_setup_source_space():
+ """Test setting up ico, oct, and all source spaces
+ """
+ fname_all = op.join(data_path, 'subjects', 'sample', 'bem',
+ 'sample-all-src.fif')
+ fname_ico = op.join(data_path, 'subjects', 'fsaverage', 'bem',
+ 'fsaverage-ico-5-src.fif')
+ # first lets test some input params
+ assert_raises(ValueError, setup_source_space, 'sample', spacing='oct')
+ assert_raises(ValueError, setup_source_space, 'sample', spacing='octo')
+ assert_raises(ValueError, setup_source_space, 'sample', spacing='oct6e')
+ assert_raises(ValueError, setup_source_space, 'sample', spacing='7emm')
+ assert_raises(ValueError, setup_source_space, 'sample', spacing='alls')
+ assert_raises(IOError, setup_source_space, 'sample', spacing='oct6',
+ subjects_dir=subjects_dir)
+
+ # ico 5 (fsaverage) - write to temp file
+ src = read_source_spaces(fname_ico)
+ temp_name = op.join(tempdir, 'temp-src.fif')
+ with warnings.catch_warnings(True): # sklearn equiv neighbors
+ src_new = setup_source_space('fsaverage', temp_name, spacing='ico5',
+ subjects_dir=subjects_dir)
+ _compare_source_spaces(src, src_new, mode='approx')
+
+ # oct-6 (sample) - auto filename + IO
+ src = read_source_spaces(fname)
+ temp_name = op.join(tempdir, 'temp-src.fif')
+ with warnings.catch_warnings(True): # sklearn equiv neighbors
+ src_new = setup_source_space('sample', temp_name, spacing='oct6',
+ subjects_dir=subjects_dir,
+ overwrite=True)
+ _compare_source_spaces(src, src_new, mode='approx')
+ src_new = read_source_spaces(temp_name)
+ _compare_source_spaces(src, src_new, mode='approx')
+
+ # all source points - no file writing
+ src = read_source_spaces(fname_all)
+ src_new = setup_source_space('sample', None, spacing='all',
+ subjects_dir=subjects_dir)
+ _compare_source_spaces(src, src_new, mode='approx')
+
+
+ at sample.requires_sample_data
def test_read_source_spaces():
"""Test reading of source space meshes
"""
src = read_source_spaces(fname, add_geom=True)
- print src
# 3D source space
lh_points = src[0]['rr']
@@ -39,37 +294,101 @@ def test_read_source_spaces():
assert_true(rh_use_faces.max() <= rh_points.shape[0] - 1)
+ at sample.requires_sample_data
def test_write_source_space():
"""Test writing and reading of source spaces
"""
src0 = read_source_spaces(fname, add_geom=False)
- src0_old = read_source_spaces(fname, add_geom=False)
write_source_spaces(op.join(tempdir, 'tmp.fif'), src0)
src1 = read_source_spaces(op.join(tempdir, 'tmp.fif'), add_geom=False)
- for orig in [src0, src0_old]:
- for s0, s1 in zip(src0, src1):
- for name in ['nuse', 'dist_limit', 'ntri', 'np', 'type', 'id',
- 'subject_his_id']:
- assert_true(s0[name] == s1[name])
- for name in ['nn', 'rr', 'inuse', 'vertno', 'nuse_tri',
- 'coord_frame', 'use_tris', 'tris', 'nearest',
- 'nearest_dist']:
+ _compare_source_spaces(src0, src1)
+
+
+def _compare_source_spaces(src0, src1, mode='exact'):
+ """Compare two source spaces
+
+ Note: this function is also used by forward/tests/test_make_forward.py
+ """
+ for s0, s1 in zip(src0, src1):
+ for name in ['nuse', 'ntri', 'np', 'type', 'id']:
+ print name
+ assert_equal(s0[name], s1[name])
+ for name in ['subject_his_id']:
+ if name in s0 or name in s1:
+ print name
+ assert_equal(s0[name], s1[name])
+ for name in ['interpolator']:
+ if name in s0 or name in s1:
+ print name
+ diffs = (s0['interpolator'] - s1['interpolator']).data
+ assert_true(np.sqrt(np.mean(diffs ** 2)) < 0.05) # 5%
+ for name in ['nn', 'rr', 'nuse_tri', 'coord_frame', 'tris']:
+ print name
+ if s0[name] is None:
+ assert_true(s1[name] is None)
+ else:
+ if mode == 'exact':
+ assert_array_equal(s0[name], s1[name])
+ elif mode == 'approx':
+ assert_allclose(s0[name], s1[name], rtol=1e-3, atol=1e-4)
+ else:
+ raise RuntimeError('unknown mode')
+ if mode == 'exact':
+ for name in ['inuse', 'vertno', 'use_tris']:
assert_array_equal(s0[name], s1[name])
+ # these fields will exist if patch info was added, these are
+ # not tested in mode == 'approx'
+ for name in ['nearest', 'nearest_dist']:
+ print name
+ if s0[name] is None:
+ assert_true(s1[name] is None)
+ else:
+ assert_array_equal(s0[name], s1[name])
+ for name in ['dist_limit']:
+ print name
+ assert_true(s0[name] == s1[name])
for name in ['dist']:
if s0[name] is not None:
- assert_true(s1[name].shape == s0[name].shape)
+ assert_equal(s1[name].shape, s0[name].shape)
assert_true(len((s0['dist'] - s1['dist']).data) == 0)
for name in ['pinfo']:
if s0[name] is not None:
assert_true(len(s0[name]) == len(s1[name]))
for p1, p2 in zip(s0[name], s1[name]):
assert_true(all(p1 == p2))
- # The above "if s0[name] is not None" can be removed once the sample
- # dataset is updated to have a source space with distance info
+ elif mode == 'approx':
+ # deal with vertno, inuse, and use_tris carefully
+ assert_array_equal(s0['vertno'], np.where(s0['inuse'])[0])
+ assert_array_equal(s1['vertno'], np.where(s1['inuse'])[0])
+ assert_equal(len(s0['vertno']), len(s1['vertno']))
+ agreement = np.mean(s0['inuse'] == s1['inuse'])
+ assert_true(agreement > 0.99)
+ if agreement < 1.0:
+ # make sure mismatched vertno are within 1.5mm
+ v0 = np.setdiff1d(s0['vertno'], s1['vertno'])
+ v1 = np.setdiff1d(s1['vertno'], s0['vertno'])
+ dists = cdist(s0['rr'][v0], s1['rr'][v1])
+ assert_allclose(np.min(dists, axis=1), np.zeros(len(v0)),
+ atol=1.5e-3)
+ if s0['use_tris'] is not None: # for "spacing"
+ assert_array_equal(s0['use_tris'].shape, s1['use_tris'].shape)
+ else:
+ assert_true(s1['use_tris'] is None)
+ assert_true(np.mean(s0['use_tris'] == s1['use_tris']) > 0.99)
+ # The above "if s0[name] is not None" can be removed once the sample
+ # dataset is updated to have a source space with distance info
for name in ['working_dir', 'command_line']:
- assert_true(src0.info[name] == src1.info[name])
+ if mode == 'exact':
+ assert_equal(src0.info[name], src1.info[name])
+ elif mode == 'approx':
+ print name
+ if name in src0.info:
+ assert_true(name in src1.info)
+ else:
+ assert_true(name not in src1.info)
+ at sample.requires_sample_data
@requires_fs_or_nibabel
def test_vertex_to_mni():
"""Test conversion of vertices to MNI coordinates
@@ -87,8 +406,9 @@ def test_vertex_to_mni():
assert_allclose(coords, coords_2, atol=1.0)
+ at sample.requires_sample_data
@requires_freesurfer
- at requires_nibabel
+ at requires_nibabel()
def test_vertex_to_mni_fs_nibabel():
"""Test equivalence of vert_to_mni for nibabel and freesurfer
"""
diff --git a/mne/tests/test_surface.py b/mne/tests/test_surface.py
index 2f96bd3..48da08b 100644
--- a/mne/tests/test_surface.py
+++ b/mne/tests/test_surface.py
@@ -1,19 +1,71 @@
import os.path as op
+import numpy as np
-from numpy.testing import assert_array_equal, assert_array_almost_equal
+from numpy.testing import (assert_array_equal, assert_array_almost_equal,
+ assert_allclose, assert_equal)
+
+from nose.tools import assert_true, assert_raises
from mne.datasets import sample
-from mne import read_bem_surfaces, write_bem_surface, read_surface, \
- write_surface
-from mne.utils import _TempDir
+from mne import (read_bem_surfaces, write_bem_surface, read_surface,
+ write_surface, decimate_surface)
+from mne.surface import (_make_morph_map, read_morph_map, _compute_nearest,
+ fast_cross_3d)
+from mne.utils import _TempDir, requires_tvtk
-data_path = sample.data_path()
-fname = op.join(data_path, 'subjects', 'sample', 'bem',
+data_path = sample.data_path(download=False)
+subjects_dir = op.join(data_path, 'subjects')
+fname = op.join(subjects_dir, 'sample', 'bem',
'sample-5120-5120-5120-bem-sol.fif')
-
tempdir = _TempDir()
+def test_huge_cross():
+ """Test cross product with lots of elements
+ """
+ x = np.random.rand(100000, 3)
+ y = np.random.rand(1, 3)
+ z = np.cross(x, y)
+ zz = fast_cross_3d(x, y)
+ assert_array_equal(z, zz)
+
+
+def test_compute_nearest():
+ """Test nearest neighbor searches"""
+ x = np.random.randn(500, 3)
+ x /= np.sqrt(np.sum(x ** 2, axis=1))[:, None]
+ nn_true = np.random.permutation(np.arange(500, dtype=np.int))[:20]
+ y = x[nn_true]
+
+ nn1 = _compute_nearest(x, y, use_balltree=False)
+ nn2 = _compute_nearest(x, y, use_balltree=True)
+ assert_array_equal(nn_true, nn1)
+ assert_array_equal(nn_true, nn2)
+
+ # test distance support
+ nnn1 = _compute_nearest(x, y, use_balltree=False, return_dists=True)
+ nnn2 = _compute_nearest(x, y, use_balltree=True, return_dists=True)
+ assert_array_equal(nnn1[0], nn_true)
+ assert_array_equal(nnn1[1], np.zeros_like(nn1)) # all dists should be 0
+ assert_equal(len(nnn1), len(nnn2))
+ for nn1, nn2 in zip(nnn1, nnn2):
+ assert_array_equal(nn1, nn2)
+
+
+ at sample.requires_sample_data
+def test_make_morph_maps():
+ """Test reading and creating morph maps
+ """
+ mmap = read_morph_map('fsaverage', 'sample', subjects_dir=subjects_dir)
+ mmap2 = _make_morph_map('fsaverage', 'sample', subjects_dir=subjects_dir)
+ assert_equal(len(mmap), len(mmap2))
+ for m1, m2 in zip(mmap, mmap2):
+ # deal with sparse matrix stuff
+ diff = (m1 - m2).data
+ assert_allclose(diff, np.zeros_like(diff), atol=1e-3, rtol=0)
+
+
+ at sample.requires_sample_data
def test_io_bem_surfaces():
"""Test reading of bem surfaces
"""
@@ -29,6 +81,7 @@ def test_io_bem_surfaces():
assert_array_almost_equal(surf[0][key], surf_read[0][key])
+ at sample.requires_sample_data
def test_io_surface():
"""Test reading and writing of Freesurfer surface mesh files
"""
@@ -38,3 +91,20 @@ def test_io_surface():
c_pts, c_tri = read_surface(op.join(tempdir, 'tmp'))
assert_array_equal(pts, c_pts)
assert_array_equal(tri, c_tri)
+
+
+ at requires_tvtk
+def test_decimate_surface():
+ """Test triangular surface decimation
+ """
+ points = np.array([[-0.00686118, -0.10369860, 0.02615170],
+ [-0.00713948, -0.10370162, 0.02614874],
+ [-0.00686208, -0.10368247, 0.02588313],
+ [-0.00713987, -0.10368724, 0.02587745]])
+ tris = np.array([[0, 1, 2], [1, 2, 3], [0, 3, 1], [1, 2, 0]])
+ for n_tri in [4, 3, 2]: # quadric decimation creates even numbered output.
+ _, this_tris = decimate_surface(points, tris, n_tri)
+ assert_true(len(this_tris) == n_tri if not n_tri % 2 else 2)
+ nirvana = 5
+ tris = np.array([[0, 1, 2], [1, 2, 3], [0, 3, 1], [1, 2, nirvana]])
+ assert_raises(ValueError, decimate_surface, points, tris, n_tri)
diff --git a/mne/tests/test_transforms.py b/mne/tests/test_transforms.py
new file mode 100644
index 0000000..a21e486
--- /dev/null
+++ b/mne/tests/test_transforms.py
@@ -0,0 +1,62 @@
+from math import pi
+import os.path as op
+
+from nose.tools import assert_true
+from numpy.testing import assert_array_equal, assert_equal, assert_allclose
+
+from mne.datasets import sample
+from mne import read_trans, write_trans
+from mne.utils import _TempDir
+from mne.transforms import (_get_mri_head_t_from_trans_file, invert_transform,
+ rotation, rotation3d, rotation_angles)
+
+data_path = sample.data_path(download=False)
+fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw-trans.fif')
+fname_trans = op.join(op.split(__file__)[0], '..', 'fiff', 'tests',
+ 'data', 'sample-audvis-raw-trans.txt')
+
+tempdir = _TempDir()
+
+
+ at sample.requires_sample_data
+def test_get_mri_head_t():
+ """Test converting '-trans.txt' to '-trans.fif'"""
+ trans = read_trans(fname)
+ trans = invert_transform(trans) # starts out as head->MRI, so invert
+ trans_2 = _get_mri_head_t_from_trans_file(fname_trans)
+ assert_equal(trans['from'], trans_2['from'])
+ assert_equal(trans['to'], trans_2['to'])
+ assert_allclose(trans['trans'], trans_2['trans'], rtol=1e-5, atol=1e-5)
+
+
+ at sample.requires_sample_data
+def test_io_trans():
+ """Test reading and writing of trans files
+ """
+ info0 = read_trans(fname)
+ fname1 = op.join(tempdir, 'test-trans.fif')
+ write_trans(fname1, info0)
+ info1 = read_trans(fname1)
+
+ # check all properties
+ assert_true(info0['from'] == info1['from'])
+ assert_true(info0['to'] == info1['to'])
+ assert_array_equal(info0['trans'], info1['trans'])
+ for d0, d1 in zip(info0['dig'], info1['dig']):
+ assert_array_equal(d0['r'], d1['r'])
+ for name in ['kind', 'ident', 'coord_frame']:
+ assert_true(d0[name] == d1[name])
+
+
+def test_rotation():
+ """Test conversion between rotation angles and transformation matrix"""
+ tests = [(0, 0, 1), (.5, .5, .5), (pi, 0, -1.5)]
+ for rot in tests:
+ x, y, z = rot
+ m = rotation3d(x, y, z)
+ m4 = rotation(x, y, z)
+ assert_array_equal(m, m4[:3, :3])
+ back = rotation_angles(m)
+ assert_equal(back, rot)
+ back4 = rotation_angles(m4)
+ assert_equal(back4, rot)
diff --git a/mne/tests/test_utils.py b/mne/tests/test_utils.py
index f340b4d..8e646bb 100644
--- a/mne/tests/test_utils.py
+++ b/mne/tests/test_utils.py
@@ -1,14 +1,18 @@
from numpy.testing import assert_equal
from nose.tools import assert_true, assert_raises
import os.path as op
+import numpy as np
import os
import warnings
import urllib2
-from ..utils import set_log_level, set_log_file, _TempDir, \
- get_config, set_config, deprecated, _fetch_file
+from ..utils import (set_log_level, set_log_file, _TempDir,
+ get_config, set_config, deprecated, _fetch_file,
+ sum_squared, requires_mem_gb)
from ..fiff import Evoked, show_fiff
+warnings.simplefilter('always') # enable b/c these tests throw warnings
+
base_dir = op.join(op.dirname(__file__), '..', 'fiff', 'tests', 'data')
fname_evoked = op.join(base_dir, 'test-ave.fif')
fname_raw = op.join(base_dir, 'test_raw.fif')
@@ -106,9 +110,10 @@ def test_config():
assert_true(len(w) == 1)
assert_true(get_config(key) is None)
assert_raises(KeyError, get_config, key, raise_error=True)
- set_config(key, value)
- assert_true(get_config(key) == value)
- set_config(key, None)
+ with warnings.catch_warnings(True):
+ set_config(key, value)
+ assert_true(get_config(key) == value)
+ set_config(key, None)
if old_val is not None:
os.environ[key] = old_val
@@ -130,6 +135,16 @@ def deprecated_func():
pass
+ at requires_mem_gb(10000)
+def big_mem_func():
+ pass
+
+
+ at requires_mem_gb(0)
+def no_mem_func():
+ pass
+
+
def test_deprecated():
"""Test deprecated function
"""
@@ -138,6 +153,27 @@ def test_deprecated():
assert_true(len(w) == 1)
+def test_requires_mem_gb():
+ """Test requires memory function
+ """
+ try:
+ with warnings.catch_warnings(True) as w:
+ big_mem_func()
+ assert_true(len(w) == 1)
+ with warnings.catch_warnings(True) as w:
+ no_mem_func()
+ assert_true(len(w) == 0)
+ except:
+ try:
+ import psutil
+ msg = ('psutil version %s exposes unexpected API' %
+ psutil.__version__)
+ except ImportError:
+ msg = 'Could not import psutil'
+ from nose.plugins.skip import SkipTest
+ SkipTest(msg)
+
+
def test_fetch_file():
"""Test file downloading
"""
@@ -150,3 +186,10 @@ def test_fetch_file():
url = "http://github.com/mne-tools/mne-python/blob/master/README.rst"
archive_name = op.join(tempdir, "download_test")
_fetch_file(url, archive_name, print_destination=False)
+
+
+def test_sum_squared():
+ """Optimized sum of squares
+ """
+ X = np.random.randint(0, 50, (3, 3))
+ assert_equal(np.sum(X ** 2), sum_squared(X))
diff --git a/mne/tests/test_viz.py b/mne/tests/test_viz.py
index 6aab242..99d7450 100644
--- a/mne/tests/test_viz.py
+++ b/mne/tests/test_viz.py
@@ -1,24 +1,31 @@
import os.path as op
+from functools import wraps
import numpy as np
from numpy.testing import assert_raises
+import warnings
from mne import fiff, read_events, Epochs, SourceEstimate, read_cov, read_proj
from mne.layouts import read_layout
from mne.fiff.pick import pick_channels_evoked
-from mne.viz import plot_topo, plot_topo_tfr, plot_topo_power, \
- plot_topo_phase_lock, plot_topo_image_epochs, \
- plot_evoked_topomap, plot_projs_topomap, \
- plot_sparse_source_estimates, plot_source_estimates, \
- plot_cov, mne_analyze_colormap, plot_image_epochs, \
- plot_connectivity_circle, circular_layout, plot_drop_log, \
- compare_fiff
-from mne.datasets.sample import data_path
+from mne.viz import (plot_topo, plot_topo_tfr, plot_topo_power,
+ plot_topo_phase_lock, plot_topo_image_epochs,
+ plot_evoked_topomap, plot_projs_topomap,
+ plot_sparse_source_estimates, plot_source_estimates,
+ plot_cov, mne_analyze_colormap, plot_image_epochs,
+ plot_connectivity_circle, circular_layout, plot_drop_log,
+ compare_fiff)
+from mne.datasets import sample
from mne.source_space import read_source_spaces
from mne.preprocessing import ICA
+from mne.utils import check_sklearn_version
+
+
+warnings.simplefilter('always') # enable b/c these tests throw warnings
# Set our plotters to test mode
import matplotlib
matplotlib.use('Agg') # for testing don't use X server
+import matplotlib.pyplot as plt
lacks_mayavi = False
try:
@@ -30,44 +37,77 @@ except ImportError:
lacks_mayavi = True
requires_mayavi = np.testing.dec.skipif(lacks_mayavi, 'Requires mayavi')
+
+def requires_sklearn(function):
+ """Decorator to skip test if scikit-learn >= 0.12 is not available"""
+ @wraps(function)
+ def dec(*args, **kwargs):
+ if not check_sklearn_version(min_version='0.12'):
+ from nose.plugins.skip import SkipTest
+ raise SkipTest('Test %s skipped, requires scikit-learn >= 0.12'
+ % function.__name__)
+ ret = function(*args, **kwargs)
+ return ret
+ return dec
+
if not lacks_mayavi:
mlab.options.backend = 'test'
-data_dir = data_path()
+data_dir = sample.data_path(download=False)
subjects_dir = op.join(data_dir, 'subjects')
-sample_src = read_source_spaces(op.join(data_dir, 'subjects', 'sample',
- 'bem', 'sample-oct-6-src.fif'))
ecg_fname = op.join(data_dir, 'MEG', 'sample', 'sample_audvis_ecg_proj.fif')
-evoked_fname = op.join(data_dir, 'MEG', 'sample', 'sample_audvis-ave.fif')
+
base_dir = op.join(op.dirname(__file__), '..', 'fiff', 'tests', 'data')
+evoked_fname = op.join(base_dir, 'test-ave.fif')
fname = op.join(base_dir, 'test-ave.fif')
raw_fname = op.join(base_dir, 'test_raw.fif')
cov_fname = op.join(base_dir, 'test-cov.fif')
event_name = op.join(base_dir, 'test-eve.fif')
event_id, tmin, tmax = 1, -0.2, 0.5
n_chan = 15
-
-raw = fiff.Raw(raw_fname, preload=False)
-events = read_events(event_name)
-picks = fiff.pick_types(raw.info, meg=True, eeg=False, stim=False,
- ecg=False, eog=False, exclude='bads')
-# Use a subset of channels for plotting speed
-picks = np.round(np.linspace(0, len(picks) + 1, n_chan)).astype(int)
-epochs = Epochs(raw, events[:10], event_id, tmin, tmax, picks=picks,
- baseline=(None, 0))
-evoked = epochs.average()
-reject = dict(mag=4e-12)
-epochs_delayed_ssp = Epochs(raw, events[:10], event_id, tmin, tmax,
- picks=picks, baseline=(None, 0), proj='delayed',
- reject=reject)
-evoked_delayed_ssp = epochs_delayed_ssp.average()
layout = read_layout('Vectorview-all')
+def _get_raw():
+ return fiff.Raw(raw_fname, preload=False)
+
+
+def _get_events():
+ return read_events(event_name)
+
+
+def _get_picks(raw):
+ return fiff.pick_types(raw.info, meg=True, eeg=False, stim=False,
+ ecg=False, eog=False, exclude='bads')
+
+
+def _get_epochs():
+ raw = _get_raw()
+ events = _get_events()
+ picks = _get_picks(raw)
+ # Use a subset of channels for plotting speed
+ picks = np.round(np.linspace(0, len(picks) + 1, n_chan)).astype(int)
+ epochs = Epochs(raw, events[:10], event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0))
+ return epochs
+
+
+def _get_epochs_delayed_ssp():
+ raw = _get_raw()
+ events = _get_events()
+ picks = _get_picks(raw)
+ reject = dict(mag=4e-12)
+ epochs_delayed_ssp = Epochs(raw, events[:10], event_id, tmin, tmax,
+ picks=picks, baseline=(None, 0),
+ proj='delayed', reject=reject)
+ return epochs_delayed_ssp
+
+
def test_plot_topo():
"""Test plotting of ERP topography
"""
# Show topography
+ evoked = _get_epochs().average()
plot_topo(evoked, layout)
picked_evoked = pick_channels_evoked(evoked, evoked.ch_names[:3])
@@ -78,6 +118,7 @@ def test_plot_topo():
for evo in [evoked, [evoked, picked_evoked]]:
assert_raises(ValueError, plot_topo, evo, layout, color=['y', 'b'])
+ evoked_delayed_ssp = _get_epochs_delayed_ssp().average()
plot_topo(evoked_delayed_ssp, layout, proj='interactive')
@@ -85,16 +126,19 @@ def test_plot_topo_tfr():
"""Test plotting of TFR
"""
# Make a fake dataset to plot
+ epochs = _get_epochs()
n_freqs = 11
con = np.random.randn(n_chan, n_freqs, len(epochs.times))
freqs = np.arange(n_freqs)
# Show topography of connectivity from seed
plot_topo_tfr(epochs, con, freqs, layout)
+ plt.close('all')
def test_plot_topo_power():
"""Test plotting of power
"""
+ epochs = _get_epochs()
decim = 3
frequencies = np.arange(7, 30, 3) # define frequencies of interest
power = np.abs(np.random.randn(n_chan, 7, 141))
@@ -107,19 +151,23 @@ def test_plot_topo_power():
plot_topo_phase_lock(epochs, phase_lock, frequencies, layout,
baseline=baseline, mode='mean', decim=decim,
title=title)
+ plt.close('all')
def test_plot_topo_image_epochs():
"""Test plotting of epochs image topography
"""
title = 'ERF images - MNE sample data'
+ epochs = _get_epochs()
plot_topo_image_epochs(epochs, layout, sigma=0.5, vmin=-200, vmax=200,
colorbar=True, title=title)
+ plt.close('all')
def test_plot_evoked():
"""Test plotting of evoked
"""
+ evoked = _get_epochs().average()
evoked.plot(proj=True, hline=[1])
# plot with bad channels excluded
@@ -128,6 +176,7 @@ def test_plot_evoked():
# test selective updating of dict keys is working.
evoked.plot(hline=[1], units=dict(mag='femto foo'))
+ evoked_delayed_ssp = _get_epochs_delayed_ssp().average()
evoked_delayed_ssp.plot(proj='interactive')
evoked_delayed_ssp.apply_proj()
assert_raises(RuntimeError, evoked_delayed_ssp.plot, proj='interactive')
@@ -135,12 +184,26 @@ def test_plot_evoked():
assert_raises(RuntimeError, evoked_delayed_ssp.plot, proj='interactive')
assert_raises(RuntimeError, evoked_delayed_ssp.plot, proj='interactive',
axes='foo')
+ plt.close('all')
+def test_plot_epochs():
+ """ Test plotting epochs
+ """
+ epochs = _get_epochs()
+ epochs.plot([0, 1], picks=[0, 2, 3], scalings=None, title_str='%s')
+ epochs[0].plot(picks=[0, 2, 3], scalings=None, title_str='%s')
+ plt.close('all')
+
+
+ at sample.requires_sample_data
@requires_mayavi
def test_plot_sparse_source_estimates():
"""Test plotting of (sparse) source estimates
"""
+ sample_src = read_source_spaces(op.join(data_dir, 'subjects', 'sample',
+ 'bem', 'sample-oct-6-src.fif'))
+
# dense version
vertices = [s['vertno'] for s in sample_src]
n_time = 5
@@ -154,8 +217,8 @@ def test_plot_sparse_source_estimates():
colormap = mne_analyze_colormap()
plot_source_estimates(stc, 'sample', colormap=colormap,
config_opts={'background': (1, 1, 0)},
- subjects_dir=subjects_dir)
- assert_raises(RuntimeError, plot_source_estimates, stc, 'sample',
+ subjects_dir=subjects_dir, colorbar=True)
+ assert_raises(TypeError, plot_source_estimates, stc, 'sample',
figure='foo', hemi='both')
# now do sparse version
@@ -166,7 +229,7 @@ def test_plot_sparse_source_estimates():
stc_data.shape = (n_verts, n_time)
inds = np.where(np.any(stc_data, axis=1))[0]
stc_data = stc_data[inds]
- vertices = vertices[inds]
+ vertices = [vertices[inds], np.empty(0, dtype=np.int)]
stc = SourceEstimate(stc_data, vertices, 1, 1)
plot_sparse_source_estimates(sample_src, stc, bgcolor=(1, 1, 1),
opacity=0.5, high_resolution=True)
@@ -175,26 +238,32 @@ def test_plot_sparse_source_estimates():
def test_plot_cov():
"""Test plotting of covariances
"""
+ raw = _get_raw()
cov = read_cov(cov_fname)
plot_cov(cov, raw.info, proj=True)
+ plt.close('all')
+ at requires_sklearn
def test_plot_ica_panel():
"""Test plotting of ICA panel
"""
+ raw = _get_raw()
ica_picks = fiff.pick_types(raw.info, meg=True, eeg=False, stim=False,
ecg=False, eog=False, exclude='bads')
- cov = read_cov(cov_fname)
- ica = ICA(noise_cov=cov, n_components=2, max_pca_components=3,
- n_pca_components=3)
+ ica = ICA(noise_cov=read_cov(cov_fname), n_components=2,
+ max_pca_components=3, n_pca_components=3)
ica.decompose_raw(raw, picks=ica_picks)
ica.plot_sources_raw(raw)
+ plt.close('all')
def test_plot_image_epochs():
"""Test plotting of epochs image
"""
+ epochs = _get_epochs()
plot_image_epochs(epochs, picks=[1, 2])
+ plt.close('all')
def test_plot_connectivity_circle():
@@ -263,23 +332,48 @@ def test_plot_connectivity_circle():
con = np.random.randn(68, 68)
plot_connectivity_circle(con, label_names, n_lines=300,
node_angles=node_angles, title='test')
+ plt.close('all')
def test_plot_drop_log():
"""Test plotting a drop log
"""
+ epochs = _get_epochs()
+ epochs.drop_bad_epochs()
plot_drop_log(epochs.drop_log)
plot_drop_log([['One'], [], []])
plot_drop_log([['One'], ['Two'], []])
plot_drop_log([['One'], ['One', 'Two'], []])
+ plt.close('all')
def test_plot_raw():
"""Test plotting of raw data
"""
+ raw = _get_raw()
+ events = _get_events()
raw.plot(events=events, show_options=True)
+ plt.close('all')
+def test_plot_raw_psds():
+ """Test plotting of raw psds
+ """
+ import matplotlib.pyplot as plt
+ raw = _get_raw()
+ # normal mode
+ raw.plot_psds(tmax=2.0)
+ # specific mode
+ picks = fiff.pick_types(raw.info, meg='mag', eeg=False)[:4]
+ raw.plot_psds(picks=picks, area_mode='range')
+ ax = plt.axes()
+ # if ax is supplied, picks must be, too:
+ assert_raises(ValueError, raw.plot_psds, ax=ax)
+ raw.plot_psds(picks=picks, ax=ax)
+ plt.close('all')
+
+
+ at sample.requires_sample_data
def test_plot_topomap():
"""Testing topomap plotting
"""
@@ -289,9 +383,15 @@ def test_plot_topomap():
evoked.plot_topomap(0.1, 'mag', layout=layout)
plot_evoked_topomap(evoked, None, ch_type='mag')
times = [0.1, 0.2]
+ plot_evoked_topomap(evoked, times, ch_type='eeg')
plot_evoked_topomap(evoked, times, ch_type='grad')
plot_evoked_topomap(evoked, times, ch_type='planar1')
- plot_evoked_topomap(evoked, times, ch_type='mag', layout='auto')
+ plot_evoked_topomap(evoked, times, ch_type='planar2')
+ with warnings.catch_warnings(True): # delaunay triangulation warning
+ plot_evoked_topomap(evoked, times, ch_type='mag', layout='auto')
+ assert_raises(RuntimeError, plot_evoked_topomap, evoked, 0.1, 'mag',
+ proj='interactive') # projs have already been applied
+ evoked.proj = False # let's fake it like they haven't been applied
plot_evoked_topomap(evoked, 0.1, 'mag', proj='interactive')
assert_raises(RuntimeError, plot_evoked_topomap, evoked, np.repeat(.1, 50))
assert_raises(ValueError, plot_evoked_topomap, evoked, [-3e12, 15e6])
@@ -299,9 +399,28 @@ def test_plot_topomap():
# projs
projs = read_proj(ecg_fname)[:7]
plot_projs_topomap(projs)
+ plt.close('all')
def test_compare_fiff():
"""Test comparing fiff files
"""
compare_fiff(raw_fname, cov_fname, read_limit=0, show=False)
+ plt.close('all')
+
+
+ at requires_sklearn
+def test_plot_ica_topomap():
+ """Test plotting of ICA solutions
+ """
+ raw = _get_raw()
+ ica = ICA(noise_cov=read_cov(cov_fname), n_components=2,
+ max_pca_components=3, n_pca_components=3)
+ ica_picks = fiff.pick_types(raw.info, meg=True, eeg=False, stim=False,
+ ecg=False, eog=False, exclude='bads')
+ ica.decompose_raw(raw, picks=ica_picks)
+ for components in [0, [0], [0, 1], [0, 1] * 7]:
+ ica.plot_topomap(components)
+ ica.info = None
+ assert_raises(RuntimeError, ica.plot_topomap, 1)
+ plt.close('all')
diff --git a/mne/time_frequency/__init__.py b/mne/time_frequency/__init__.py
index 5a22be0..8d17898 100644
--- a/mne/time_frequency/__init__.py
+++ b/mne/time_frequency/__init__.py
@@ -2,7 +2,8 @@
"""
from .tfr import induced_power, single_trial_power, morlet
-from .psd import compute_raw_psd
+from .psd import compute_raw_psd, compute_epochs_psd
+from .csd import CrossSpectralDensity, compute_epochs_csd
from .ar import yule_walker, ar_raw, iir_filter_raw
from .multitaper import dpss_windows, multitaper_psd
from .stft import stft, istft, stftfreq
diff --git a/mne/time_frequency/csd.py b/mne/time_frequency/csd.py
new file mode 100644
index 0000000..1b4d0e3
--- /dev/null
+++ b/mne/time_frequency/csd.py
@@ -0,0 +1,258 @@
+# Author: Roman Goj <roman.goj at gmail.com>
+#
+# License: BSD (3-clause)
+
+import warnings
+import copy as cp
+
+import numpy as np
+from scipy.fftpack import fftfreq
+
+from ..fiff.pick import pick_types
+from ..utils import logger, verbose
+from ..time_frequency.multitaper import (dpss_windows, _mt_spectra,
+ _csd_from_mt, _psd_from_mt_adaptive)
+
+
+class CrossSpectralDensity(object):
+ """Cross-spectral density
+
+ Parameters
+ ----------
+ data : array of shape (n_channels, n_channels)
+ The cross-spectral density matrix.
+ ch_names : list of string
+ List of channels' names.
+ projs :
+ List of projectors used in CSD calculation.
+ bads :
+ List of bad channels.
+ frequencies : float | list of float
+ Frequency or frequencies for which the CSD matrix was calculated. If a
+ list is passed, data is a sum across CSD matrices for all frequencies.
+ sfreq : float
+ Sampling frequency of the data from which the CSD was obtained.
+ n_fft : int
+ Length of the FFT used when calculating the CSD matrix.
+ """
+ def __init__(self, data, ch_names, projs, bads, frequencies, n_fft):
+ self.data = data
+ self.dim = len(data)
+ self.ch_names = cp.deepcopy(ch_names)
+ self.projs = cp.deepcopy(projs)
+ self.bads = cp.deepcopy(bads)
+ self.frequencies = np.atleast_1d(np.copy(frequencies))
+ self.n_fft = n_fft
+
+ def __repr__(self):
+ s = 'frequencies : %s' % self.frequencies
+ s += ', size : %s x %s' % self.data.shape
+ s += ', data : %s' % self.data
+ return '<CrossSpectralDensity | %s>' % s
+
+
+ at verbose
+def compute_epochs_csd(epochs, mode='multitaper', fmin=0, fmax=np.inf,
+ fsum=True, tmin=None, tmax=None, n_fft=None,
+ mt_bandwidth=None, mt_adaptive=False, mt_low_bias=True,
+ projs=None, verbose=None):
+ """Estimate cross-spectral density from epochs
+
+ Note: Baseline correction should be used when creating the Epochs.
+ Otherwise the computed cross-spectral density will be inaccurate.
+
+ Note: Results are scaled by sampling frequency for compatibility with
+ Matlab.
+
+ Parameters
+ ----------
+ epochs : instance of Epochs
+ The epochs.
+ mode : str
+ Spectrum estimation mode can be either: 'multitaper' or 'fourier'.
+ fmin : float
+ Minimum frequency of interest.
+ fmax : float | np.inf
+ Maximum frequency of interest.
+ fsum : bool
+ Sum CSD values for the frequencies of interest. Summing is performed
+ instead of averaging so that accumulated power is comparable to power
+ in the time domain. If True, a single CSD matrix will be returned. If
+ False, the output will be a list of CSD matrices.
+ tmin : float | None
+ Minimum time instant to consider. If None start at first sample.
+ tmax : float | None
+ Maximum time instant to consider. If None end at last sample.
+ n_fft : int | None
+ Length of the FFT. If None the exact number of samples between tmin and
+ tmax will be used.
+ mt_bandwidth : float | None
+ The bandwidth of the multitaper windowing function in Hz.
+ Only used in 'multitaper' mode.
+ mt_adaptive : bool
+ Use adaptive weights to combine the tapered spectra into PSD.
+ Only used in 'multitaper' mode.
+ mt_low_bias : bool
+ Only use tapers with more than 90% spectral concentration within
+ bandwidth. Only used in 'multitaper' mode.
+ projs : list of Projection | None
+ List of projectors to use in CSD calculation, or None to indicate that
+ the projectors from the epochs should be inherited.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ csd : instance of CrossSpectralDensity
+ The computed cross-spectral density.
+ """
+ # Portions of this code adapted from mne/connectivity/spectral.py
+
+ # Check correctness of input data and parameters
+ if fmax < fmin:
+ raise ValueError('fmax must be larger than fmin')
+ tstep = epochs.times[1] - epochs.times[0]
+ if tmin is not None and tmin < epochs.times[0] - tstep:
+ raise ValueError('tmin should be larger than the smallest data time '
+ 'point')
+ if tmax is not None and tmax > epochs.times[-1] + tstep:
+ raise ValueError('tmax should be smaller than the largest data time '
+ 'point')
+ if tmax is not None and tmin is not None:
+ if tmax < tmin:
+ raise ValueError('tmax must be larger than tmin')
+ if epochs.baseline is None:
+ warnings.warn('Epochs are not baseline corrected, cross-spectral '
+ 'density may be inaccurate')
+
+ if projs is None:
+ projs = cp.deepcopy(epochs.info['projs'])
+ else:
+ projs = cp.deepcopy(projs)
+
+ picks_meeg = pick_types(epochs[0].info, meg=True, eeg=True, eog=False,
+ ref_meg=False, exclude='bads')
+ ch_names = [epochs.ch_names[k] for k in picks_meeg]
+
+ # Preparing time window slice
+ tstart, tend = None, None
+ if tmin is not None:
+ tstart = np.where(epochs.times >= tmin)[0][0]
+ if tmax is not None:
+ tend = np.where(epochs.times <= tmax)[0][-1] + 1
+ tslice = slice(tstart, tend, None)
+ n_times = len(epochs.times[tslice])
+ n_fft = n_times if n_fft is None else n_fft
+
+ # Preparing frequencies of interest
+ sfreq = epochs.info['sfreq']
+ frequencies = fftfreq(n_fft, 1. / sfreq)
+ freq_mask = (frequencies > fmin) & (frequencies < fmax)
+ frequencies = frequencies[freq_mask]
+ n_freqs = len(frequencies)
+
+ if n_freqs == 0:
+ raise ValueError('No discrete fourier transform results within '
+ 'the given frequency window. Please widen either '
+ 'the frequency window or the time window')
+
+ # Preparing for computing CSD
+ logger.info('Computing cross-spectral density from epochs...')
+ if mode == 'multitaper':
+ # Compute standardized half-bandwidth
+ if mt_bandwidth is not None:
+ half_nbw = float(mt_bandwidth) * n_times / (2 * sfreq)
+ else:
+ half_nbw = 2
+
+ # Compute DPSS windows
+ n_tapers_max = int(2 * half_nbw)
+ window_fun, eigvals = dpss_windows(n_times, half_nbw, n_tapers_max,
+ low_bias=mt_low_bias)
+ n_tapers = len(eigvals)
+ logger.info(' using multitaper spectrum estimation with %d DPSS '
+ 'windows' % n_tapers)
+
+ if mt_adaptive and len(eigvals) < 3:
+ warnings.warn('Not adaptively combining the spectral estimators '
+ 'due to a low number of tapers.')
+ mt_adaptive = False
+ elif mode == 'fourier':
+ logger.info(' using FFT with a Hanning window to estimate spectra')
+ window_fun = np.hanning(n_times)
+ mt_adaptive = False
+ eigvals = 1.
+ n_tapers = None
+ else:
+ raise ValueError('Mode has an invalid value.')
+
+ csds_mean = np.zeros((len(ch_names), len(ch_names), n_freqs),
+ dtype=complex)
+
+ # Compute CSD for each epoch
+ n_epochs = 0
+ for epoch in epochs:
+ epoch = epoch[picks_meeg][:, tslice]
+
+ # Calculating Fourier transform using multitaper module
+ x_mt, _ = _mt_spectra(epoch, window_fun, sfreq, n_fft)
+
+ if mt_adaptive:
+ # Compute adaptive weights
+ _, weights = _psd_from_mt_adaptive(x_mt, eigvals, freq_mask,
+ return_weights=True)
+ # Tiling weights so that we can easily use _csd_from_mt()
+ weights = weights[:, np.newaxis, :, :]
+ weights = np.tile(weights, [1, x_mt.shape[0], 1, 1])
+ else:
+ # Do not use adaptive weights
+ if mode == 'multitaper':
+ weights = np.sqrt(eigvals)[np.newaxis, np.newaxis, :,
+ np.newaxis]
+ else:
+ # Hack so we can sum over axis=-2
+ weights = np.array([1.])[:, None, None, None]
+
+ # Picking frequencies of interest
+ x_mt = x_mt[:, :, freq_mask]
+
+ # Calculating CSD
+ # Tiling x_mt so that we can easily use _csd_from_mt()
+ x_mt = x_mt[:, np.newaxis, :, :]
+ x_mt = np.tile(x_mt, [1, x_mt.shape[0], 1, 1])
+ y_mt = np.transpose(x_mt, axes=[1, 0, 2, 3])
+ weights_y = np.transpose(weights, axes=[1, 0, 2, 3])
+ csds_epoch = _csd_from_mt(x_mt, y_mt, weights, weights_y)
+
+ # Scaling by number of samples and compensating for loss of power due
+ # to windowing (see section 11.5.2 in Bendat & Piersol).
+ if mode == 'fourier':
+ csds_epoch /= n_times
+ csds_epoch *= 8 / 3.
+
+ # Scaling by sampling frequency for compatibility with Matlab
+ csds_epoch /= sfreq
+
+ csds_mean += csds_epoch
+ n_epochs += 1
+
+ csds_mean /= n_epochs
+
+ logger.info('[done]')
+
+ # Summing over frequencies of interest or returning a list of separate CSD
+ # matrices for each frequency
+ if fsum is True:
+ csd_mean_fsum = np.sum(csds_mean, 2)
+ csd = CrossSpectralDensity(csd_mean_fsum, ch_names, projs,
+ epochs.info['bads'],
+ frequencies=frequencies, n_fft=n_fft)
+ return csd
+ else:
+ csds = []
+ for i in range(n_freqs):
+ csds.append(CrossSpectralDensity(csds_mean[:, :, i], ch_names,
+ projs, epochs.info['bads'],
+ frequencies=frequencies[i],
+ n_fft=n_fft))
+ return csds
diff --git a/mne/time_frequency/multitaper.py b/mne/time_frequency/multitaper.py
index 1c39765..387a9bd 100644
--- a/mne/time_frequency/multitaper.py
+++ b/mne/time_frequency/multitaper.py
@@ -8,7 +8,7 @@ import numpy as np
from scipy import fftpack, linalg, interpolate
from ..parallel import parallel_func
-from .. import verbose
+from ..utils import verbose, sum_squared
def tridisolve(d, e, b, overwrite_b=True):
@@ -167,7 +167,7 @@ def dpss_windows(N, half_nbw, Kmax, low_bias=True, interp_from=None,
float(this_d.shape[-1] - 1) / N))
# Rescale:
- d_temp = d_temp / np.sqrt(np.sum(d_temp ** 2))
+ d_temp = d_temp / np.sqrt(sum_squared(d_temp))
dpss.append(d_temp)
@@ -228,7 +228,7 @@ def dpss_windows(N, half_nbw, Kmax, low_bias=True, interp_from=None,
# compute autocorr using FFT (same as nitime.utils.autocorr(dpss) * N)
rxx_size = 2 * N - 1
- NFFT = 2 ** np.ceil(np.log2(rxx_size))
+ NFFT = 2 ** int(np.ceil(np.log2(rxx_size)))
dpss_fft = fftpack.fft(dpss, NFFT)
dpss_rxx = np.real(fftpack.ifft(dpss_fft * dpss_fft.conj()))
dpss_rxx = dpss_rxx[:, :N]
@@ -325,8 +325,8 @@ def _psd_from_mt_adaptive(x_mt, eigvals, freq_mask, max_iter=150,
err = np.zeros_like(xk)
for n in range(max_iter):
- d_k = psd_iter / (eigvals[:, np.newaxis] * psd_iter + \
- (1 - eigvals[:, np.newaxis]) * var)
+ d_k = (psd_iter / (eigvals[:, np.newaxis] * psd_iter +
+ (1 - eigvals[:, np.newaxis]) * var))
d_k *= rt_eig[:, np.newaxis]
# Test for convergence -- this is overly conservative, since
# iteration only stops when all frequencies have converged.
@@ -345,7 +345,7 @@ def _psd_from_mt_adaptive(x_mt, eigvals, freq_mask, max_iter=150,
if n == max_iter - 1:
warn('Iterative multi-taper PSD computation did not converge.',
- RuntimeWarning)
+ RuntimeWarning)
psd[i, :] = psd_iter
@@ -402,15 +402,15 @@ def _csd_from_mt(x_mt, y_mt, weights_x, weights_y):
csd = np.sum(weights_x * x_mt * (weights_y * y_mt).conj(), axis=-2)
- denom = np.sqrt(np.sum(np.abs(weights_x) ** 2, axis=-2))\
- * np.sqrt(np.sum(np.abs(weights_y) ** 2, axis=-2))
+ denom = (np.sqrt(np.sum(np.abs(weights_x) ** 2, axis=-2))
+ * np.sqrt(np.sum(np.abs(weights_y) ** 2, axis=-2)))
csd *= 2 / denom
return csd
-def _mt_spectra(x, dpss, sfreq):
+def _mt_spectra(x, dpss, sfreq, n_fft=None):
""" Compute tapered spectra
Parameters
@@ -421,6 +421,9 @@ def _mt_spectra(x, dpss, sfreq):
The tapers
sfreq : float
The sampling frequency
+ n_fft : int | None
+ Length of the FFT. If None, the number of samples in the input signal
+ will be used.
Returns
-------
@@ -430,12 +433,15 @@ def _mt_spectra(x, dpss, sfreq):
The frequency points in Hz of the spectra
"""
+ if n_fft is None:
+ n_fft = x.shape[1]
+
# remove mean (do not use in-place subtraction as it may modify input x)
x = x - np.mean(x, axis=-1)[:, np.newaxis]
- x_mt = fftpack.fft(x[:, np.newaxis, :] * dpss)
+ x_mt = fftpack.fft(x[:, np.newaxis, :] * dpss, n=n_fft)
# only keep positive frequencies
- freqs = fftpack.fftfreq(x.shape[1], 1. / sfreq)
+ freqs = fftpack.fftfreq(n_fft, 1. / sfreq)
freq_mask = (freqs >= 0)
x_mt = x_mt[:, :, freq_mask]
diff --git a/mne/time_frequency/psd.py b/mne/time_frequency/psd.py
index d4bd5ec..99a8510 100644
--- a/mne/time_frequency/psd.py
+++ b/mne/time_frequency/psd.py
@@ -1,16 +1,13 @@
-# Author : Alexandre Gramfort, gramfort at nmr.mgh.harvard.edu (2011)
+# Authors : Alexandre Gramfort, gramfort at nmr.mgh.harvard.edu (2011)
+# Denis A. Engemann <d.engemann at fz-juelich.de>
# License : BSD 3-clause
import numpy as np
-import logging
-logger = logging.getLogger('mne')
-
-# XXX : don't import pylab here or you will break the doc
-
from ..parallel import parallel_func
from ..fiff.proj import make_projector_info
-from .. import verbose
+from ..fiff.pick import pick_types
+from ..utils import logger, verbose
@verbose
@@ -23,36 +20,22 @@ def compute_raw_psd(raw, tmin=0, tmax=np.inf, picks=None,
----------
raw : instance of Raw
The raw data.
-
- tmin : float
- Min time instant to consider
-
- tmax : float
- Max time instant to consider
-
picks : None or array of integers
The selection of channels to include in the computation.
If None, take all channels.
-
fmin : float
Min frequency of interest
-
fmax : float
Max frequency of interest
-
NFFT : int
- The length of the tappers ie. the windows. The smaller
+ The length of the tapers ie. the windows. The smaller
it is the smoother are the PSDs.
-
n_jobs : int
Number of CPUs to use in the computation.
-
plot : bool
Plot each PSD estimates
-
proj : bool
Apply SSP projection vectors
-
verbose : bool, str, int, or None
If not None, override default verbose level (see mne.verbose).
@@ -60,7 +43,6 @@ def compute_raw_psd(raw, tmin=0, tmax=np.inf, picks=None,
-------
psd : array of float
The PSD for all channels
-
freqs: array of float
The frequencies
"""
@@ -82,12 +64,12 @@ def compute_raw_psd(raw, tmin=0, tmax=np.inf, picks=None,
logger.info("Effective window size : %0.3f (s)" % (NFFT / float(Fs)))
- import pylab as pl
- parallel, my_psd, n_jobs = parallel_func(pl.psd, n_jobs)
- fig = pl.figure()
+ import matplotlib.pyplot as plt
+ parallel, my_psd, n_jobs = parallel_func(plt.psd, n_jobs)
+ fig = plt.figure()
out = parallel(my_psd(d, Fs=Fs, NFFT=NFFT) for d in data)
if not plot:
- pl.close(fig)
+ plt.close(fig)
freqs = out[0][1]
psd = np.array(zip(*out)[0])
@@ -96,3 +78,68 @@ def compute_raw_psd(raw, tmin=0, tmax=np.inf, picks=None,
psd = psd[:, mask]
return psd, freqs
+
+
+def _compute_psd(data, fmin, fmax, Fs, n_fft, psd):
+ """Compute the PSD"""
+ out = [psd(d, Fs=Fs, NFFT=n_fft) for d in data]
+ psd = np.array(zip(*out)[0])
+ freqs = out[0][1]
+ mask = (freqs >= fmin) & (freqs <= fmax)
+ freqs = freqs[mask]
+ return psd[:, mask], freqs
+
+
+ at verbose
+def compute_epochs_psd(epochs, picks=None, fmin=0, fmax=np.inf, n_fft=256,
+ n_jobs=1, verbose=None):
+ """Compute power spectral density with multi-taper
+
+ Parameters
+ ----------
+ epochs : instance of Epochs
+ The epochs.
+ tmin : float
+ Min time instant to consider
+ tmax : float
+ Max time instant to consider
+ picks : None or array of integers
+ The selection of channels to include in the computation.
+ If None, take all channels.
+ fmin : float
+ Min frequency of interest
+ fmax : float
+ Max frequency of interest
+ n_fft : int
+ The length of the tapers ie. the windows. The smaller
+ it is the smoother are the PSDs.
+ n_jobs : int
+ Number of CPUs to use in the computation.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+
+ Returns
+ -------
+ psds : ndarray (n_epochs, n_channels, n_freqs)
+ The power spectral densities.
+ freqs : ndarray (n_freqs)
+ The frequencies.
+ """
+
+ n_fft = int(n_fft)
+ Fs = epochs.info['sfreq']
+ if picks is None:
+ picks = pick_types(epochs.info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
+
+ logger.info("Effective window size : %0.3f (s)" % (n_fft / float(Fs)))
+ psds = []
+ import matplotlib.pyplot as plt
+ parallel, my_psd, n_jobs = parallel_func(_compute_psd, n_jobs)
+ fig = plt.figure() # threading will induce errors otherwise
+ out = parallel(my_psd(data[picks], fmin, fmax, Fs, n_fft, plt.psd)
+ for data in epochs)
+ plt.close(fig)
+ psds, freqs = zip(*out)
+
+ return np.array(psds), freqs[0]
diff --git a/mne/time_frequency/stft.py b/mne/time_frequency/stft.py
index e9fe61f..ff802bd 100644
--- a/mne/time_frequency/stft.py
+++ b/mne/time_frequency/stft.py
@@ -2,10 +2,7 @@ from math import ceil
import numpy as np
from scipy.fftpack import fft, ifft, fftfreq
-import logging
-logger = logging.getLogger('mne')
-
-from .. import verbose
+from ..utils import logger, verbose
@verbose
diff --git a/mne/time_frequency/tests/test_csd.py b/mne/time_frequency/tests/test_csd.py
new file mode 100644
index 0000000..45ae9ec
--- /dev/null
+++ b/mne/time_frequency/tests/test_csd.py
@@ -0,0 +1,163 @@
+import numpy as np
+from nose.tools import assert_raises, assert_equal, assert_almost_equal
+from numpy.testing import assert_array_equal
+from os import path as op
+
+import mne
+
+from mne.fiff import Raw
+from mne.utils import sum_squared
+from mne.time_frequency import compute_epochs_csd, induced_power
+
+base_dir = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data')
+raw_fname = op.join(base_dir, 'test_raw.fif')
+event_fname = op.join(base_dir, 'test-eve.fif')
+
+
+def _get_data():
+ # Read raw data
+ raw = Raw(raw_fname)
+ raw.info['bads'] = ['MEG 2443', 'EEG 053'] # 2 bads channels
+
+ # Set picks
+ picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False, eog=False,
+ stim=False, exclude='bads')
+
+ # Read several epochs
+ event_id, tmin, tmax = 1, -0.2, 0.5
+ events = mne.read_events(event_fname)[0:100]
+ epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
+ picks=picks, baseline=(None, 0), preload=True,
+ reject=dict(grad=4000e-13, mag=4e-12))
+
+ # Create an epochs object with one epoch and one channel of artificial data
+ event_id, tmin, tmax = 1, 0.0, 1.0
+ epochs_sin = mne.Epochs(raw, events[0:5], event_id, tmin, tmax, proj=True,
+ picks=[0], baseline=(None, 0), preload=True,
+ reject=dict(grad=4000e-13))
+ freq = 10
+ epochs_sin._data = np.sin(2 * np.pi * freq
+ * epochs_sin.times)[None, None, :]
+ return epochs, epochs_sin
+
+
+def test_compute_epochs_csd():
+ """Test computing cross-spectral density from epochs
+ """
+ epochs, epochs_sin = _get_data()
+ # Check that wrong parameters are recognized
+ assert_raises(ValueError, compute_epochs_csd, epochs, mode='notamode')
+ assert_raises(ValueError, compute_epochs_csd, epochs, fmin=20, fmax=10)
+ assert_raises(ValueError, compute_epochs_csd, epochs, fmin=20, fmax=20.1)
+ assert_raises(ValueError, compute_epochs_csd, epochs, tmin=0.15, tmax=0.1)
+ assert_raises(ValueError, compute_epochs_csd, epochs, tmin=0, tmax=10)
+ assert_raises(ValueError, compute_epochs_csd, epochs, tmin=10, tmax=11)
+
+ data_csd_mt = compute_epochs_csd(epochs, mode='multitaper', fmin=8,
+ fmax=12, tmin=0.04, tmax=0.15)
+ data_csd_fourier = compute_epochs_csd(epochs, mode='fourier', fmin=8,
+ fmax=12, tmin=0.04, tmax=0.15)
+
+ # Check shape of the CSD matrix
+ n_chan = len(data_csd_mt.ch_names)
+ assert_equal(data_csd_mt.data.shape, (n_chan, n_chan))
+ assert_equal(data_csd_fourier.data.shape, (n_chan, n_chan))
+
+ # Check if the CSD matrix is hermitian
+ assert_array_equal(np.tril(data_csd_mt.data).T.conj(),
+ np.triu(data_csd_mt.data))
+ assert_array_equal(np.tril(data_csd_fourier.data).T.conj(),
+ np.triu(data_csd_fourier.data))
+
+ # Computing induced power for comparison
+ epochs.crop(tmin=0.04, tmax=0.15)
+ power, _ = induced_power(epochs.get_data(), epochs.info['sfreq'], [10],
+ n_cycles=0.6)
+ power = np.mean(power, 2)
+
+ # Maximum PSD should occur for specific channel
+ max_ch_power = power.argmax()
+ max_ch_mt = data_csd_mt.data.diagonal().argmax()
+ max_ch_fourier = data_csd_fourier.data.diagonal().argmax()
+ assert_equal(max_ch_mt, max_ch_power)
+ assert_equal(max_ch_fourier, max_ch_power)
+
+ # Maximum CSD should occur for specific channel
+ ch_csd_mt = [np.abs(data_csd_mt.data[max_ch_power][i])
+ if i != max_ch_power else 0 for i in range(n_chan)]
+ max_ch_csd_mt = np.argmax(ch_csd_mt)
+ ch_csd_fourier = [np.abs(data_csd_fourier.data[max_ch_power][i])
+ if i != max_ch_power else 0 for i in range(n_chan)]
+ max_ch_csd_fourier = np.argmax(ch_csd_fourier)
+ assert_equal(max_ch_csd_mt, max_ch_csd_fourier)
+
+ # Check a list of CSD matrices is returned for multiple frequencies within
+ # a given range when fsum=False
+ csd_fsum = compute_epochs_csd(epochs, mode='fourier', fmin=8, fmax=20,
+ fsum=True)
+ csds = compute_epochs_csd(epochs, mode='fourier', fmin=8, fmax=20,
+ fsum=False)
+ freqs = [csd.frequencies[0] for csd in csds]
+
+ csd_sum = np.zeros_like(csd_fsum.data)
+ for csd in csds:
+ csd_sum += csd.data
+
+ assert(len(csds) == 2)
+ assert(len(csd_fsum.frequencies) == 2)
+ assert_array_equal(csd_fsum.frequencies, freqs)
+ assert_array_equal(csd_fsum.data, csd_sum)
+
+
+def test_compute_epochs_csd_on_artificial_data():
+ """Test computing CSD on artificial data
+ """
+ epochs, epochs_sin = _get_data()
+ sfreq = epochs_sin.info['sfreq']
+
+ # Computing signal power in the time domain
+ signal_power = sum_squared(epochs_sin._data)
+ signal_power_per_sample = signal_power / len(epochs_sin.times)
+
+ # Computing signal power in the frequency domain
+ data_csd_fourier = compute_epochs_csd(epochs_sin, mode='fourier')
+ data_csd_mt = compute_epochs_csd(epochs_sin, mode='multitaper')
+ fourier_power = np.abs(data_csd_fourier.data[0, 0]) * sfreq
+ mt_power = np.abs(data_csd_mt.data[0, 0]) * sfreq
+ assert_almost_equal(fourier_power, signal_power, delta=0.5)
+ assert_almost_equal(mt_power, signal_power, delta=1)
+
+ # Power per sample should not depend on time window length
+ for tmax in [0.2, 0.4, 0.6, 0.8]:
+ for add_n_fft in [30, 0, 30]:
+ t_mask = (epochs_sin.times >= 0) & (epochs_sin.times <= tmax)
+ n_samples = sum(t_mask)
+ n_fft = n_samples + add_n_fft
+
+ data_csd_fourier = compute_epochs_csd(epochs_sin, mode='fourier',
+ tmin=None, tmax=tmax, fmin=0,
+ fmax=np.inf, n_fft=n_fft)
+ fourier_power_per_sample = np.abs(data_csd_fourier.data[0, 0]) *\
+ sfreq / data_csd_fourier.n_fft
+ assert_almost_equal(signal_power_per_sample,
+ fourier_power_per_sample, delta=0.003)
+
+ # Power per sample should not depend on number of tapers
+ for n_tapers in [1, 2, 3, 5]:
+ for add_n_fft in [30, 0, 30]:
+ mt_bandwidth = sfreq / float(n_samples) * (n_tapers + 1)
+ data_csd_mt = compute_epochs_csd(epochs_sin, mode='multitaper',
+ tmin=None, tmax=tmax, fmin=0,
+ fmax=np.inf,
+ mt_bandwidth=mt_bandwidth,
+ n_fft=n_fft)
+ mt_power_per_sample = np.abs(data_csd_mt.data[0, 0]) *\
+ sfreq / data_csd_mt.n_fft
+ # The estimate of power gets worse for small time windows when
+ # more tapers are used
+ if n_tapers == 5 and tmax == 0.2:
+ delta = 0.05
+ else:
+ delta = 0.004
+ assert_almost_equal(signal_power_per_sample,
+ mt_power_per_sample, delta=delta)
diff --git a/mne/time_frequency/tests/test_psd.py b/mne/time_frequency/tests/test_psd.py
index 2769c10..c7677e3 100644
--- a/mne/time_frequency/tests/test_psd.py
+++ b/mne/time_frequency/tests/test_psd.py
@@ -4,11 +4,13 @@ from numpy.testing import assert_array_almost_equal
from nose.tools import assert_true
from mne import fiff
-from mne.time_frequency import compute_raw_psd
+from mne import Epochs
+from mne import read_events
+from mne.time_frequency import compute_raw_psd, compute_epochs_psd
-
-raw_fname = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data',
- 'test_raw.fif')
+base_dir = op.join(op.dirname(__file__), '..', '..', 'fiff', 'tests', 'data')
+raw_fname = op.join(base_dir, 'test_raw.fif')
+event_fname = op.join(base_dir, 'test-eve.fif')
def test_psd():
@@ -26,7 +28,7 @@ def test_psd():
tmin, tmax = 0, 10 # use the first 60s of data
fmin, fmax = 2, 70 # look at frequencies between 5 and 70Hz
- NFFT = 124 # the FFT size (NFFT). Ideally a power of 2
+ NFFT = 128 # the FFT size (NFFT). Ideally a power of 2
psds, freqs = compute_raw_psd(raw, tmin=tmin, tmax=tmax, picks=picks,
fmin=fmin, fmax=fmax, NFFT=NFFT, n_jobs=1,
proj=False)
@@ -38,3 +40,45 @@ def test_psd():
assert_true(psds.shape == (len(picks), len(freqs)))
assert_true(np.sum(freqs < 0) == 0)
assert_true(np.sum(psds < 0) == 0)
+
+
+def test_psd_epochs():
+ """Test PSD estimation on epochs
+ """
+ raw = fiff.Raw(raw_fname)
+
+ exclude = raw.info['bads'] + ['MEG 2443', 'EEG 053'] # bads + 2 more
+
+ # picks MEG gradiometers
+ picks = fiff.pick_types(raw.info, meg='mag', eeg=False, stim=False,
+ exclude=exclude)
+
+ picks = picks[:2]
+
+ n_fft = 128 # the FFT size (n_fft). Ideally a power of 2
+
+ tmin, tmax, event_id = -1, 1, 1
+ include = []
+ raw.info['bads'] += ['MEG 2443'] # bads
+
+ # picks MEG gradiometers
+ picks = fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
+ stim=False, include=include, exclude='bads')
+
+ events = read_events(event_fname)
+ epochs = Epochs(raw, events[:10], event_id, tmin, tmax, picks=picks,
+ baseline=(None, 0),
+ reject=dict(grad=4000e-13, eog=150e-6), proj=False,
+ preload=True)
+
+ picks = fiff.pick_types(epochs.info, meg='grad', eeg=False, eog=True,
+ stim=False, include=include, exclude='bads')
+ psds, freqs = compute_epochs_psd(epochs[:1], fmin=2, fmax=300, n_fft=n_fft,
+ picks=picks)
+ psds_proj, _ = compute_epochs_psd(epochs[:1].apply_proj(), fmin=2,
+ fmax=300, n_fft=n_fft, picks=picks)
+
+ assert_array_almost_equal(psds, psds_proj)
+ assert_true(psds.shape == (1, len(picks), len(freqs)))
+ assert_true(np.sum(freqs < 0) == 0)
+ assert_true(np.sum(psds < 0) == 0)
diff --git a/mne/time_frequency/tfr.py b/mne/time_frequency/tfr.py
index 8613ceb..02b2515 100644
--- a/mne/time_frequency/tfr.py
+++ b/mne/time_frequency/tfr.py
@@ -12,12 +12,9 @@ import numpy as np
from scipy import linalg
from scipy.fftpack import fftn, ifftn
-import logging
-logger = logging.getLogger('mne')
-
from ..baseline import rescale
from ..parallel import parallel_func
-from .. import verbose
+from ..utils import logger, verbose
def morlet(Fs, freqs, n_cycles=7, sigma=None, zero_mean=False):
@@ -27,13 +24,10 @@ def morlet(Fs, freqs, n_cycles=7, sigma=None, zero_mean=False):
----------
Fs : float
Sampling Frequency
-
freqs : array
frequency range of interest (1 x Frequencies)
-
n_cycles: float | array of float
Number of cycles. Fixed number or one per frequency.
-
sigma : float, (optional)
It controls the width of the wavelet ie its temporal
resolution. If sigma is None the temporal resolution
@@ -42,7 +36,6 @@ def morlet(Fs, freqs, n_cycles=7, sigma=None, zero_mean=False):
If sigma is fixed the temporal resolution is fixed
like for the short time Fourier transform and the number
of oscillations increases with the frequency.
-
zero_mean : bool
Make sure the wavelet is zero mean
@@ -104,7 +97,7 @@ def _cwt_fft(X, Ws, mode="same"):
Ws_max_size = max(W.size for W in Ws)
size = n_times + Ws_max_size - 1
# Always use 2**n-sized FFT
- fsize = 2 ** np.ceil(np.log2(size))
+ fsize = 2 ** int(np.ceil(np.log2(size)))
# precompute FFTs of Ws
fft_Ws = np.empty((n_freqs, fsize), dtype=np.complex128)
diff --git a/mne/transforms/transforms.py b/mne/transforms.py
similarity index 67%
rename from mne/transforms/transforms.py
rename to mne/transforms.py
index 7d3db77..55206fd 100644
--- a/mne/transforms/transforms.py
+++ b/mne/transforms.py
@@ -7,18 +7,54 @@ import numpy as np
from numpy import sin, cos
from scipy import linalg
-import logging
-logger = logging.getLogger('mne')
-
-from ..fiff import FIFF
-from ..fiff.open import fiff_open
-from ..fiff.tag import read_tag, find_tag
-from ..fiff.tree import dir_tree_find
-from ..fiff.write import start_file, end_file, start_block, end_block, \
- write_coord_trans, write_dig_point, write_int
-
-
-def apply_trans(trans, pts):
+from .fiff import FIFF
+from .fiff.open import fiff_open
+from .fiff.tag import read_tag, find_tag
+from .fiff.tree import dir_tree_find
+from .fiff.write import (start_file, end_file, start_block, end_block,
+ write_coord_trans, write_dig_point, write_int)
+from .utils import logger
+
+
+# transformation from anterior/left/superior coordinate system to
+# right/anterior/superior:
+als_ras_trans = np.array([[0, -1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0],
+ [0, 0, 0, 1]])
+# simultaneously convert [m] to [mm]:
+als_ras_trans_mm = als_ras_trans * [0.001, 0.001, 0.001, 1]
+
+
+def _coord_frame_name(cframe):
+ """Map integers to human-readable names"""
+ types = [FIFF.FIFFV_COORD_UNKNOWN, FIFF.FIFFV_COORD_DEVICE,
+ FIFF.FIFFV_COORD_ISOTRAK, FIFF.FIFFV_COORD_HPI,
+ FIFF.FIFFV_COORD_HEAD, FIFF.FIFFV_COORD_MRI,
+ FIFF.FIFFV_MNE_COORD_MRI_VOXEL, FIFF.FIFFV_COORD_MRI_SLICE,
+ FIFF.FIFFV_COORD_MRI_DISPLAY, FIFF.FIFFV_MNE_COORD_CTF_DEVICE,
+ FIFF.FIFFV_MNE_COORD_CTF_HEAD, FIFF.FIFFV_MNE_COORD_RAS,
+ FIFF.FIFFV_MNE_COORD_MNI_TAL, FIFF.FIFFV_MNE_COORD_FS_TAL_GTZ,
+ FIFF.FIFFV_MNE_COORD_FS_TAL_LTZ, -1]
+ strs = ['unknown', 'MEG device', 'isotrak', 'hpi', 'head',
+ 'MRI (surface RAS)', 'MRI voxel', 'MRI slice', 'MRI display',
+ 'CTF MEG device', 'CTF/4D/KIT head', 'RAS (non-zero origin)',
+ 'MNI Talairach', 'Talairach (MNI z > 0)', 'Talairach (MNI z < 0)',
+ 'unknown']
+ assert len(types) == len(strs)
+ for t, s in zip(types, strs):
+ if cframe == t:
+ return s
+ return strs[-1]
+
+
+def _print_coord_trans(t, prefix='Coordinate transformation: '):
+ logger.info(prefix + '%s -> %s'
+ % (_coord_frame_name(t['from']), _coord_frame_name(t['to'])))
+ for tt in t['trans']:
+ logger.info(' % 8.6f % 8.6f % 8.6f %7.2f mm' %
+ (tt[0], tt[1], tt[2], 1000 * tt[3]))
+
+
+def apply_trans(trans, pts, move=True):
"""Apply a transform matrix to an array of points
Parameters
@@ -27,6 +63,8 @@ def apply_trans(trans, pts):
Transform matrix.
pts : array, shape = (3,) | (n, 3)
Array with coordinates for one or n points.
+ move : bool
+ If True (default), apply translation.
Returns
-------
@@ -35,19 +73,24 @@ def apply_trans(trans, pts):
"""
trans = np.asarray(trans)
pts = np.asarray(pts)
+
+ # apply rotation & scale
if pts.ndim == 1:
- pts = np.vstack((pts[:, None], [1]))
- pts = np.dot(trans, pts)
- pts = pts[:3, 0]
+ out_pts = np.dot(trans[:3, :3], pts)
else:
- pts = np.vstack((pts.T, np.ones(len(pts))))
- pts = np.dot(trans, pts)
- pts = pts[:3].T
- return pts
+ out_pts = np.dot(pts, trans[:3, :3].T)
+
+ # apply translation
+ if move is True:
+ transl = trans[:3, 3]
+ if np.any(transl != 0):
+ out_pts += transl
+
+ return out_pts
def rotation(x=0, y=0, z=0):
- """Create an array with a rotation matrix
+ """Create an array with a 4 dimensional rotation matrix
Parameters
----------
@@ -74,6 +117,55 @@ def rotation(x=0, y=0, z=0):
return r
+def rotation3d(x=0, y=0, z=0):
+ """Create an array with a 3 dimensional rotation matrix
+
+ Parameters
+ ----------
+ x, y, z : scalar
+ Rotation around the origin (in rad).
+
+ Returns
+ -------
+ r : array, shape = (3, 3)
+ The rotation matrix.
+ """
+ cos_x = cos(x)
+ cos_y = cos(y)
+ cos_z = cos(z)
+ sin_x = sin(x)
+ sin_y = sin(y)
+ sin_z = sin(z)
+ r = np.array([[cos_y * cos_z, -cos_x * sin_z + sin_x * sin_y * cos_z,
+ sin_x * sin_z + cos_x * sin_y * cos_z],
+ [cos_y * sin_z, cos_x * cos_z + sin_x * sin_y * sin_z,
+ - sin_x * cos_z + cos_x * sin_y * sin_z],
+ [-sin_y, sin_x * cos_y, cos_x * cos_y]], dtype=float)
+ return r
+
+
+def rotation_angles(m):
+ """Find rotation angles from a transformation matrix
+
+ Parameters
+ ----------
+ m : array, shape >= (3, 3)
+ Rotation matrix. Only the top left 3 x 3 partition is accessed.
+
+ Returns
+ -------
+ x, y, z : float
+ Rotation around x, y and z axes.
+ """
+ x = np.arctan2(m[2, 1], m[2, 2])
+ c2 = np.sqrt(m[0, 0] ** 2 + m[1, 0] ** 2)
+ y = np.arctan2(-m[2, 0], c2)
+ s1 = np.sin(x)
+ c1 = np.cos(x)
+ z = np.arctan2(s1 * m[0, 2] - c1 * m[0, 1], c1 * m[1, 1] - s1 * m[1, 2])
+ return x, y, z
+
+
def scaling(x=1, y=1, z=1):
"""Create an array with a scaling matrix
@@ -114,6 +206,38 @@ def translation(x=0, y=0, z=0):
return m
+def _get_mri_head_t_from_trans_file(fname):
+ """Helper to convert "-trans.txt" to "-trans.fif" mri-type equivalent"""
+ # Read a Neuromag -> FreeSurfer transformation matrix
+ t = np.genfromtxt(fname)
+ if t.ndim != 2 or t.shape != (4, 4):
+ raise RuntimeError('File "%s" did not have 4x4 entries' % fname)
+ t = {'from': FIFF.FIFFV_COORD_HEAD, 'to': FIFF.FIFFV_COORD_MRI, 'trans': t}
+ return invert_transform(t)
+
+
+def combine_transforms(t_first, t_second, fro, to):
+ """Combine two transforms"""
+ if t_first['from'] != fro:
+ raise RuntimeError('From mismatch: %s ("%s") != %s ("%s")'
+ % (t_first['from'],
+ _coord_frame_name(t_first['from']),
+ fro, _coord_frame_name(fro)))
+ if t_first['to'] != t_second['from']:
+ raise RuntimeError('Transform mismatch: t1["to"] = %s ("%s"), '
+ 't2["from"] = %s ("%s")'
+ % (t_first['to'], _coord_frame_name(t_first['to']),
+ t_second['from'],
+ _coord_frame_name(t_second['from'])))
+ if t_second['to'] != to:
+ raise RuntimeError('To mismatch: %s ("%s") != %s ("%s")'
+ % (t_second['to'],
+ _coord_frame_name(t_second['to']),
+ to, _coord_frame_name(to)))
+ return {'from': fro, 'to': to, 'trans': np.dot(t_second['trans'],
+ t_first['trans'])}
+
+
def read_trans(fname):
"""Read a -trans.fif file
@@ -216,8 +340,7 @@ def transform_source_space_to(src, dest, trans):
"""
if src['coord_frame'] == dest:
- res = src
- return res
+ return src
if trans['to'] == src['coord_frame'] and trans['from'] == dest:
trans = invert_transform(trans)
@@ -226,12 +349,11 @@ def transform_source_space_to(src, dest, trans):
'coordinate transformation')
t = trans['trans'][:3, :]
- res = src
- res['coord_frame'] = dest
+ src['coord_frame'] = dest
- res['rr'] = np.dot(np.c_[res['rr'], np.ones((res['np'], 1))], t.T)
- res['nn'] = np.dot(np.c_[res['nn'], np.zeros((res['np'], 1))], t.T)
- return res
+ src['rr'] = np.dot(np.c_[src['rr'], np.ones((src['np'], 1))], t.T)
+ src['nn'] = np.dot(np.c_[src['nn'], np.zeros((src['np'], 1))], t.T)
+ return src
def transform_coordinates(filename, pos, orig, dest):
diff --git a/mne/transforms/__init__.py b/mne/transforms/__init__.py
deleted file mode 100644
index 990ca43..0000000
--- a/mne/transforms/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from .transforms import read_trans, write_trans, invert_transform, \
- transform_source_space_to, transform_coordinates
diff --git a/mne/transforms/coreg.py b/mne/transforms/coreg.py
deleted file mode 100644
index 8002831..0000000
--- a/mne/transforms/coreg.py
+++ /dev/null
@@ -1,67 +0,0 @@
-"""Coregistration between different coordinate frames"""
-
-# Authors: Christian Brodbeck <christianbrodbeck at nyu.edu>
-#
-# License: BSD (3-clause)
-
-import numpy as np
-from numpy import dot
-from scipy.optimize import leastsq
-
-from .transforms import apply_trans, rotation, translation
-
-
-def fit_matched_pts(src_pts, tgt_pts, tol=None, params=False):
- """Find a transform that minimizes the squared distance between two
- matching sets of points.
-
- Uses :func:`scipy.optimize.leastsq` to find a transformation involving
- rotation and translation.
-
- Parameters
- ----------
- src_pts : array, shape = (n, 3)
- Points to which the transform should be applied.
- tgt_pts : array, shape = (n, 3)
- Points to which src_pts should be fitted. Each point in tgt_pts should
- correspond to the point in src_pts with the same index.
- tol : scalar | None
- The error tolerance. If the distance between any of the matched points
- exceeds this value in the solution, a RuntimeError is raised. With
- None, no error check is performed.
- params : bool
- Also return the estimated rotation and translation parameters.
-
- Returns
- -------
- trans : array, shape = (4, 4)
- Transformation that, if applied to src_pts, minimizes the squared
- distance to tgt_pts.
- [rotation : array, len = 3, optional]
- The rotation parameters around the x, y, and z axes (in radians).
- [translation : array, len = 3, optional]
- The translation parameters in x, y, and z direction.
- """
- def error(params):
- trans = dot(translation(*params[:3]), rotation(*params[3:]))
- est = apply_trans(trans, src_pts)
- return (tgt_pts - est).ravel()
-
- x0 = (0, 0, 0, 0, 0, 0)
- x, _, _, _, _ = leastsq(error, x0, full_output=True)
-
- transl = x[:3]
- rot = x[3:]
- trans = dot(translation(*transl), rotation(*rot))
-
- # assess the error of the solution
- if tol is not None:
- est_pts = apply_trans(trans, src_pts)
- err = np.sqrt(np.sum((est_pts - tgt_pts) ** 2, axis=1))
- if np.any(err > tol):
- raise RuntimeError("Error exceeds tolerance. Error = %r" % err)
-
- if params:
- return trans, rot, transl
- else:
- return trans
diff --git a/mne/transforms/tests/test_coreg.py b/mne/transforms/tests/test_coreg.py
deleted file mode 100644
index 780c3b6..0000000
--- a/mne/transforms/tests/test_coreg.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from nose.tools import assert_raises
-import numpy as np
-from numpy.testing import assert_array_almost_equal
-
-from mne.transforms.coreg import fit_matched_pts
-from mne.transforms.transforms import apply_trans, rotation, translation
-
-
-def test_fit_matched_pts():
- """Test fitting two matching sets of points"""
- src_pts = np.random.normal(size=(5, 3))
- trans0 = np.dot(translation(2, 65, 3), rotation(2, 6, 3))
- tgt_pts = apply_trans(trans0, src_pts)
- trans = fit_matched_pts(tgt_pts, src_pts)
- est_pts = apply_trans(trans, tgt_pts)
- assert_array_almost_equal(src_pts, est_pts)
-
- # test exceeding tolerance
- src_pts[0, :] += 20
- assert_raises(RuntimeError, fit_matched_pts, src_pts, tgt_pts, tol=10)
diff --git a/mne/transforms/tests/test_transforms.py b/mne/transforms/tests/test_transforms.py
deleted file mode 100644
index 9995d74..0000000
--- a/mne/transforms/tests/test_transforms.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import os.path as op
-
-from nose.tools import assert_true
-from numpy.testing import assert_array_equal
-
-from mne.datasets import sample
-from mne import read_trans, write_trans
-from mne.utils import _TempDir
-
-data_path = sample.data_path()
-fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw-trans.fif')
-
-tempdir = _TempDir()
-
-
-def test_io_trans():
- """Test reading and writing of trans files
- """
- info0 = read_trans(fname)
- fname1 = op.join(tempdir, 'test-trans.fif')
- write_trans(fname1, info0)
- info1 = read_trans(fname1)
-
- # check all properties
- assert_true(info0['from'] == info1['from'])
- assert_true(info0['to'] == info1['to'])
- assert_array_equal(info0['trans'], info1['trans'])
- for d0, d1 in zip(info0['dig'], info1['dig']):
- assert_array_equal(d0['r'], d1['r'])
- for name in ['kind', 'ident', 'coord_frame']:
- assert_true(d0[name] == d1[name])
diff --git a/mne/utils.py b/mne/utils.py
index 9a7cf43..69583ee 100644
--- a/mne/utils.py
+++ b/mne/utils.py
@@ -12,6 +12,7 @@ import os
import os.path as op
from functools import wraps
import inspect
+from string import Formatter
import subprocess
import sys
from sys import stdout
@@ -25,9 +26,11 @@ import urllib
import urllib2
import ftplib
import urlparse
+import scipy
from scipy import linalg
-logger = logging.getLogger('mne')
+logger = logging.getLogger('mne') # one selection here used across mne-python
+logger.propagate = False # don't propagate (in case of multiple imports)
###############################################################################
@@ -60,6 +63,36 @@ def split_list(l, n):
yield l[(n - 1) * sz:]
+def create_chunks(sequence, size):
+ """Generate chunks from a sequence
+
+ Parameters
+ ----------
+ sequence : iterable
+ Any iterable object
+ size : int
+ The chunksize to be returned
+ """
+ return (sequence[p:p + size] for p in xrange(0, len(sequence), size))
+
+
+def sum_squared(X):
+ """Compute norm of an array
+
+ Parameters
+ ----------
+ X : array
+ Data whose norm must be found
+
+ Returns
+ -------
+ value : float
+ Sum of squares of the input array X
+ """
+ X_flat = X.ravel(order='F' if np.isfortran(X) else 'C')
+ return np.dot(X_flat, X_flat)
+
+
class WrapStdOut(object):
"""Ridiculous class to work around how doctest captures stdout"""
def __getattr__(self, name):
@@ -188,11 +221,31 @@ def run_subprocess(command, *args, **kwargs):
output = (stdout, stderr)
if p.returncode:
+ print output
raise subprocess.CalledProcessError(p.returncode, command, output)
return output
+class _FormatDict(dict):
+ """Helper for pformat()"""
+ def __missing__(self, key):
+ return "{" + key + "}"
+
+
+def pformat(temp, **fmt):
+ """Partially format a template string.
+
+ Examples
+ --------
+ >>> pformat("{a}_{b}", a='x')
+ 'x_{b}'
+ """
+ formatter = Formatter()
+ mapping = _FormatDict(fmt)
+ return formatter.vformat(temp, (), mapping)
+
+
###############################################################################
# DECORATORS
@@ -343,15 +396,25 @@ requires_mne = np.testing.dec.skipif(not has_command_line_tools(),
'Requires MNE command line tools')
-def has_nibabel():
+def has_nibabel(vox2ras_tkr=False):
try:
import nibabel
- return True
+ if vox2ras_tkr: # we need MGHHeader to have vox2ras_tkr param
+ mgh_ihdr = getattr(nibabel, 'MGHImage', None)
+ mgh_ihdr = getattr(mgh_ihdr, 'header_class', None)
+ get_vox2ras_tkr = getattr(mgh_ihdr, 'get_vox2ras_tkr', None)
+ if get_vox2ras_tkr is not None:
+ return True
+ else:
+ return False
+ else:
+ return True
except ImportError:
return False
def has_freesurfer():
+ """Aux function"""
if not 'FREESURFER_HOME' in os.environ:
return False
else:
@@ -362,12 +425,49 @@ requires_fs_or_nibabel = np.testing.dec.skipif(not has_nibabel() and
not has_freesurfer(),
'Requires nibabel or '
'Freesurfer')
-requires_nibabel = np.testing.dec.skipif(not has_nibabel(),
- 'Requires nibabel')
+
+
+def requires_nibabel(vox2ras_tkr=False):
+ """Aux function"""
+ if vox2ras_tkr:
+ extra = ' with vox2ras_tkr support'
+ else:
+ extra = ''
+ return np.testing.dec.skipif(not has_nibabel(vox2ras_tkr),
+ 'Requires nibabel%s' % extra)
+
requires_freesurfer = np.testing.dec.skipif(not has_freesurfer(),
'Requires Freesurfer')
+def requires_mem_gb(requirement):
+ """Decorator to skip test if insufficient memory is available"""
+ def real_decorator(function):
+ # convert to gb
+ req = int(1e9 * requirement)
+ try:
+ import psutil
+ has_psutil = True
+ except ImportError:
+ has_psutil = False
+
+ @wraps(function)
+ def dec(*args, **kwargs):
+ if has_psutil and psutil.virtual_memory().available >= req:
+ skip = False
+ else:
+ skip = True
+
+ if skip is True:
+ from nose.plugins.skip import SkipTest
+ raise SkipTest('Test %s skipped, requires >= %0.1f GB free '
+ 'memory' % (function.__name__, requirement))
+ ret = function(*args, **kwargs)
+ return ret
+ return dec
+ return real_decorator
+
+
def requires_pandas(function):
"""Decorator to skip test if pandas is not available"""
@wraps(function)
@@ -392,6 +492,27 @@ def requires_pandas(function):
return dec
+def requires_tvtk(function):
+ """Decorator to skip test if TVTK is not available"""
+ @wraps(function)
+ def dec(*args, **kwargs):
+ skip = False
+ try:
+ from tvtk.api import tvtk
+ except ImportError:
+ skip = True
+
+ if skip is True:
+ from nose.plugins.skip import SkipTest
+ raise SkipTest('Test %s skipped, requires TVTK'
+ % function.__name__)
+ ret = function(*args, **kwargs)
+
+ return ret
+
+ return dec
+
+
def make_skipper_dec(module, skip_str):
"""Helper to make skipping decorators"""
skip = False
@@ -406,6 +527,54 @@ requires_sklearn = make_skipper_dec('sklearn', 'scikit-learn not installed')
requires_nitime = make_skipper_dec('nitime', 'nitime not installed')
+def _mne_fs_not_in_env():
+ """Aux function"""
+ return (('FREESURFER_HOME' not in os.environ) or
+ ('MNE_ROOT' not in os.environ))
+
+requires_mne_fs_in_env = np.testing.dec.skipif(_mne_fs_not_in_env)
+
+
+def check_sklearn_version(min_version):
+ """ Check minimum sklearn version required
+
+ Parameters
+ ----------
+ min_version : str
+ The version string. Anything that matches
+ ``'(\\d+ | [a-z]+ | \\.)'``
+ """
+ ok = True
+ try:
+ import sklearn
+ this_version = LooseVersion(sklearn.__version__)
+ if this_version < min_version:
+ ok = False
+ except ImportError:
+ ok = False
+ return ok
+
+
+def check_scipy_version(min_version):
+ """ Check minimum sklearn version required
+
+ Parameters
+ ----------
+ min_version : str
+ The version string. Anything that matches
+ ``'(\\d+ | [a-z]+ | \\.)'``
+ """
+ this_version = LooseVersion(scipy.__version__)
+ return False if this_version < min_version else True
+
+
+def requires_scipy_version(min_version):
+ """Helper for testing"""
+ ok = check_scipy_version(min_version)
+ return np.testing.dec.skipif(not ok, 'Requires scipy version >= %s'
+ % min_version)
+
+
###############################################################################
# LOGGING
@@ -535,16 +704,61 @@ def get_config_path():
return val
+def set_cache_dir(cache_dir):
+ """Set the directory to be used for temporary file storage.
+
+ This directory is used by joblib to store memmapped arrays,
+ which reduces memory requirements and speeds up parallel
+ computation.
+
+ Parameters
+ ----------
+ cache_dir: str or None
+ Directory to use for temporary file storage. None disables
+ temporary file storage.
+ """
+ if cache_dir is not None and not op.exists(cache_dir):
+ raise IOError('Directory %s does not exist' % cache_dir)
+
+ set_config('MNE_CACHE_DIR', cache_dir)
+
+
+def set_memmap_min_size(memmap_min_size):
+ """Set the minimum size for memmaping of arrays for parallel processing
+
+ Parameters
+ ----------
+ memmap_min_size: str or None
+ Threshold on the minimum size of arrays that triggers automated memmory
+ mapping for parallel processing, e.g., '1M' for 1 megabyte.
+ Use None to disable memmaping of large arrays.
+ """
+ if memmap_min_size is not None:
+ if not isinstance(memmap_min_size, basestring):
+ raise ValueError('\'memmap_min_size\' has to be a string.')
+ if memmap_min_size[-1] not in ['K', 'M', 'G']:
+ raise ValueError('The size has to be given in kilo-, mega-, or '
+ 'gigabytes, e.g., 100K, 500M, 1G.')
+
+ set_config('MNE_MEMMAP_MIN_SIZE', memmap_min_size)
+
+
# List the known configuration values
known_config_types = [
'MNE_BROWSE_RAW_SIZE',
'MNE_CUDA_IGNORE_PRECISION',
'MNE_DATASETS_MEGSIM_PATH',
'MNE_DATASETS_SAMPLE_PATH',
+ 'MNE_DATASETS_SPM_FACE_PATH',
'MNE_LOGGING_LEVEL',
'MNE_USE_CUDA',
'SUBJECTS_DIR',
+ 'MNE_CACHE_DIR',
+ 'MNE_MEMMAP_MIN_SIZE',
+ 'MNE_SKIP_SAMPLE_DATASET_TESTS',
+ 'MNE_DATASETS_SPM_FACE_DATASETS_TESTS'
]
+
# These allow for partial matches, e.g. 'MNE_STIM_CHANNEL_1' is okay key
known_config_wildcards = [
'MNE_STIM_CHANNEL',
@@ -977,6 +1191,7 @@ def _check_subject(class_subject, input_subject, raise_error=True):
def _check_pandas_installed():
+ """Aux function"""
try:
import pandas as pd
return pd
diff --git a/mne/viz.py b/mne/viz.py
index d7769b5..2e4e339 100644
--- a/mne/viz.py
+++ b/mne/viz.py
@@ -4,6 +4,7 @@
# Authors: Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
# Denis Engemann <d.engemann at fz-juelich.de>
# Martin Luessi <mluessi at nmr.mgh.harvard.edu>
+# Eric Larson <larson.eric.d at gmail.com>
#
# License: Simplified BSD
import os
@@ -12,6 +13,7 @@ from itertools import cycle
from functools import partial
from copy import deepcopy
import math
+from distutils.version import LooseVersion
import difflib
import tempfile
@@ -23,38 +25,40 @@ import numpy as np
from scipy import linalg
from scipy import ndimage
from matplotlib import delaunay
-
-import logging
-logger = logging.getLogger('mne')
from warnings import warn
+from collections import deque
+# XXX : don't import pyplot here or you will break the doc
-# XXX : don't import pylab here or you will break the doc
from .fixes import tril_indices, Counter
from .baseline import rescale
-from .utils import deprecated, get_subjects_dir, get_config, set_config, \
- _check_subject
+from .utils import (get_subjects_dir, get_config, set_config, _check_subject,
+ logger, verbose)
from .fiff import show_fiff, FIFF
from .fiff.pick import channel_type, pick_types
from .fiff.proj import make_projector, setup_proj
-from . import verbose
+from .fixes import normalize_colors
+from .utils import create_chunks
+from .time_frequency import compute_raw_psd
COLORS = ['b', 'g', 'r', 'c', 'm', 'y', 'k', '#473C8B', '#458B74',
'#CD7F32', '#FF4040', '#ADFF2F', '#8E2323', '#FF1493']
DEFAULTS = dict(color=dict(mag='darkblue', grad='b', eeg='k', eog='k', ecg='r',
- emg='k', ref_meg='steelblue', misc='k', stim='k',
- resp='k', chpi='k'),
+ emg='k', ref_meg='steelblue', misc='k', stim='k',
+ resp='k', chpi='k', exci='k', ias='k', syst='k'),
units=dict(eeg='uV', grad='fT/cm', mag='fT', misc='AU'),
scalings=dict(eeg=1e6, grad=1e13, mag=1e15, misc=1.0),
scalings_plot_raw=dict(mag=1e-12, grad=4e-11, eeg=20e-6,
- eog=150e-6, ecg=5e-4, emg=1e-3, ref_meg=1e-12, misc=1e-3,
- stim=1, resp=1, chpi=1e-4),
- ylim=dict(mag=(-600., 600.), grad=(-200., 200.), eeg=(-200., 200.),
- misc=(-5., 5.)),
+ eog=150e-6, ecg=5e-4, emg=1e-3,
+ ref_meg=1e-12, misc=1e-3,
+ stim=1, resp=1, chpi=1e-4, exci=1,
+ ias=1, syst=1),
+ ylim=dict(mag=(-600., 600.), grad=(-200., 200.),
+ eeg=(-200., 200.), misc=(-5., 5.)),
titles=dict(eeg='EEG', grad='Gradiometers',
- mag='Magnetometers', misc='misc'))
+ mag='Magnetometers', misc='misc'))
def _mutable_defaults(*mappings):
@@ -93,7 +97,15 @@ def _clean_names(names):
# prepare plot
"""
- return [n.replace(' ', '') if ' ' in n else n for n in names]
+ cleaned = []
+ for name in names:
+ if ' ' in name:
+ name = name.replace(' ', '')
+ if '-' in name:
+ name = name.split('-')[0]
+ cleaned.append(name)
+
+ return cleaned
def _check_delayed_ssp(container):
@@ -101,7 +113,7 @@ def _check_delayed_ssp(container):
"""
if container.proj is True:
raise RuntimeError('Projs are already applied. Please initialize'
- ' the data with proj set to False.')
+ ' the data with proj set to False.')
elif len(container.info['projs']) < 1:
raise RuntimeError('No projs found in evoked.')
@@ -109,7 +121,7 @@ def _check_delayed_ssp(container):
def tight_layout(pad=1.2, h_pad=None, w_pad=None):
""" Adjust subplot parameters to give specified padding.
- Note. For plotting please use this function instead of pl.tight_layout
+ Note. For plotting please use this function instead of plt.tight_layout
Parameters
----------
@@ -120,17 +132,19 @@ def tight_layout(pad=1.2, h_pad=None, w_pad=None):
padding (height/width) between edges of adjacent subplots.
Defaults to `pad_inches`.
"""
- try:
- import pylab as pl
- pl.tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad)
- except:
- msg = ('Matplotlib function \'tight_layout\'%s.'
- ' Skipping subpplot adjusment.')
- if not hasattr(pl, 'tight_layout'):
- case = ' is not available'
- else:
- case = ' seems corrupted'
- warn(msg % case)
+ import matplotlib.pyplot as plt
+ if plt.get_backend().lower() != 'agg':
+ try:
+ plt.tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad)
+ except:
+ msg = ('Matplotlib function \'tight_layout\'%s.'
+ ' Skipping subpplot adjusment.')
+ if not hasattr(plt, 'tight_layout'):
+ case = ' is not available'
+ else:
+ case = (' is not supported by your backend: `%s`'
+ % plt.get_backend())
+ warn(msg % case)
def _plot_topo(info=None, times=None, show_func=None, layout=None,
@@ -138,40 +152,41 @@ def _plot_topo(info=None, times=None, show_func=None, layout=None,
border='none', cmap=None, layout_scale=None, title=None,
x_label=None, y_label=None, vline=None):
"""Helper function to plot on sensor layout"""
- import pylab as pl
- orig_facecolor = pl.rcParams['axes.facecolor']
- orig_edgecolor = pl.rcParams['axes.edgecolor']
+ import matplotlib.pyplot as plt
+ orig_facecolor = plt.rcParams['axes.facecolor']
+ orig_edgecolor = plt.rcParams['axes.edgecolor']
try:
if cmap is None:
- cmap = pl.cm.jet
+ cmap = plt.cm.jet
ch_names = _clean_names(info['ch_names'])
- pl.rcParams['axes.facecolor'] = 'k'
- fig = pl.figure(facecolor='k')
+ plt.rcParams['axes.facecolor'] = 'k'
+ fig = plt.figure(facecolor='k')
pos = layout.pos.copy()
tmin, tmax = times[0], times[-1]
if colorbar:
pos[:, :2] *= layout_scale
- pl.rcParams['axes.edgecolor'] = 'k'
- sm = pl.cm.ScalarMappable(cmap=cmap,
- norm=pl.normalize(vmin=vmin, vmax=vmax))
+ plt.rcParams['axes.edgecolor'] = 'k'
+ norm = normalize_colors(vmin=vmin, vmax=vmax)
+ sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array(np.linspace(vmin, vmax))
- ax = pl.axes([0.015, 0.025, 1.05, .8], axisbg='k')
+ ax = plt.axes([0.015, 0.025, 1.05, .8], axisbg='k')
cb = fig.colorbar(sm, ax=ax)
- cb_yticks = pl.getp(cb.ax.axes, 'yticklabels')
- pl.setp(cb_yticks, color='w')
- pl.rcParams['axes.edgecolor'] = border
+ cb_yticks = plt.getp(cb.ax.axes, 'yticklabels')
+ plt.setp(cb_yticks, color='w')
+ plt.rcParams['axes.edgecolor'] = border
for idx, name in enumerate(_clean_names(layout.names)):
if name in ch_names:
- ax = pl.axes(pos[idx], axisbg='k')
+ ax = plt.axes(pos[idx], axisbg='k')
ch_idx = ch_names.index(name)
# hack to inlcude channel idx and name, to use in callback
ax.__dict__['_mne_ch_name'] = name
ax.__dict__['_mne_ch_idx'] = ch_idx
if layout.kind == 'Vectorview-all' and ylim is not None:
- this_type = {'mag': 0, 'grad': 1}[channel_type(info, ch_idx)]
+ this_type = {'mag': 0, 'grad': 1}[channel_type(info,
+ ch_idx)]
ylim_ = [v[this_type] if _check_vlim(v) else
- v for v in ylim]
+ v for v in ylim]
else:
ylim_ = ylim
@@ -179,9 +194,9 @@ def _plot_topo(info=None, times=None, show_func=None, layout=None,
vmax=vmax, ylim=ylim_)
if ylim_ and not any(v is None for v in ylim_):
- pl.ylim(*ylim_)
- pl.xticks([], ())
- pl.yticks([], ())
+ plt.ylim(*ylim_)
+ plt.xticks([], ())
+ plt.yticks([], ())
# register callback
callback = partial(_plot_topo_onpick, show_func=show_func, tmin=tmin,
@@ -192,12 +207,12 @@ def _plot_topo(info=None, times=None, show_func=None, layout=None,
fig.canvas.mpl_connect('pick_event', callback)
if title is not None:
- pl.figtext(0.03, 0.9, title, color='w', fontsize=19)
+ plt.figtext(0.03, 0.9, title, color='w', fontsize=19)
finally:
- # Revert global pylab config
- pl.rcParams['axes.facecolor'] = orig_facecolor
- pl.rcParams['axes.edgecolor'] = orig_edgecolor
+ # Revert global pyplot config
+ plt.rcParams['axes.facecolor'] = orig_facecolor
+ plt.rcParams['axes.edgecolor'] = orig_edgecolor
return fig
@@ -213,22 +228,22 @@ def _plot_topo_onpick(event, show_func=None, tmin=None, tmax=None,
artist = event.artist
try:
- import pylab as pl
+ import matplotlib.pyplot as plt
ch_idx = artist.axes._mne_ch_idx
- fig, ax = pl.subplots(1)
+ fig, ax = plt.subplots(1)
ax.set_axis_bgcolor('k')
- show_func(pl, ch_idx, tmin, tmax, vmin, vmax, ylim=ylim,
+ show_func(plt, ch_idx, tmin, tmax, vmin, vmax, ylim=ylim,
vline=vline)
if colorbar:
- pl.colorbar()
+ plt.colorbar()
if title is not None:
- pl.title(title + ' ' + artist.axes._mne_ch_name)
+ plt.title(title + ' ' + artist.axes._mne_ch_name)
else:
- pl.title(artist.axes._mne_ch_name)
+ plt.title(artist.axes._mne_ch_name)
if x_label is not None:
- pl.xlabel(x_label)
+ plt.xlabel(x_label)
if y_label is not None:
- pl.ylabel(y_label)
+ plt.ylabel(y_label)
except Exception as err:
# matplotlib silently ignores exceptions in event handlers, so we print
# it here to know what went wrong
@@ -256,8 +271,8 @@ def _plot_timeseries(ax, ch_idx, tmin, tmax, vmin, vmax, ylim, data, color,
else:
ax.plot(times, data_[ch_idx], color_)
if vline:
- import pylab as pl
- [pl.axvline(x, color='w', linewidth=0.5) for x in vline]
+ import matplotlib.pyplot as plt
+ [plt.axvline(x, color='w', linewidth=0.5) for x in vline]
def _check_vlim(vlim):
@@ -356,7 +371,8 @@ def plot_topo(evoked, layout=None, layout_scale=0.945, color=None,
is_meg = any(types_used == set(k) for k in meg_types)
if is_meg:
types_used = list(types_used)[::-1] # -> restore kwarg order
- picks = [pick_types(info, meg=k, exclude=[]) for k in types_used]
+ picks = [pick_types(info, meg=kk, ref_meg=False, exclude=[])
+ for kk in types_used]
else:
types_used_kwargs = dict((t, True) for t in types_used)
picks = [pick_types(info, meg=False, **types_used_kwargs)]
@@ -384,7 +400,7 @@ def plot_topo(evoked, layout=None, layout_scale=0.945, color=None,
ylim_ = (-ymax, ymax)
elif isinstance(ylim, dict):
ylim_ = _mutable_defaults(('ylim', ylim))[0]
- ylim_ = [ylim_[k] for k in types_used]
+ ylim_ = [ylim_[kk] for kk in types_used]
ylim_ = zip(*[np.array(yl) for yl in ylim_])
else:
raise ValueError('ylim must be None ore a dict')
@@ -457,7 +473,7 @@ def plot_topo_tfr(epochs, tfr, freq, layout=None, colorbar=True, vmin=None,
Minimum value mapped to lowermost color
vmax : float
Minimum value mapped to upppermost color
- cmap : instance of matplotlib.pylab.colormap
+ cmap : instance of matplotlib.pyplot.colormap
Colors to be mapped to the values
layout_scale : float
Scaling factor for adjusting the relative size of the layout
@@ -535,7 +551,7 @@ def plot_topo_power(epochs, power, freq, layout=None, baseline=None,
Minimum value mapped to lowermost color
vmax : float
Minimum value mapped to upppermost color
- cmap : instance of matplotlib.pylab.colormap
+ cmap : instance of matplotlib.pyplot.colormap
Colors to be mapped to the values
layout_scale : float
Scaling factor for adjusting the relative size of the layout
@@ -622,7 +638,7 @@ def plot_topo_phase_lock(epochs, phase, freq, layout=None, baseline=None,
Minimum value mapped to lowermost color
vmax : float
Minimum value mapped to upppermost color
- cmap : instance of matplotlib.pylab.colormap
+ cmap : instance of matplotlib.pyplot.colormap
Colors to be mapped to the values
layout_scale : float
Scaling factor for adjusting the relative size of the layout
@@ -712,7 +728,7 @@ def plot_topo_image_epochs(epochs, layout=None, sigma=0.3, vmin=None,
the number of good epochs. If it's a callable the arguments
passed are the times vector and the data as 2d array
(data.shape[1] == len(times)).
- cmap : instance of matplotlib.pylab.colormap
+ cmap : instance of matplotlib.pyplot.colormap
Colors to be mapped to the values.
layout_scale: float
scaling factor for adjusting the relative size of the layout
@@ -743,9 +759,10 @@ def plot_topo_image_epochs(epochs, layout=None, sigma=0.3, vmin=None,
erf_imshow = partial(_erfimage_imshow, scalings=scalings, order=order,
data=data, epochs=epochs, sigma=sigma)
- fig = _plot_topo(info=epochs.info, times=epochs.times, show_func=erf_imshow,
- layout=layout, decim=1, colorbar=colorbar, vmin=vmin,
- vmax=vmax, cmap=cmap, layout_scale=layout_scale, title=title,
+ fig = _plot_topo(info=epochs.info, times=epochs.times,
+ show_func=erf_imshow, layout=layout, decim=1,
+ colorbar=colorbar, vmin=vmin, vmax=vmax, cmap=cmap,
+ layout_scale=layout_scale, title=title,
border='w', x_label='Time (s)', y_label='Epoch')
return fig
@@ -798,9 +815,9 @@ def plot_evoked_topomap(evoked, times=None, ch_type='mag', layout=None,
a check box for reversible selection of SSP projection vectors will
be show.
show : bool
- Call pylab.show() at the end.
+ Call pyplot.show() at the end.
"""
- import pylab as pl
+ import matplotlib.pyplot as plt
if scale is None:
if ch_type.startswith('planar'):
@@ -818,55 +835,22 @@ def plot_evoked_topomap(evoked, times=None, ch_type='mag', layout=None,
raise RuntimeError('Too many plots requested. Please pass fewer '
'than 20 time instants.')
tmin, tmax = evoked.times[[0, -1]]
- for ii, t in enumerate(times):
+ for t in times:
if not tmin <= t <= tmax:
raise ValueError('Times should be between %0.3f and %0.3f. (Got '
'%0.3f).' % (tmin, tmax, t))
- info = copy.deepcopy(evoked.info)
-
- if layout is None:
- from .layouts.layout import find_layout
- layout = find_layout(info['chs'])
- elif layout == 'auto':
- layout = None
-
- info['ch_names'] = _clean_names(info['ch_names'])
- for ii, this_ch in enumerate(info['chs']):
- this_ch['ch_name'] = info['ch_names'][ii]
-
- if layout is not None:
- layout = copy.deepcopy(layout)
- layout.names = _clean_names(layout.names)
-
- # special case for merging grad channels
- if (ch_type == 'grad' and FIFF.FIFFV_COIL_VV_PLANAR_T1 in
- np.unique([ch['coil_type'] for ch in info['chs']])):
- from .layouts.layout import _pair_grad_sensors, _merge_grad_data
- picks, pos = _pair_grad_sensors(info, layout)
- merge_grads = True
- else:
- merge_grads = False
- picks = pick_types(info, meg=ch_type, exclude='bads')
- if len(picks) == 0:
- raise ValueError("No channels of type %r" % ch_type)
-
- if layout is None:
- chs = [info['chs'][i] for i in picks]
- from .layouts.layout import _find_topomap_coords
- pos = _find_topomap_coords(chs, layout)
- else:
- pos = [layout.pos[layout.names.index(info['ch_names'][k])] for k in
- picks]
+ picks, pos, merge_grads = _prepare_topo_plot(evoked, ch_type, layout)
n = len(times)
nax = n + bool(colorbar)
width = size * nax
height = size * 1. + max(0, 0.1 * (3 - size))
- fig = pl.figure(figsize=(width, height))
- w_frame = pl.rcParams['figure.subplot.wspace'] / (2 * nax)
+ fig = plt.figure(figsize=(width, height))
+ w_frame = plt.rcParams['figure.subplot.wspace'] / (2 * nax)
top_frame = max(.05, .2 / size)
- fig.subplots_adjust(left=w_frame, right=1 - w_frame, bottom=0, top=1 - top_frame)
+ fig.subplots_adjust(left=w_frame, right=1 - w_frame, bottom=0,
+ top=1 - top_frame)
time_idx = [np.where(evoked.times >= t)[0][0] for t in times]
if proj is True and evoked.proj is not True:
@@ -876,18 +860,19 @@ def plot_evoked_topomap(evoked, times=None, ch_type='mag', layout=None,
data = data[np.ix_(picks, time_idx)] * scale
if merge_grads:
+ from .layouts.layout import _merge_grad_data
data = _merge_grad_data(data)
vmax = vmax or np.max(np.abs(data))
images = []
for i, t in enumerate(times):
- pl.subplot(1, nax, i + 1)
+ plt.subplot(1, nax, i + 1)
images.append(plot_topomap(data[:, i], pos, vmax=vmax, cmap=cmap,
sensors=sensors, res=res))
- pl.title('%i ms' % (t * 1000))
+ plt.title('%i ms' % (t * 1000))
if colorbar:
- cax = pl.subplot(1, n + 1, n + 1)
- pl.colorbar(cax=cax, ticks=[-vmax, 0, vmax], format=format)
+ cax = plt.subplot(1, n + 1, n + 1)
+ plt.colorbar(cax=cax, ticks=[-vmax, 0, vmax], format=format)
# resize the colorbar (by default the color fills the whole axes)
cpos = cax.get_position()
cpos.x0 = 1 - (.7 + .1 / size) / nax
@@ -907,7 +892,7 @@ def plot_evoked_topomap(evoked, times=None, ch_type='mag', layout=None,
_draw_proj_checkbox(None, params)
if show:
- pl.show()
+ plt.show()
return fig
@@ -923,8 +908,8 @@ def _plot_update_evoked_topomap(params, bools):
new_evoked.add_proj(projs)
new_evoked.apply_proj()
- data = new_evoked.data[np.ix_(params['picks'], params['time_idx'])] \
- * params['scale']
+ data = new_evoked.data[np.ix_(params['picks'],
+ params['time_idx'])] * params['scale']
if params['merge_grads']:
from .layouts.layout import _merge_grad_data
data = _merge_grad_data(data)
@@ -975,7 +960,7 @@ def plot_projs_topomap(projs, layout=None, cmap='RdBu_r', sensors='k,',
show : bool
Show figures if True
"""
- import pylab as pl
+ import matplotlib.pyplot as plt
if layout is None:
from .layouts import read_layout
@@ -988,13 +973,16 @@ def plot_projs_topomap(projs, layout=None, cmap='RdBu_r', sensors='k,',
nrows = math.floor(math.sqrt(n_projs))
ncols = math.ceil(n_projs / nrows)
- pl.clf()
+ plt.clf()
for k, proj in enumerate(projs):
- ch_names = proj['data']['col_names']
+
+ ch_names = _clean_names(proj['data']['col_names'])
data = proj['data']['data'].ravel()
idx = []
for l in layout:
+ l = copy.deepcopy(l)
+ l.names = _clean_names(l.names)
is_vv = l.kind.startswith('Vectorview')
if is_vv:
from .layouts.layout import _pair_grad_sensors_from_ch_names
@@ -1015,22 +1003,23 @@ def plot_projs_topomap(projs, layout=None, cmap='RdBu_r', sensors='k,',
break
- ax = pl.subplot(nrows, ncols, k + 1)
+ ax = plt.subplot(nrows, ncols, k + 1)
ax.set_title(proj['desc'])
if len(idx):
plot_topomap(data, pos, vmax=None, cmap=cmap,
sensors=sensors, res=res)
if colorbar:
- pl.colorbar()
+ plt.colorbar()
else:
raise RuntimeError('Cannot find a proper layout for projection %s'
% proj['desc'])
if show:
- pl.show()
+ plt.show()
-def plot_topomap(data, pos, vmax=None, cmap='RdBu_r', sensors='k,', res=100):
+def plot_topomap(data, pos, vmax=None, cmap='RdBu_r', sensors='k,', res=100,
+ axis=None):
"""Plot a topographic map as image
Parameters
@@ -1049,8 +1038,10 @@ def plot_topomap(data, pos, vmax=None, cmap='RdBu_r', sensors='k,', res=100):
format string (e.g., 'r+' for red plusses).
res : int
The resolution of the topomap image (n pixels along each side).
+ axis : instance of Axes | None
+ The axis to plot to. If None, the current axis will be used.
"""
- import pylab as pl
+ import matplotlib.pyplot as plt
data = np.asarray(data)
pos = np.asarray(pos)
@@ -1062,20 +1053,21 @@ def plot_topomap(data, pos, vmax=None, cmap='RdBu_r', sensors='k,', res=100):
err = ("Data and pos need to be of same length. Got data of shape %s, "
"pos of shape %s." % (str(), str()))
- axes = pl.gca()
+ axes = plt.gca()
axes.set_frame_on(False)
vmax = vmax or np.abs(data).max()
- pl.xticks(())
- pl.yticks(())
+ plt.xticks(())
+ plt.yticks(())
pos_x = pos[:, 0]
pos_y = pos[:, 1]
+ ax = axis if axis else plt
if sensors:
- if sensors == True:
+ if sensors is True:
sensors = 'k,'
- pl.plot(pos_x, pos_y, sensors)
+ ax.plot(pos_x, pos_y, sensors)
xmin, xmax = pos_x.min(), pos_x.max()
ymin, ymax = pos_y.min(), pos_y.max()
@@ -1088,8 +1080,7 @@ def plot_topomap(data, pos, vmax=None, cmap='RdBu_r', sensors='k,', res=100):
im = interp[yi.min():yi.max():complex(0, yi.shape[0]),
xi.min():xi.max():complex(0, xi.shape[1])]
im = np.ma.masked_array(im, im == np.nan)
-
- im = pl.imshow(im, cmap=cmap, vmin=-vmax, vmax=vmax, origin='lower',
+ im = ax.imshow(im, cmap=cmap, vmin=-vmax, vmax=vmax, origin='lower',
aspect='equal', extent=(xmin, xmax, ymin, ymax))
return im
@@ -1113,11 +1104,11 @@ def plot_evoked(evoked, picks=None, exclude='bads', unit=True, show=True,
unit : bool
Scale plot with channel (SI) unit.
show : bool
- Call pylab.show() as the end or not.
+ Call pyplot.show() as the end or not.
ylim : dict | None
ylim for plots. e.g. ylim = dict(eeg=[-200e-6, 200e6])
Valid keys are eeg, mag, grad, misc. If None, the ylim parameter
- for each channel equals the pylab default.
+ for each channel equals the pyplot default.
xlim : 'tight' | tuple | None
xlim for plots.
proj : bool | 'interactive'
@@ -1140,7 +1131,7 @@ def plot_evoked(evoked, picks=None, exclude='bads', unit=True, show=True,
the same length as the number of channel types. If instance of
Axes, there must be only one channel type plotted.
"""
- import pylab as pl
+ import matplotlib.pyplot as plt
if axes is not None and proj == 'interactive':
raise RuntimeError('Currently only single axis figures are supported'
' for interactive SSP selection.')
@@ -1175,17 +1166,24 @@ def plot_evoked(evoked, picks=None, exclude='bads', unit=True, show=True,
n_channel_types += 1
ch_types_used.append(t)
+ axes_init = axes # remember if axes where given as input
+
+ fig = None
if axes is None:
- pl.clf()
- axes = [pl.subplot(n_channel_types, 1, c + 1)
- for c in range(n_channel_types)]
- if not isinstance(axes, list):
+ fig, axes = plt.subplots(n_channel_types, 1)
+
+ if isinstance(axes, plt.Axes):
axes = [axes]
+ elif isinstance(axes, np.ndarray):
+ axes = list(axes)
+
+ if axes_init is not None:
+ fig = axes[0].get_figure()
+
if not len(axes) == n_channel_types:
raise ValueError('Number of axes (%g) must match number of channel '
'types (%g)' % (len(axes), n_channel_types))
- fig = axes[0].get_figure()
# instead of projecting during each iteration let's use the mixin here.
if proj is True and evoked.proj is not True:
@@ -1212,25 +1210,26 @@ def plot_evoked(evoked, picks=None, exclude='bads', unit=True, show=True,
ax._get_lines.color_cycle = cycle(['k'])
D = this_scaling * evoked.data[idx, :]
- pl.axes(ax)
+ # plt.axes(ax)
ax.plot(times, D.T)
if xlim is not None:
if xlim == 'tight':
xlim = (times[0], times[-1])
- pl.xlim(xlim)
+ ax.set_xlim(xlim)
if ylim is not None and t in ylim:
- pl.ylim(ylim[t])
- pl.title(titles[t] + ' (%d channel%s)' % (
- len(D), 's' if len(D) > 1 else ''))
- pl.xlabel('time (ms)')
- pl.ylabel('data (%s)' % ch_unit)
+ ax.set_ylim(ylim[t])
+ ax.set_title(titles[t] + ' (%d channel%s)' % (
+ len(D), 's' if len(D) > 1 else ''))
+ ax.set_xlabel('time (ms)')
+ ax.set_ylabel('data (%s)' % ch_unit)
if hline is not None:
for h in hline:
- pl.axhline(h, color='r', linestyle='--', linewidth=2)
+ ax.axhline(h, color='r', linestyle='--', linewidth=2)
- pl.subplots_adjust(0.175, 0.08, 0.94, 0.94, 0.2, 0.63)
- tight_layout()
+ if axes_init is None:
+ plt.subplots_adjust(0.175, 0.08, 0.94, 0.94, 0.2, 0.63)
+ tight_layout()
if proj == 'interactive':
_check_delayed_ssp(evoked)
@@ -1240,8 +1239,8 @@ def plot_evoked(evoked, picks=None, exclude='bads', unit=True, show=True,
plot_update_proj_callback=_plot_update_evoked)
_draw_proj_checkbox(None, params)
- if show:
- pl.show()
+ if show and plt.get_backend() != 'agg':
+ fig.show()
return fig
@@ -1252,7 +1251,7 @@ def _plot_update_evoked(params, bools):
picks, evoked = [params[k] for k in 'picks', 'evoked']
times = evoked.times * 1e3
projs = [proj for ii, proj in enumerate(params['projs'])
- if ii in np.where(bools)[0]]
+ if ii in np.where(bools)[0]]
params['proj_bools'] = bools
new_evoked = evoked.copy()
new_evoked.info['projs'] = []
@@ -1268,20 +1267,21 @@ def _plot_update_evoked(params, bools):
def _draw_proj_checkbox(event, params, draw_current_state=True):
"""Toggle options (projectors) dialog"""
- import pylab as pl
+ import matplotlib.pyplot as plt
+ import matplotlib as mpl
projs = params['projs']
# turn on options dialog
fig_proj = figure_nobar()
fig_proj.canvas.set_window_title('SSP projection vectors')
- ax_temp = pl.axes((0, 0, 1, 1))
+ ax_temp = plt.axes((0, 0, 1, 1))
ax_temp.get_yaxis().set_visible(False)
ax_temp.get_xaxis().set_visible(False)
fig_proj.add_axes(ax_temp)
labels = [p['desc'] for p in projs]
actives = [p['active'] for p in projs] if draw_current_state else \
[True] * len(params['projs'])
- proj_checks = pl.mpl.widgets.CheckButtons(ax_temp, labels=labels,
- actives=actives)
+ proj_checks = mpl.widgets.CheckButtons(ax_temp, labels=labels,
+ actives=actives)
# change already-applied projectors to red
for ii, p in enumerate(projs):
if p['active'] is True:
@@ -1403,10 +1403,10 @@ def plot_sparse_source_estimates(src, stcs, colors=None, linewidth=2,
use_faces, color=brain_color,
opacity=opacity, **kwargs)
- import pylab as pl
+ import matplotlib.pyplot as plt
# Show time courses
- pl.figure(fig_number)
- pl.clf()
+ plt.figure(fig_number)
+ plt.clf()
colors = cycle(colors)
@@ -1414,7 +1414,7 @@ def plot_sparse_source_estimates(src, stcs, colors=None, linewidth=2,
if labels is not None:
colors = [colors.next() for _ in
- range(np.unique(np.concatenate(labels).ravel()).size)]
+ range(np.unique(np.concatenate(labels).ravel()).size)]
for idx, v in enumerate(unique_vertnos):
# get indices of stcs it belongs to
@@ -1444,17 +1444,17 @@ def plot_sparse_source_estimates(src, stcs, colors=None, linewidth=2,
mask = (vertno == v)
assert np.sum(mask) == 1
linestyle = linestyles[k]
- pl.plot(1e3 * stc.times, 1e9 * stcs[k].data[mask].ravel(), c=c,
- linewidth=linewidth, linestyle=linestyle)
+ plt.plot(1e3 * stc.times, 1e9 * stcs[k].data[mask].ravel(), c=c,
+ linewidth=linewidth, linestyle=linestyle)
- pl.xlabel('Time (ms)', fontsize=18)
- pl.ylabel('Source amplitude (nAm)', fontsize=18)
+ plt.xlabel('Time (ms)', fontsize=18)
+ plt.ylabel('Source amplitude (nAm)', fontsize=18)
if fig_name is not None:
- pl.title(fig_name)
+ plt.title(fig_name)
if show:
- pl.show()
+ plt.show()
surface.actor.property.backface_culling = True
surface.actor.property.shading = True
@@ -1481,7 +1481,7 @@ def plot_cov(cov, info, exclude=[], colorbar=True, proj=False, show_svd=True,
proj : bool
Apply projections or not.
show : bool
- Call pylab.show() as the end or not.
+ Call pyplot.show() as the end or not.
show_svd : bool
Plot also singular values of the noise covariance for each sensor type.
We show square roots ie. standard deviations.
@@ -1493,9 +1493,12 @@ def plot_cov(cov, info, exclude=[], colorbar=True, proj=False, show_svd=True,
ch_names = [n for n in cov.ch_names if not n in exclude]
ch_idx = [cov.ch_names.index(n) for n in ch_names]
info_ch_names = info['ch_names']
- sel_eeg = pick_types(info, meg=False, eeg=True, exclude=exclude)
- sel_mag = pick_types(info, meg='mag', eeg=False, exclude=exclude)
- sel_grad = pick_types(info, meg='grad', eeg=False, exclude=exclude)
+ sel_eeg = pick_types(info, meg=False, eeg=True, ref_meg=False,
+ exclude=exclude)
+ sel_mag = pick_types(info, meg='mag', eeg=False, ref_meg=False,
+ exclude=exclude)
+ sel_grad = pick_types(info, meg='grad', eeg=False, ref_meg=False,
+ exclude=exclude)
idx_eeg = [ch_names.index(info_ch_names[c])
for c in sel_eeg if info_ch_names[c] in ch_names]
idx_mag = [ch_names.index(info_ch_names[c])
@@ -1527,36 +1530,37 @@ def plot_cov(cov, info, exclude=[], colorbar=True, proj=False, show_svd=True,
logger.info(' The projection vectors do not apply to these '
'channels.')
- import pylab as pl
+ import matplotlib.pyplot as plt
- pl.figure(figsize=(2.5 * len(idx_names), 2.7))
+ plt.figure(figsize=(2.5 * len(idx_names), 2.7))
for k, (idx, name, _, _) in enumerate(idx_names):
- pl.subplot(1, len(idx_names), k + 1)
- pl.imshow(C[idx][:, idx], interpolation="nearest")
- pl.title(name)
- pl.subplots_adjust(0.04, 0.0, 0.98, 0.94, 0.2, 0.26)
+ plt.subplot(1, len(idx_names), k + 1)
+ plt.imshow(C[idx][:, idx], interpolation="nearest")
+ plt.title(name)
+ plt.subplots_adjust(0.04, 0.0, 0.98, 0.94, 0.2, 0.26)
tight_layout()
if show_svd:
- pl.figure()
+ plt.figure()
for k, (idx, name, unit, scaling) in enumerate(idx_names):
_, s, _ = linalg.svd(C[idx][:, idx])
- pl.subplot(1, len(idx_names), k + 1)
- pl.ylabel('Noise std (%s)' % unit)
- pl.xlabel('Eigenvalue index')
- pl.semilogy(np.sqrt(s) * scaling)
- pl.title(name)
+ plt.subplot(1, len(idx_names), k + 1)
+ plt.ylabel('Noise std (%s)' % unit)
+ plt.xlabel('Eigenvalue index')
+ plt.semilogy(np.sqrt(s) * scaling)
+ plt.title(name)
tight_layout()
if show:
- pl.show()
+ plt.show()
def plot_source_estimates(stc, subject=None, surface='inflated', hemi='lh',
colormap='hot', time_label='time=%0.2f ms',
smoothing_steps=10, fmin=5., fmid=10., fmax=15.,
transparent=True, alpha=1.0, time_viewer=False,
- config_opts={}, subjects_dir=None, figure=None):
+ config_opts={}, subjects_dir=None, figure=None,
+ views='lat', colorbar=True):
"""Plot SourceEstimates with PySurfer
Note: PySurfer currently needs the SUBJECTS_DIR environment variable,
@@ -1577,9 +1581,9 @@ def plot_source_estimates(stc, subject=None, surface='inflated', hemi='lh',
is None, the environment will be used.
surface : str
The type of surface (inflated, white etc.).
- hemi : str, 'lh' | 'rh' | 'both'
- The hemisphere to display. Using 'both' opens two separate figures,
- one for each hemisphere.
+ hemi : str, 'lh' | 'rh' | 'split' | 'both'
+ The hemisphere to display. Using 'both' or 'split' requires
+ PySurfer version 0.4 or above.
colormap : str
The type of colormap to use.
time_label : str
@@ -1604,25 +1608,64 @@ def plot_source_estimates(stc, subject=None, surface='inflated', hemi='lh',
subjects_dir : str
The path to the freesurfer subjects reconstructions.
It corresponds to Freesurfer environment variable SUBJECTS_DIR.
- figure : instance of mayavi.core.scene.Scene | None
- If None, the last figure will be cleaned and a new figure will
- be created.
+ figure : instance of mayavi.core.scene.Scene | list | int | None
+ If None, a new figure will be created. If multiple views or a
+ split view is requested, this must be a list of the appropriate
+ length. If int is provided it will be used to identify the Mayavi
+ figure by it's id or create a new figure with the given id.
+ views : str | list
+ View to use. See surfer.Brain().
+ colorbar : bool
+ If True, display colorbar on scene.
Returns
-------
- brain : Brain | list of Brain
- A instance of surfer.viz.Brain from PySurfer. For hemi='both',
- a list with Brain instances for the left and right hemisphere is
- returned.
+ brain : Brain
+ A instance of surfer.viz.Brain from PySurfer.
"""
+ import surfer
from surfer import Brain, TimeViewer
- if hemi not in ['lh', 'rh', 'both']:
- raise ValueError('hemi has to be either "lh", "rh", or "both"')
+ if hemi in ['split', 'both'] and LooseVersion(surfer.__version__) < '0.4':
+ raise NotImplementedError('hemi type "%s" not supported with your '
+ 'version of pysurfer. Please upgrade to '
+ 'version 0.4 or higher.' % hemi)
+
+ try:
+ import mayavi
+ from mayavi import mlab
+ except ImportError:
+ from enthought import mayavi
+ from enthought.mayavi import mlab
+
+ # import here to avoid circular import problem
+ from .source_estimate import SourceEstimate
+
+ if not isinstance(stc, SourceEstimate):
+ raise ValueError('stc has to be a surface source estimate')
+
+ if hemi not in ['lh', 'rh', 'split', 'both']:
+ raise ValueError('hemi has to be either "lh", "rh", "split", '
+ 'or "both"')
+
+ n_split = 2 if hemi == 'split' else 1
+ n_views = 1 if isinstance(views, basestring) else len(views)
+ if figure is not None:
+ # use figure with specified id or create new figure
+ if isinstance(figure, int):
+ figure = mlab.figure(figure, size=(600, 600))
+ # make sure it is of the correct type
+ if not isinstance(figure, list):
+ figure = [figure]
+ if not all([isinstance(f, mayavi.core.scene.Scene) for f in figure]):
+ raise TypeError('figure must be a mayavi scene or list of scenes')
+ # make sure we have the right number of figures
+ n_fig = len(figure)
+ if not n_fig == n_split * n_views:
+ raise RuntimeError('`figure` must be a list with the same '
+ 'number of elements as PySurfer plots that '
+ 'will be created (%s)' % n_split * n_views)
- if hemi == 'both' and figure is not None:
- raise RuntimeError('`hemi` can\'t be `both` if the figure parameter'
- ' is supplied.')
subjects_dir = get_subjects_dir(subjects_dir=subjects_dir)
subject = _check_subject(stc.subject, subject, False)
@@ -1632,142 +1675,42 @@ def plot_source_estimates(stc, subject=None, surface='inflated', hemi='lh',
else:
raise ValueError('SUBJECT environment variable not set')
- if hemi == 'both':
+ if hemi in ['both', 'split']:
hemis = ['lh', 'rh']
else:
hemis = [hemi]
- brains = list()
+ title = subject if len(hemis) > 1 else '%s - %s' % (subject, hemis[0])
+ args = inspect.getargspec(Brain.__init__)[0]
+ kwargs = dict(title=title, figure=figure, config_opts=config_opts,
+ subjects_dir=subjects_dir)
+ if 'views' in args:
+ kwargs['views'] = views
+ else:
+ logger.info('PySurfer does not support "views" argument, please '
+ 'consider updating to a newer version (0.4 or later)')
+ brain = Brain(subject, hemi, surface, **kwargs)
for hemi in hemis:
hemi_idx = 0 if hemi == 'lh' else 1
-
- title = '%s-%s' % (subject, hemi)
- args = inspect.getargspec(Brain.__init__)[0]
- if 'subjects_dir' in args:
- brain = Brain(subject, hemi, surface, title=title, figure=figure,
- config_opts=config_opts, subjects_dir=subjects_dir)
- else:
- # Current PySurfer versions need the SUBJECTS_DIR env. var.
- # so we set it here. This is a hack as it can break other things
- # XXX reminder to remove this once upstream pysurfer is changed
- os.environ['SUBJECTS_DIR'] = subjects_dir
- brain = Brain(subject, hemi, surface, config_opts=config_opts,
- title=title, figure=figure)
-
if hemi_idx == 0:
data = stc.data[:len(stc.vertno[0])]
else:
data = stc.data[len(stc.vertno[0]):]
-
vertices = stc.vertno[hemi_idx]
-
time = 1e3 * stc.times
brain.add_data(data, colormap=colormap, vertices=vertices,
smoothing_steps=smoothing_steps, time=time,
- time_label=time_label, alpha=alpha)
+ time_label=time_label, alpha=alpha, hemi=hemi,
+ colorbar=colorbar)
# scale colormap and set time (index) to display
brain.scale_data_colormap(fmin=fmin, fmid=fmid, fmax=fmax,
transparent=transparent)
- brains.append(brain)
if time_viewer:
- viewer = TimeViewer(brains)
-
- if len(brains) == 1:
- return brains[0]
- else:
- return brains
-
+ TimeViewer(brain)
- at deprecated('Use plot_source_estimates. Will be removed in v0.7.')
-def plot_source_estimate(src, stc, n_smooth=200, cmap='jet'):
- """Plot source estimates
- """
- from enthought.tvtk.api import tvtk
- from enthought.traits.api import HasTraits, Range, Instance, \
- on_trait_change
- from enthought.traits.ui.api import View, Item, Group
-
- from enthought.mayavi.core.api import PipelineBase
- from enthought.mayavi.core.ui.api import MayaviScene, SceneEditor, \
- MlabSceneModel
-
- class SurfaceViewer(HasTraits):
- n_times = Range(0, 100, 0,)
-
- scene = Instance(MlabSceneModel, ())
- surf = Instance(PipelineBase)
- text = Instance(PipelineBase)
-
- def __init__(self, src, data, times, n_smooth=20, cmap='jet'):
- super(SurfaceViewer, self).__init__()
- self.src = src
- self.data = data
- self.times = times
- self.n_smooth = n_smooth
- self.cmap = cmap
-
- lh_points = src[0]['rr']
- rh_points = src[1]['rr']
- # lh_faces = src[0]['tris']
- # rh_faces = src[1]['tris']
- lh_faces = src[0]['use_tris']
- rh_faces = src[1]['use_tris']
- points = np.r_[lh_points, rh_points]
- points *= 200
- faces = np.r_[lh_faces, lh_points.shape[0] + rh_faces]
-
- lh_idx = np.where(src[0]['inuse'])[0]
- rh_idx = np.where(src[1]['inuse'])[0]
- use_idx = np.r_[lh_idx, lh_points.shape[0] + rh_idx]
-
- self.points = points[use_idx]
- self.faces = np.searchsorted(use_idx, faces)
-
- # When the scene is activated, or when the parameters are changed, we
- # update the plot.
- @on_trait_change('n_times,scene.activated')
- def update_plot(self):
- idx = int(self.n_times * len(self.times) / 100)
- t = self.times[idx]
- d = self.data[:, idx].astype(np.float) # 8bits for mayavi
- points = self.points
- faces = self.faces
- info_time = "%d ms" % (1e3 * t)
- if self.surf is None:
- surface_mesh = self.scene.mlab.pipeline.triangular_mesh_source(
- points[:, 0], points[:, 1], points[:, 2],
- faces, scalars=d)
- smooth_ = tvtk.SmoothPolyDataFilter(
- number_of_iterations=self.n_smooth,
- relaxation_factor=0.18,
- feature_angle=70,
- feature_edge_smoothing=False,
- boundary_smoothing=False,
- convergence=0.)
- surface_mesh_smooth = self.scene.mlab.pipeline.user_defined(
- surface_mesh, filter=smooth_)
- self.surf = self.scene.mlab.pipeline.surface(
- surface_mesh_smooth, colormap=self.cmap)
-
- self.scene.mlab.colorbar()
- self.text = self.scene.mlab.text(0.7, 0.9, info_time,
- width=0.2)
- self.scene.background = (.05, 0, .1)
- else:
- self.surf.mlab_source.set(scalars=d)
- self.text.set(text=info_time)
-
- # The layout of the dialog created
- view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
- height=800, width=800, show_label=False),
- Group('_', 'n_times',),
- resizable=True,)
-
- viewer = SurfaceViewer(src, stc.data, stc.times, n_smooth=200)
- viewer.configure_traits()
- return viewer
+ return brain
def _plot_ica_panel_onpick(event, sources=None, ylims=None):
@@ -1779,14 +1722,14 @@ def _plot_ica_panel_onpick(event, sources=None, ylims=None):
artist = event.artist
try:
- import pylab as pl
- pl.figure()
+ import matplotlib.pyplot as plt
+ plt.figure()
src_idx = artist._mne_src_idx
component = artist._mne_component
- pl.plot(sources[src_idx], 'r')
- pl.ylim(ylims)
- pl.grid(linestyle='-', color='gray', linewidth=.25)
- pl.title(component)
+ plt.plot(sources[src_idx], 'r')
+ plt.ylim(ylims)
+ plt.grid(linestyle='-', color='gray', linewidth=.25)
+ plt.title(component)
except Exception as err:
# matplotlib silently ignores exceptions in event handlers, so we print
# it here to know what went wrong
@@ -1800,8 +1743,6 @@ def plot_ica_panel(sources, start=None, stop=None, n_components=None,
title=None, show=True):
"""Create panel plots of ICA sources
- Note. Inspired by an example from Carl Vogel's stats blog 'Will it Python?'
-
Clicking on the plot of an individual source opens a new figure showing
the source.
@@ -1832,78 +1773,184 @@ def plot_ica_panel(sources, start=None, stop=None, n_components=None,
-------
fig : instance of pyplot.Figure
"""
- import pylab as pl
+ import matplotlib.pyplot as plt
if source_idx is None:
source_idx = np.arange(len(sources))
else:
source_idx = np.array(source_idx)
- sources = sources[source_idx]
- if n_components is None:
- n_components = len(sources)
+ for param in ['nrow', 'n_components']:
+ if eval(param) is not None:
+ warnings.warn('The `%s` parameter is deprecated and will be'
+ 'removed in MNE-Python 0.8' % param,
+ DeprecationWarning)
- hangover = n_components % ncol
- nplots = nrow * ncol
-
- if source_idx.size > nrow * ncol:
- logger.info('More sources selected than rows and cols specified. '
- 'Showing the first %i sources.' % nplots)
- source_idx = np.arange(nplots)
-
- sources = sources[:, start:stop]
+ n_components = len(sources)
+ sources = sources[source_idx, start:stop]
ylims = sources.min(), sources.max()
- fig, panel_axes = pl.subplots(nrow, ncol, sharey=True, figsize=(9, 10))
+ xlims = np.arange(sources.shape[-1])[[0, -1]]
+ fig, axes = _prepare_trellis(n_components, ncol)
if title is None:
fig.suptitle('MEG signal decomposition'
' -- %i components.' % n_components, size=16)
elif title:
fig.suptitle(title, size=16)
- pl.subplots_adjust(wspace=0.05, hspace=0.05)
-
- iter_plots = ((row, col) for row in range(nrow) for col in range(ncol))
-
- for idx, (row, col) in enumerate(iter_plots):
- xs = panel_axes[row, col]
- xs.grid(linestyle='-', color='gray', linewidth=.25)
- if idx < n_components:
- component = '[%i]' % idx
- this_ax = xs.plot(sources[idx], linewidth=0.5, color='red',
- picker=1e9)
- xs.text(0.05, .95, component,
- transform=panel_axes[row, col].transAxes,
- verticalalignment='top')
- # emebed idx and comp. name to use in callback
- this_ax[0].__dict__['_mne_src_idx'] = idx
- this_ax[0].__dict__['_mne_component'] = component
- pl.ylim(ylims)
- else:
- # Make extra subplots invisible
- pl.setp(xs, visible=False)
-
- xtl = xs.get_xticklabels()
- ytl = xs.get_yticklabels()
- if row < nrow - 2 or (row < nrow - 1 and
- (hangover == 0 or col <= hangover - 1)):
- pl.setp(xtl, visible=False)
- if (col > 0) or (row % 2 == 1):
- pl.setp(ytl, visible=False)
- if (col == ncol - 1) and (row % 2 == 1):
- xs.yaxis.tick_right()
-
- pl.setp(xtl, rotation=90.)
-
+ plt.subplots_adjust(wspace=0.05, hspace=0.05)
+
+ for idx, (ax, source) in enumerate(zip(axes, sources)):
+ ax.grid(linestyle='-', color='gray', linewidth=.25)
+ component = '[%i]' % idx
+
+ # plot+ emebed idx and comp. name to use in callback
+ line = ax.plot(source, linewidth=0.5, color='red', picker=1e9)[0]
+ vars(line)['_mne_src_idx'] = idx
+ vars(line)['_mne_component'] = component
+ ax.set_xlim(xlims)
+ ax.set_ylim(ylims)
+ ax.text(0.05, .95, component, transform=ax.transAxes,
+ verticalalignment='top')
+ plt.setp(ax.get_xticklabels(), visible=False)
+ plt.setp(ax.get_yticklabels(), visible=False)
# register callback
callback = partial(_plot_ica_panel_onpick, sources=sources, ylims=ylims)
fig.canvas.mpl_connect('pick_event', callback)
if show:
- pl.show()
+ plt.show()
return fig
+def plot_ica_topomap(ica, source_idx, ch_type='mag', res=500, layout=None,
+ vmax=None, cmap='RdBu_r', sensors='k,', colorbar=True,
+ show=True):
+ """ Plot topographic map from ICA component.
+
+ Parameters
+ ----------
+ ica : instance of mne.prerocessing.ICA
+ The ica object to plot from.
+ source_idx : int | array-like
+ The indices of the sources to be plotted.
+ ch_type : 'mag' | 'grad' | 'planar1' | 'planar2' | 'eeg'
+ The channel type to plot. For 'grad', the gradiometers are collected in
+ pairs and the RMS for each pair is plotted.
+ layout : None | Layout
+ Layout instance specifying sensor positions (does not need to
+ be specified for Neuromag data). If possible, the correct layout is
+ inferred from the data.
+ vmax : scalar
+ The value specfying the range of the color scale (-vmax to +vmax). If
+ None, the largest absolute value in the data is used.
+ cmap : matplotlib colormap
+ Colormap.
+ sensors : bool | str
+ Add markers for sensor locations to the plot. Accepts matplotlib plot
+ format string (e.g., 'r+' for red plusses).
+ colorbar : bool
+ Plot a colorbar.
+ res : int
+ The resolution of the topomap image (n pixels along each side).
+ show : bool
+ Call pyplot.show() at the end.
+ """
+ import matplotlib.pyplot as plt
+
+ if np.isscalar(source_idx):
+ source_idx = [source_idx]
+
+ data = np.dot(ica.mixing_matrix_[:, source_idx].T,
+ ica.pca_components_[:ica.n_components_])
+
+ if ica.info is None:
+ raise RuntimeError('The ICA\'s measurement info is missing. Please '
+ 'fit the ICA or add the corresponding info object.')
+
+ picks, pos, merge_grads = _prepare_topo_plot(ica, ch_type, layout)
+ data = np.atleast_2d(data)
+ data = data[:, picks]
+
+ # prepare data for iteration
+ fig, axes = _prepare_trellis(len(data), max_col=5)
+
+ if vmax is None:
+ vrange = np.array([f(data) for f in np.min, np.max])
+ vmax = max(abs(vrange))
+
+ if merge_grads:
+ from .layouts.layout import _merge_grad_data
+ for ii, data_, ax in zip(source_idx, data, axes):
+ data_ = _merge_grad_data(data_) if merge_grads else data_
+ plot_topomap(data_.flatten(), pos, vmax=vmax, res=res, axis=ax)
+ ax.set_title('IC #%03d' % ii, fontsize=12)
+ ax.set_yticks([])
+ ax.set_xticks([])
+ ax.set_frame_on(False)
+
+ tight_layout()
+ if colorbar:
+ vmax_ = normalize_colors(vmin=-vmax, vmax=vmax)
+ sm = plt.cm.ScalarMappable(cmap=cmap, norm=vmax_)
+ sm.set_array(np.linspace(-vmax, vmax))
+ fig.subplots_adjust(right=0.8)
+ cax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
+ fig.colorbar(sm, cax=cax)
+ cax.set_title('AU')
+
+ if show is True:
+ plt.show()
+
+ return fig
+
+
+def _prepare_topo_plot(obj, ch_type, layout):
+ """"Aux Function"""
+ info = copy.deepcopy(obj.info)
+ if layout is None and ch_type is not 'eeg':
+ from .layouts.layout import find_layout
+ layout = find_layout(info['chs'])
+ elif layout == 'auto':
+ layout = None
+
+ info['ch_names'] = _clean_names(info['ch_names'])
+ for ii, this_ch in enumerate(info['chs']):
+ this_ch['ch_name'] = info['ch_names'][ii]
+
+ if layout is not None:
+ layout = copy.deepcopy(layout)
+ layout.names = _clean_names(layout.names)
+
+ # special case for merging grad channels
+ if (ch_type == 'grad' and FIFF.FIFFV_COIL_VV_PLANAR_T1 in
+ np.unique([ch['coil_type'] for ch in info['chs']])):
+ from .layouts.layout import _pair_grad_sensors
+ picks, pos = _pair_grad_sensors(info, layout)
+ merge_grads = True
+ else:
+ merge_grads = False
+ if ch_type == 'eeg':
+ picks = pick_types(info, meg=False, eeg=True, ref_meg=False,
+ exclude='bads')
+ else:
+ picks = pick_types(info, meg=ch_type, ref_meg=False,
+ exclude='bads')
+
+ if len(picks) == 0:
+ raise ValueError("No channels of type %r" % ch_type)
+
+ if layout is None:
+ chs = [info['chs'][i] for i in picks]
+ from .layouts.layout import _find_topomap_coords
+ pos = _find_topomap_coords(chs, layout)
+ else:
+ pos = [layout.pos[layout.names.index(info['ch_names'][k])] for k in
+ picks]
+
+ return picks, pos, merge_grads
+
+
def plot_image_epochs(epochs, picks=None, sigma=0.3, vmin=None,
vmax=None, colorbar=True, order=None, show=True,
units=None, scalings=None):
@@ -1950,9 +1997,10 @@ def plot_image_epochs(epochs, picks=None, sigma=0.3, vmin=None,
units, scalings = _mutable_defaults(('units', units),
('scalings', scalings))
- import pylab as pl
+ import matplotlib.pyplot as plt
if picks is None:
- picks = pick_types(epochs.info, meg=True, eeg=True, exclude='bads')
+ picks = pick_types(epochs.info, meg=True, eeg=True, ref_meg=False,
+ exclude='bads')
if units.keys() != scalings.keys():
raise ValueError('Scalings and units must have the same keys.')
@@ -1967,7 +2015,7 @@ def plot_image_epochs(epochs, picks=None, sigma=0.3, vmin=None,
figs = list()
for i, (this_data, idx) in enumerate(zip(np.swapaxes(data, 0, 1), picks)):
- this_fig = pl.figure()
+ this_fig = plt.figure()
figs.append(this_fig)
ch_type = channel_type(epochs.info, idx)
@@ -1985,15 +2033,15 @@ def plot_image_epochs(epochs, picks=None, sigma=0.3, vmin=None,
this_data = ndimage.gaussian_filter1d(this_data, sigma=sigma, axis=0)
- ax1 = pl.subplot2grid((3, 10), (0, 0), colspan=9, rowspan=2)
- im = pl.imshow(this_data,
- extent=[1e3 * epochs.times[0], 1e3 * epochs.times[-1],
- 0, len(data)],
- aspect='auto', origin='lower',
- vmin=vmin, vmax=vmax)
- ax2 = pl.subplot2grid((3, 10), (2, 0), colspan=9, rowspan=1)
+ ax1 = plt.subplot2grid((3, 10), (0, 0), colspan=9, rowspan=2)
+ im = plt.imshow(this_data,
+ extent=[1e3 * epochs.times[0], 1e3 * epochs.times[-1],
+ 0, len(data)],
+ aspect='auto', origin='lower',
+ vmin=vmin, vmax=vmax)
+ ax2 = plt.subplot2grid((3, 10), (2, 0), colspan=9, rowspan=1)
if colorbar:
- ax3 = pl.subplot2grid((3, 10), (0, 9), colspan=1, rowspan=3)
+ ax3 = plt.subplot2grid((3, 10), (0, 9), colspan=1, rowspan=3)
ax1.set_title(epochs.ch_names[idx])
ax1.set_ylabel('Epochs')
ax1.axis('auto')
@@ -2005,11 +2053,11 @@ def plot_image_epochs(epochs, picks=None, sigma=0.3, vmin=None,
ax2.set_ylim([vmin, vmax])
ax2.axvline(0, color='m', linewidth=3, linestyle='--')
if colorbar:
- pl.colorbar(im, cax=ax3)
+ plt.colorbar(im, cax=ax3)
tight_layout()
if show:
- pl.show()
+ plt.show()
return figs
@@ -2028,7 +2076,7 @@ def mne_analyze_colormap(limits=[5, 10, 15], format='mayavi'):
Returns
-------
- cmap : instance of matplotlib.pylab.colormap | array
+ cmap : instance of matplotlib.pyplot.colormap | array
A teal->blue->gray->red->yellow colormap.
Notes
@@ -2188,7 +2236,7 @@ def plot_connectivity_circle(con, node_names, indices=None, n_lines=None,
fig : instance of pyplot.Figure
The figure handle.
"""
- import pylab as pl
+ import matplotlib.pyplot as plt
import matplotlib.path as m_path
import matplotlib.patches as m_patches
@@ -2214,7 +2262,7 @@ def plot_connectivity_circle(con, node_names, indices=None, n_lines=None,
node_colors = cycle(node_colors)
else:
# assign colors using colormap
- node_colors = [pl.cm.spectral(i / float(n_nodes))
+ node_colors = [plt.cm.spectral(i / float(n_nodes))
for i in range(n_nodes)]
# handle 1D and 2D connectivity information
@@ -2232,20 +2280,20 @@ def plot_connectivity_circle(con, node_names, indices=None, n_lines=None,
# get the colormap
if isinstance(colormap, basestring):
- colormap = pl.get_cmap(colormap)
+ colormap = plt.get_cmap(colormap)
# Make figure background the same colors as axes
- fig = pl.figure(figsize=(8, 8), facecolor=facecolor)
+ fig = plt.figure(figsize=(8, 8), facecolor=facecolor)
# Use a polar axes
- axes = pl.subplot(111, polar=True, axisbg=facecolor)
+ axes = plt.subplot(111, polar=True, axisbg=facecolor)
# No ticks, we'll put our own
- pl.xticks([])
- pl.yticks([])
+ plt.xticks([])
+ plt.yticks([])
# Set y axes limit
- pl.ylim(0, 10)
+ plt.ylim(0, 10)
# Draw lines between connected nodes, only draw the strongest connections
if n_lines is not None and len(con) > n_lines:
@@ -2348,24 +2396,24 @@ def plot_connectivity_circle(con, node_names, indices=None, n_lines=None,
angle_deg += 180
ha = 'right'
- pl.text(angle_rad, 10.4, name, size=10, rotation=angle_deg,
- rotation_mode='anchor', horizontalalignment=ha,
- verticalalignment='center', color=textcolor)
+ plt.text(angle_rad, 10.4, name, size=10, rotation=angle_deg,
+ rotation_mode='anchor', horizontalalignment=ha,
+ verticalalignment='center', color=textcolor)
if title is not None:
- pl.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.75)
- pl.figtext(0.03, 0.95, title, color=textcolor, fontsize=14)
+ plt.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.75)
+ plt.figtext(0.03, 0.95, title, color=textcolor, fontsize=14)
else:
- pl.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.8)
+ plt.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.8)
if colorbar:
- sm = pl.cm.ScalarMappable(cmap=colormap,
- norm=pl.normalize(vmin=vmin, vmax=vmax))
+ norm = normalize_colors(vmin=vmin, vmax=vmax)
+ sm = plt.cm.ScalarMappable(cmap=colormap, norm=norm)
sm.set_array(np.linspace(vmin, vmax))
ax = fig.add_axes([.92, 0.03, .015, .25])
cb = fig.colorbar(sm, cax=ax)
- cb_yticks = pl.getp(cb.ax.axes, 'yticklabels')
- pl.setp(cb_yticks, color=textcolor)
+ cb_yticks = plt.getp(cb.ax.axes, 'yticklabels')
+ plt.setp(cb_yticks, color=textcolor)
return fig
@@ -2397,7 +2445,7 @@ def plot_drop_log(drop_log, threshold=0, n_max_plot=20, subject='Unknown',
"""
if not isinstance(drop_log, list) or not isinstance(drop_log[0], list):
raise ValueError('drop_log must be a list of lists')
- import pylab as pl
+ import matplotlib.pyplot as plt
scores = Counter([ch for d in drop_log for ch in d])
ch_names = np.array(scores.keys())
perc = 100 * np.mean([len(d) > 0 for d in drop_log])
@@ -2406,24 +2454,24 @@ def plot_drop_log(drop_log, threshold=0, n_max_plot=20, subject='Unknown',
counts = 100 * np.array(scores.values(), dtype=float) / len(drop_log)
n_plot = min(n_max_plot, len(ch_names))
order = np.flipud(np.argsort(counts))
- pl.figure()
- pl.title('%s: %0.1f%%' % (subject, perc))
+ plt.figure()
+ plt.title('%s: %0.1f%%' % (subject, perc))
x = np.arange(n_plot)
- pl.bar(x, counts[order[:n_plot]], color=color, width=width)
- pl.xticks(x + width / 2.0, ch_names[order[:n_plot]], rotation=45,
- horizontalalignment='right')
- pl.tick_params(axis='x', which='major', labelsize=10)
- pl.ylabel('% of epochs rejected')
- pl.xlim((-width / 2.0, (n_plot - 1) + width * 3 / 2))
- pl.grid(True, axis='y')
- pl.show()
+ plt.bar(x, counts[order[:n_plot]], color=color, width=width)
+ plt.xticks(x + width / 2.0, ch_names[order[:n_plot]], rotation=45,
+ horizontalalignment='right')
+ plt.tick_params(axis='x', which='major', labelsize=10)
+ plt.ylabel('% of epochs rejected')
+ plt.xlim((-width / 2.0, (n_plot - 1) + width * 3 / 2))
+ plt.grid(True, axis='y')
+ plt.show()
return perc
def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
bgcolor='w', color=None, bad_color=(0.8, 0.8, 0.8),
event_color='cyan', scalings=None, remove_dc=True, order='type',
- show_options=False, title=None, show=True):
+ show_options=False, title=None, show=True, block=False):
"""Plot raw data
Parameters
@@ -2465,6 +2513,9 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
raw object or '<unknown>' will be displayed as title.
show : bool
Show figure if True
+ block : bool
+ Whether to halt program execution until the figure is closed.
+ Useful for setting bad channels on the fly by clicking on a line.
Returns
-------
@@ -2476,8 +2527,12 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
The arrow keys (up/down/left/right) can typically be used to navigate
between channels and time ranges, but this depends on the backend
matplotlib is configured to use (e.g., mpl.use('TkAgg') should work).
+ To mark or un-mark a channel as bad, click on the rather flat segments
+ of a channel's time series. The changes will be reflected immediately
+ in the raw object's ``raw.info['bads']`` entry.
"""
- import pylab as pl
+ import matplotlib.pyplot as plt
+ import matplotlib as mpl
color, scalings = _mutable_defaults(('color', color),
('scalings_plot_raw', scalings))
@@ -2489,8 +2544,14 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
# allow for raw objects without filename, e.g., ICA
if title is None:
- title = (raw.info['filenames'][0] if 'filenames' in raw.info
- else '<unknown>')
+ title = raw.info.get('filenames', None) # should return a list
+ if not title: # empty list or absent key
+ title = '<unknown>'
+ else:
+ if len(title) > 1:
+ title = '<unknown>'
+ else:
+ title = title[0]
elif not isinstance(title, basestring):
raise TypeError('title must be None or a string')
if len(title) > 60:
@@ -2505,11 +2566,11 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
inds = list()
types = list()
for t in ['grad', 'mag']:
- inds += [pick_types(info, meg=t, exclude=[])]
+ inds += [pick_types(info, meg=t, ref_meg=False, exclude=[])]
types += [t] * len(inds[-1])
pick_args = dict(meg=False, exclude=[])
for t in ['eeg', 'eog', 'ecg', 'emg', 'ref_meg', 'stim', 'resp',
- 'misc', 'chpi']:
+ 'misc', 'chpi', 'syst', 'ias', 'exci']:
pick_args[t] = True
inds += [pick_types(raw.info, **pick_args)]
types += [t] * len(inds[-1])
@@ -2553,14 +2614,14 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
fig.set_size_inches(size, forward=True)
except Exception:
pass
- ax = pl.subplot2grid((10, 10), (0, 0), colspan=9, rowspan=9)
+ ax = plt.subplot2grid((10, 10), (0, 0), colspan=9, rowspan=9)
ax.set_title(title, fontsize=12)
- ax_hscroll = pl.subplot2grid((10, 10), (9, 0), colspan=9)
+ ax_hscroll = plt.subplot2grid((10, 10), (9, 0), colspan=9)
ax_hscroll.get_yaxis().set_visible(False)
ax_hscroll.set_xlabel('Time (s)')
- ax_vscroll = pl.subplot2grid((10, 10), (0, 9), rowspan=9)
+ ax_vscroll = plt.subplot2grid((10, 10), (0, 9), rowspan=9)
ax_vscroll.set_axis_off()
- ax_button = pl.subplot2grid((10, 10), (9, 9))
+ ax_button = plt.subplot2grid((10, 10), (9, 9))
# store these so they can be fixed on resize
params['fig'] = fig
params['ax'] = ax
@@ -2570,19 +2631,19 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
# populate vertical and horizontal scrollbars
for ci in xrange(len(info['ch_names'])):
- this_color = bad_color if info['ch_names'][inds[ci]] in info['bads'] \
- else color
+ this_color = (bad_color if info['ch_names'][inds[ci]] in info['bads']
+ else color)
if isinstance(this_color, dict):
this_color = this_color[types[inds[ci]]]
- ax_vscroll.add_patch(pl.mpl.patches.Rectangle((0, ci), 1, 1,
- facecolor=this_color,
- edgecolor=this_color))
- vsel_patch = pl.mpl.patches.Rectangle((0, 0), 1, n_channels, facecolor='w',
- edgecolor='w', alpha=0.5)
+ ax_vscroll.add_patch(mpl.patches.Rectangle((0, ci), 1, 1,
+ facecolor=this_color,
+ edgecolor=this_color))
+ vsel_patch = mpl.patches.Rectangle((0, 0), 1, n_channels, alpha=0.5,
+ facecolor='w', edgecolor='w')
ax_vscroll.add_patch(vsel_patch)
params['vsel_patch'] = vsel_patch
- hsel_patch = pl.mpl.patches.Rectangle((start, 0), duration, 1, color='k',
- edgecolor=None, alpha=0.5)
+ hsel_patch = mpl.patches.Rectangle((start, 0), duration, 1, color='k',
+ edgecolor=None, alpha=0.5)
ax_hscroll.add_patch(hsel_patch)
params['hsel_patch'] = hsel_patch
ax_hscroll.set_xlim(0, n_times / float(info['sfreq']))
@@ -2604,7 +2665,7 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
event_line=event_line, offsets=offsets)
# set up callbacks
- opt_button = pl.mpl.widgets.Button(ax_button, 'Opt')
+ opt_button = mpl.widgets.Button(ax_button, 'Opt')
callback_option = partial(_toggle_options, params=params)
opt_button.on_clicked(callback_option)
callback_key = partial(_plot_raw_onkey, params=params)
@@ -2635,19 +2696,20 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
_toggle_options(None, params)
if show:
- pl.show()
+ plt.show(block=block)
+
return fig
def _toggle_options(event, params):
"""Toggle options (projectors) dialog"""
- import pylab as pl
+ import matplotlib.pyplot as plt
if len(params['projs']) > 0:
if params['fig_opts'] is None:
_draw_proj_checkbox(event, params, draw_current_state=False)
else:
# turn off options dialog
- pl.close(params['fig_opts'])
+ plt.close(params['fig_opts'])
del params['proj_checks']
params['fig_opts'] = None
@@ -2758,6 +2820,31 @@ def _helper_resize(event, params):
_layout_raw(params)
+def _pick_bad_channels(event, params):
+ """Helper for selecting / dropping bad channels onpick"""
+ bads = params['raw'].info['bads']
+ # trade-off, avoid selecting more than one channel when drifts are present
+ # however for clean data don't click on peaks but on flat segments
+ f = lambda x, y: y(np.mean(x), x.std() * 2)
+ for l in event.inaxes.lines:
+ ydata = l.get_ydata()
+ if not isinstance(ydata, list) and not np.isnan(ydata).any():
+ ymin, ymax = f(ydata, np.subtract), f(ydata, np.add)
+ if ymin <= event.ydata <= ymax:
+ this_chan = vars(l)['ch_name']
+ if this_chan in params['raw'].ch_names:
+ if this_chan not in bads:
+ bads.append(this_chan)
+ l.set_color(params['bad_color'])
+ else:
+ bads.pop(bads.index(this_chan))
+ l.set_color(vars(l)['def-color'])
+ event.canvas.draw()
+ break
+ # update deep-copied info to persistently draw bads
+ params['info']['bads'] = bads
+
+
def _mouse_click(event, params):
"""Vertical select callback"""
if event.inaxes is None or event.button != 1:
@@ -2773,6 +2860,9 @@ def _mouse_click(event, params):
elif event.inaxes == params['ax_hscroll']:
_plot_raw_time(event.xdata - params['duration'] / 2, params)
+ elif event.inaxes == params['ax']:
+ _pick_bad_channels(event, params)
+
def _plot_raw_time(value, params):
"""Deal with changed time value"""
@@ -2791,7 +2881,7 @@ def _plot_raw_time(value, params):
def _plot_raw_onkey(event, params):
"""Interpret key presses"""
- import pylab as pl
+ import matplotlib.pyplot as plt
# check for initial plot
plot_fun = params['plot_fun']
if event is None:
@@ -2800,7 +2890,7 @@ def _plot_raw_onkey(event, params):
# quit event
if event.key == 'escape':
- pl.close(params['fig'])
+ plt.close(params['fig'])
return
# change plotting params
@@ -2840,7 +2930,7 @@ def _plot_traces(params, inds, color, bad_color, lines, event_line, offsets):
info = params['info']
n_channels = params['n_channels']
-
+ params['bad_color'] = bad_color
# do the plotting
tick_list = []
for ii in xrange(n_channels):
@@ -2865,6 +2955,8 @@ def _plot_traces(params, inds, color, bad_color, lines, event_line, offsets):
lines[ii].set_ydata(offset - this_data)
lines[ii].set_xdata(params['times'])
lines[ii].set_color(this_color)
+ vars(lines[ii])['ch_name'] = ch_name
+ vars(lines[ii])['def-color'] = color[params['types'][inds[ch_ind]]]
else:
# "remove" lines
lines[ii].set_xdata([])
@@ -2887,7 +2979,7 @@ def _plot_traces(params, inds, color, bad_color, lines, event_line, offsets):
event_line.set_ydata([])
# finalize plot
params['ax'].set_xlim(params['times'][0],
- params['times'][0] + params['duration'], False)
+ params['times'][0] + params['duration'], False)
params['ax'].set_yticklabels(tick_list)
params['vsel_patch'].set_y(params['ch_start'])
params['fig'].canvas.draw()
@@ -2895,22 +2987,135 @@ def _plot_traces(params, inds, color, bad_color, lines, event_line, offsets):
def figure_nobar(*args, **kwargs):
"""Make matplotlib figure with no toolbar"""
- import pylab as pl
- old_val = pl.mpl.rcParams['toolbar']
+ import matplotlib.pyplot as plt
+ import matplotlib as mpl
+ old_val = mpl.rcParams['toolbar']
try:
- pl.mpl.rcParams['toolbar'] = 'none'
- fig = pl.figure(*args, **kwargs)
+ mpl.rcParams['toolbar'] = 'none'
+ fig = plt.figure(*args, **kwargs)
# remove button press catchers (for toolbar)
for key in fig.canvas.callbacks.callbacks['key_press_event'].keys():
fig.canvas.callbacks.disconnect(key)
except Exception as ex:
raise ex
finally:
- pl.mpl.rcParams['toolbar'] = old_val
+ mpl.rcParams['toolbar'] = old_val
return fig
@verbose
+def plot_raw_psds(raw, tmin=0.0, tmax=60.0, fmin=0, fmax=np.inf,
+ proj=False, n_fft=2048, picks=None, ax=None, color='black',
+ area_mode='std', area_alpha=0.33, n_jobs=1, verbose=None):
+ """Plot the power spectral density across channels
+
+ Parameters
+ ----------
+ raw : instance of fiff.Raw
+ The raw instance to use.
+ tmin : float
+ Start time for calculations.
+ tmax : float
+ End time for calculations.
+ fmin : float
+ Start frequency to consider.
+ fmax : float
+ End frequency to consider.
+ proj : bool
+ Apply projection.
+ n_fft : int
+ Number of points to use in Welch FFT calculations.
+ picks : list | None
+ List of channels to use. Cannot be None if `ax` is supplied. If both
+ `picks` and `ax` are None, separate subplots will be created for
+ each standard channel type (`mag`, `grad`, and `eeg`).
+ ax : instance of matplotlib Axes | None
+ Axes to plot into. If None, axes will be created.
+ color : str | tuple
+ A matplotlib-compatible color to use.
+ area_mode : str | None
+ Mode for plotting area. If 'std', the mean +/- 1 STD (across channels)
+ will be plotted. If 'range', the min and max (across channels) will be
+ plotted. Bad channels will be excluded from these calculations.
+ If None, no area will be plotted.
+ area_alpha : float
+ Alpha for the area.
+ n_jobs : int
+ Number of jobs to run in parallel.
+ verbose : bool, str, int, or None
+ If not None, override default verbose level (see mne.verbose).
+ """
+ import matplotlib.pyplot as plt
+ if area_mode not in [None, 'std', 'range']:
+ raise ValueError('"area_mode" must be "std", "range", or None')
+ if picks is None:
+ if ax is not None:
+ raise ValueError('If "ax" is not supplied (None), then "picks" '
+ 'must also be supplied')
+ megs = ['mag', 'grad', False]
+ eegs = [False, False, True]
+ names = ['Magnetometers', 'Gradiometers', 'EEG']
+ picks_list = list()
+ titles_list = list()
+ for meg, eeg, name in zip(megs, eegs, names):
+ picks = pick_types(raw.info, meg=meg, eeg=eeg, ref_meg=False)
+ if len(picks) > 0:
+ picks_list.append(picks)
+ titles_list.append(name)
+ if len(picks_list) == 0:
+ raise RuntimeError('No MEG or EEG channels found')
+ else:
+ picks_list = [picks]
+ titles_list = ['Selected channels']
+ ax_list = [ax]
+
+ make_label = False
+ if ax is None:
+ plt.figure()
+ ax_list = list()
+ for ii in range(len(picks_list)):
+ # Make x-axes change together
+ if ii > 0:
+ ax_list.append(plt.subplot(len(picks_list), 1, ii + 1,
+ sharex=ax_list[0]))
+ else:
+ ax_list.append(plt.subplot(len(picks_list), 1, ii + 1))
+ make_label = True
+
+ for ii, (picks, title, ax) in enumerate(zip(picks_list, titles_list,
+ ax_list)):
+ psds, freqs = compute_raw_psd(raw, tmin=tmin, tmax=tmax, picks=picks,
+ fmin=fmin, fmax=fmax, NFFT=n_fft,
+ n_jobs=n_jobs, plot=False, proj=proj)
+
+ # Convert PSDs to dB
+ psds = 10 * np.log10(psds)
+ psd_mean = np.mean(psds, axis=0)
+ if area_mode == 'std':
+ psd_std = np.std(psds, axis=0)
+ hyp_limits = (psd_mean - psd_std, psd_mean + psd_std)
+ elif area_mode == 'range':
+ hyp_limits = (np.min(psds, axis=0), np.max(psds, axis=0))
+ else: # area_mode is None
+ hyp_limits = None
+
+ ax.plot(freqs, psd_mean, color=color)
+ if hyp_limits is not None:
+ ax.fill_between(freqs, hyp_limits[0], y2=hyp_limits[1],
+ color=color, alpha=area_alpha)
+ if make_label:
+ if ii == len(picks_list) - 1:
+ ax.set_xlabel('Freq (Hz)')
+ if ii == len(picks_list) / 2:
+ ax.set_ylabel('Power Spectral Density (dB/Hz)')
+ ax.set_title(title)
+ ax.set_xlim(freqs[0], freqs[-1])
+ if make_label:
+ tight_layout(pad=0.1, h_pad=0.1, w_pad=0.1)
+ plt.show()
+
+
+ at verbose
def compare_fiff(fname_1, fname_2, fname_out=None, show=True, indent=' ',
read_limit=np.inf, max_str=30, verbose=None):
"""Compare the contents of two fiff files using diff and show_fiff
@@ -2958,3 +3163,338 @@ def compare_fiff(fname_1, fname_2, fname_out=None, show=True, indent=' ',
if show is True:
webbrowser.open_new_tab(fname_out)
return fname_out
+
+
+def _prepare_trellis(n_cells, max_col):
+ """Aux function
+ """
+ import matplotlib.pyplot as plt
+ if n_cells == 1:
+ nrow = ncol = 1
+ elif n_cells <= max_col:
+ nrow, ncol = 1, n_cells
+ else:
+ nrow, ncol = int(math.ceil(n_cells / float(max_col))), max_col
+
+ fig, axes = plt.subplots(nrow, ncol)
+ axes = [axes] if ncol == nrow == 1 else axes.flatten()
+ for ax in axes[n_cells:]: # hide unused axes
+ ax.set_visible(False)
+ return fig, axes
+
+
+def _plot_epochs_get_data(epochs, epoch_idx, n_channels, times, picks,
+ scalings, types):
+ """Aux function
+ """
+ data = np.zeros((len(epoch_idx), n_channels, len(times)))
+ for ii, epoch in enumerate(epochs.get_data()[epoch_idx][:, picks]):
+ for jj, (this_type, this_channel) in enumerate(zip(types, epoch)):
+ data[ii, jj] = this_channel / scalings[this_type]
+ return data
+
+
+def _draw_epochs_axes(epoch_idx, good_ch_idx, bad_ch_idx, data, times, axes,
+ title_str, axes_handler):
+ """Aux functioin"""
+ this = axes_handler[0]
+ for ii, data_, ax in zip(epoch_idx, data, axes):
+ [l.set_data(times, d) for l, d in zip(ax.lines, data_[good_ch_idx])]
+ if bad_ch_idx is not None:
+ bad_lines = [ax.lines[k] for k in bad_ch_idx]
+ [l.set_data(times, d) for l, d in zip(bad_lines,
+ data_[bad_ch_idx])]
+ if title_str is not None:
+ ax.set_title(title_str % ii, fontsize=12)
+ ax.set_ylim(data.min(), data.max())
+ ax.set_yticks([])
+ ax.set_xticks([])
+ if vars(ax)[this]['reject'] is True:
+ # memorizing reject
+ [l.set_color((0.8, 0.8, 0.8)) for l in ax.lines]
+ ax.get_figure().canvas.draw()
+ else:
+ # forgetting previous reject
+ for k in axes_handler:
+ if k == this:
+ continue
+ if vars(ax).get(k, {}).get('reject', None) is True:
+ [l.set_color('k') for l in ax.lines[:len(good_ch_idx)]]
+ if bad_ch_idx is not None:
+ [l.set_color('r') for l in ax.lines[-len(bad_ch_idx):]]
+ ax.get_figure().canvas.draw()
+ break
+
+
+def _epochs_navigation_onclick(event, params):
+ """Aux function"""
+ import matplotlib.pyplot as plt
+ p = params
+ here = None
+ if event.inaxes == p['back'].ax:
+ here = 1
+ elif event.inaxes == p['next'].ax:
+ here = -1
+ elif event.inaxes == p['reject-quit'].ax:
+ if p['reject_idx']:
+ p['epochs'].drop_epochs(p['reject_idx'])
+ plt.close(p['fig'])
+ plt.close(event.inaxes.get_figure())
+
+ if here is not None:
+ p['idx_handler'].rotate(here)
+ p['axes_handler'].rotate(here)
+ this_idx = p['idx_handler'][0]
+ data = _plot_epochs_get_data(p['epochs'], this_idx, p['n_channels'],
+ p['times'], p['picks'], p['scalings'],
+ p['types'])
+ _draw_epochs_axes(this_idx, p['good_ch_idx'], p['bad_ch_idx'], data,
+ p['times'], p['axes'], p['title_str'],
+ p['axes_handler'])
+ # XXX don't ask me why
+ p['axes'][0].get_figure().canvas.draw()
+
+
+def _epochs_axes_onclick(event, params):
+ """Aux function"""
+ reject_color = (0.8, 0.8, 0.8)
+ ax = event.inaxes
+ p = params
+ here = vars(ax)[p['axes_handler'][0]]
+ if here.get('reject', None) is False:
+ idx = here['idx']
+ if idx not in p['reject_idx']:
+ p['reject_idx'].append(idx)
+ [l.set_color(reject_color) for l in ax.lines]
+ here['reject'] = True
+ elif here.get('reject', None) is True:
+ idx = here['idx']
+ if idx in p['reject_idx']:
+ p['reject_idx'].pop(p['reject_idx'].index(idx))
+ good_lines = [ax.lines[k] for k in p['good_ch_idx']]
+ [l.set_color('k') for l in good_lines]
+ if p['bad_ch_idx'] is not None:
+ bad_lines = ax.lines[-len(p['bad_ch_idx']):]
+ [l.set_color('r') for l in bad_lines]
+ here['reject'] = False
+ ax.get_figure().canvas.draw()
+
+
+def plot_epochs(epochs, epoch_idx=None, picks=None, scalings=None,
+ title_str='#%003i', show=True, block=False):
+ """ Visualize single trials using Trellis plot.
+
+ Parameters
+ ----------
+
+ epochs : instance of Epochs
+ The epochs object
+ epoch_idx : array-like | int | None
+ The epochs to visualize. If None, the first 20 epochs are shown.
+ Defaults to None.
+ picks : array-like | None
+ Channels to be included. If None only good data channels are used.
+ Defaults to None
+ scalings : dict | None
+ Scale factors for the traces. If None, defaults to:
+ `dict(mag=1e-12, grad=4e-11, eeg=20e-6, eog=150e-6, ecg=5e-4, emg=1e-3,
+ ref_meg=1e-12, misc=1e-3, stim=1, resp=1, chpi=1e-4)`
+ title_str : None | str
+ The string formatting to use for axes titles. If None, no titles
+ will be shown. Defaults expand to ``#001, #002, ...``
+ show : bool
+ Whether to show the figure or not.
+ block : bool
+ Whether to halt program execution until the figure is closed.
+ Useful for rejecting bad trials on the fly by clicking on a
+ sub plot.
+
+ Returns
+ -------
+ fig : Instance of matplotlib.figure.Figure
+ The figure.
+ """
+ import matplotlib.pyplot as plt
+ import matplotlib as mpl
+ scalings = _mutable_defaults(('scalings_plot_raw', None))[0]
+ if np.isscalar(epoch_idx):
+ epoch_idx = [epoch_idx]
+ if epoch_idx is None:
+ n_events = len(epochs.events)
+ epoch_idx = range(n_events)
+ else:
+ n_events = len(epoch_idx)
+ epoch_idx = epoch_idx[:n_events]
+ idx_handler = deque(create_chunks(epoch_idx, 20))
+
+ if picks is None:
+ if any('ICA' in k for k in epochs.ch_names):
+ picks = pick_types(epochs.info, misc=True, ref_meg=False,
+ exclude=[])
+ else:
+ picks = pick_types(epochs.info, meg=True, eeg=True, ref_meg=False,
+ exclude=[])
+ if len(picks) < 1:
+ raise RuntimeError('No appropriate channels found. Please'
+ ' check your picks')
+ times = epochs.times * 1e3
+ n_channels = len(picks)
+ types = [channel_type(epochs.info, idx) for idx in
+ picks]
+
+ # preallocation needed for min / max scaling
+ data = _plot_epochs_get_data(epochs, idx_handler[0], n_channels,
+ times, picks, scalings, types)
+ n_events = len(epochs.events)
+ epoch_idx = epoch_idx[:n_events]
+ idx_handler = deque(create_chunks(epoch_idx, 20))
+ # handle bads
+ bad_ch_idx = None
+ ch_names = epochs.ch_names
+ bads = epochs.info['bads']
+ if any([ch_names[k] in bads for k in picks]):
+ ch_picked = [k for k in ch_names if ch_names.index(k) in picks]
+ bad_ch_idx = [ch_picked.index(k) for k in bads if k in ch_names]
+ good_ch_idx = [p for p in picks if p not in bad_ch_idx]
+ else:
+ good_ch_idx = np.arange(n_channels)
+
+ fig, axes = _prepare_trellis(len(data), max_col=5)
+ axes_handler = deque(range(len(idx_handler)))
+ for ii, data_, ax in zip(idx_handler[0], data, axes):
+ ax.plot(times, data_[good_ch_idx].T, color='k')
+ if bad_ch_idx is not None:
+ ax.plot(times, data_[bad_ch_idx].T, color='r')
+ if title_str is not None:
+ ax.set_title(title_str % ii, fontsize=12)
+ ax.set_ylim(data.min(), data.max())
+ ax.set_yticks([])
+ ax.set_xticks([])
+ vars(ax)[axes_handler[0]] = {'idx': ii, 'reject': False}
+
+ # initialize memory
+ for this_view, this_inds in zip(axes_handler, idx_handler):
+ for ii, ax in zip(this_inds, axes):
+ vars(ax)[this_view] = {'idx': ii, 'reject': False}
+
+ tight_layout()
+ navigation = figure_nobar(figsize=(3, 1.5))
+ from matplotlib import gridspec
+ gs = gridspec.GridSpec(2, 2)
+ ax1 = plt.subplot(gs[0, 0])
+ ax2 = plt.subplot(gs[0, 1])
+ ax3 = plt.subplot(gs[1, :])
+
+ params = {
+ 'fig': fig,
+ 'idx_handler': idx_handler,
+ 'epochs': epochs,
+ 'n_channels': n_channels,
+ 'picks': picks,
+ 'times': times,
+ 'scalings': scalings,
+ 'types': types,
+ 'good_ch_idx': good_ch_idx,
+ 'bad_ch_idx': bad_ch_idx,
+ 'axes': axes,
+ 'back': mpl.widgets.Button(ax1, 'back'),
+ 'next': mpl.widgets.Button(ax2, 'next'),
+ 'reject-quit': mpl.widgets.Button(ax3, 'reject-quit'),
+ 'title_str': title_str,
+ 'reject_idx': [],
+ 'axes_handler': axes_handler
+ }
+ fig.canvas.mpl_connect('button_press_event',
+ partial(_epochs_axes_onclick, params=params))
+ navigation.canvas.mpl_connect('button_press_event',
+ partial(_epochs_navigation_onclick,
+ params=params))
+ if show is True:
+ plt.show(block=block)
+ return fig
+
+
+def plot_source_spectrogram(stcs, freq_bins, source_index=None, colorbar=False,
+ show=True):
+ """Plot source power in time-freqency grid
+
+ Parameters
+ ----------
+ stcs : list of SourceEstimate
+ Source power for consecutive time windows, one SourceEstimate object
+ should be provided for each frequency bin.
+ freq_bins : list of tuples of float
+ Start and end points of frequency bins of interest.
+ source_index : int | None
+ Index of source for which the spectrogram will be plotted. If None,
+ the source with the largest activation will be selected.
+ colorbar : bool
+ If true, a colorbar will be added to the plot.
+ show : bool
+ Show figure if True.
+ """
+ import matplotlib.pyplot as plt
+
+ # Gathering results for each time window
+ source_power = np.array([stc.data for stc in stcs])
+
+ # Finding the source with maximum source power
+ if source_index is None:
+ source_index = np.unravel_index(source_power.argmax(),
+ source_power.shape)[1]
+
+ # Preparing time-frequency cell boundaries for plotting
+ stc = stcs[0]
+ time_bounds = np.append(stc.times, stc.times[-1] + stc.tstep)
+ freq_bounds = sorted(set(np.ravel(freq_bins)))
+ freq_ticks = deepcopy(freq_bounds)
+
+ # If there is a gap in the frequency bins record its locations so that it
+ # can be covered with a gray horizontal bar
+ gap_bounds = []
+ for i in range(len(freq_bins) - 1):
+ lower_bound = freq_bins[i][1]
+ upper_bound = freq_bins[i+1][0]
+ if lower_bound != upper_bound:
+ freq_bounds.remove(lower_bound)
+ gap_bounds.append((lower_bound, upper_bound))
+
+ # Preparing time-frequency grid for plotting
+ time_grid, freq_grid = np.meshgrid(time_bounds, freq_bounds)
+
+ # Plotting the results
+ plt.figure(figsize=(9, 6))
+ plt.pcolor(time_grid, freq_grid, source_power[:, source_index, :],
+ cmap=plt.cm.jet)
+ ax = plt.gca()
+
+ plt.title('Time-frequency source power')
+ plt.xlabel('Time (s)')
+ plt.ylabel('Frequency (Hz)')
+
+ time_tick_labels = [str(np.round(t, 2)) for t in time_bounds]
+ n_skip = 1 + len(time_bounds) // 10
+ for i in range(len(time_bounds)):
+ if i % n_skip != 0:
+ time_tick_labels[i] = ''
+
+ ax.set_xticks(time_bounds)
+ ax.set_xticklabels(time_tick_labels)
+ plt.xlim(time_bounds[0], time_bounds[-1])
+ plt.yscale('log')
+ ax.set_yticks(freq_ticks)
+ ax.set_yticklabels([np.round(freq, 2) for freq in freq_ticks])
+ plt.ylim(freq_bounds[0], freq_bounds[-1])
+
+ plt.grid(True, ls='-')
+ if colorbar:
+ plt.colorbar()
+ tight_layout()
+
+ # Covering frequency gaps with horizontal bars
+ for lower_bound, upper_bound in gap_bounds:
+ plt.barh(lower_bound, time_bounds[-1] - time_bounds[0], upper_bound -
+ lower_bound, time_bounds[0], color='lightgray')
+
+ if show:
+ plt.show()
diff --git a/setup.py b/setup.py
index 2253d7e..72ad6db 100755
--- a/setup.py
+++ b/setup.py
@@ -1,23 +1,33 @@
#! /usr/bin/env python
#
-# Copyright (C) 2011 Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
+# Copyright (C) 2011-2013 Alexandre Gramfort <gramfort at nmr.mgh.harvard.edu>
import os
-import mne
import setuptools # we are using a setuptools namespace
from numpy.distutils.core import setup
+# get the version (don't import mne here, so dependencies are not needed)
+version = None
+with open(os.path.join('mne', '__init__.py'), 'r') as fid:
+ for line in (line.strip() for line in fid):
+ if line.startswith('__version__'):
+ version = line.split('=')[1].strip().strip('\'')
+ break
+if version is None:
+ raise RuntimeError('Could not determine version')
+
+
descr = """MNE python project for MEG and EEG data analysis."""
-DISTNAME = 'mne'
-DESCRIPTION = descr
-MAINTAINER = 'Alexandre Gramfort'
-MAINTAINER_EMAIL = 'gramfort at nmr.mgh.harvard.edu'
-URL = 'http://martinos.org/mne'
-LICENSE = 'BSD (3-clause)'
-DOWNLOAD_URL = 'http://github.com/mne-tools/mne-python'
-VERSION = mne.__version__
+DISTNAME = 'mne'
+DESCRIPTION = descr
+MAINTAINER = 'Alexandre Gramfort'
+MAINTAINER_EMAIL = 'gramfort at nmr.mgh.harvard.edu'
+URL = 'http://martinos.org/mne'
+LICENSE = 'BSD (3-clause)'
+DOWNLOAD_URL = 'http://github.com/mne-tools/mne-python'
+VERSION = version
if __name__ == "__main__":
@@ -53,9 +63,13 @@ if __name__ == "__main__":
'mne.datasets',
'mne.datasets.sample',
'mne.datasets.megsim',
+ 'mne.datasets.spm_face',
'mne.fiff', 'mne.fiff.tests',
'mne.fiff.bti', 'mne.fiff.bti.tests',
'mne.fiff.kit', 'mne.fiff.kit.tests',
+ 'mne.fiff.edf', 'mne.fiff.edf.tests',
+ 'mne.fiff.brainvision', 'mne.fiff.brainvision.tests',
+ 'mne.forward', 'mne.forward.tests',
'mne.layouts', 'mne.layouts.tests',
'mne.minimum_norm', 'mne.minimum_norm.tests',
'mne.mixed_norm',
@@ -63,14 +77,14 @@ if __name__ == "__main__":
'mne.preprocessing', 'mne.preprocessing.tests',
'mne.simulation', 'mne.simulation.tests',
'mne.tests',
- 'mne.transforms',
'mne.stats', 'mne.stats.tests',
- 'mne.time_frequency', 'mne.time_frequency.tests'],
+ 'mne.time_frequency', 'mne.time_frequency.tests',
+ 'mne.realtime', 'mne.realtime.tests',
+ 'mne.decoding', 'mne.decoding.tests',
+ 'mne.commands'],
package_data={'mne': ['data/*.sel',
'data/icos.fif.gz',
- 'layouts/*.lout']},
- scripts=['bin/mne_clean_eog_ecg.py', 'bin/mne_flash_bem_model.py',
- 'bin/mne_surf2bem.py', 'bin/mne_compute_proj_ecg.py',
- 'bin/mne_compute_proj_eog.py', 'bin/mne_maxfilter.py',
- 'bin/mne_bti2fiff.py', 'bin/mne_kit2fiff.py',
- 'bin/mne_browse_raw.py'])
+ 'data/coil_def.dat',
+ 'layouts/*.lout',
+ 'layouts/*.lay']},
+ scripts=['bin/mne'])
--
Alioth's /git/debian-med/git-commit-notice on /srv/git.debian.org/git/debian-med/mne-python.git
More information about the debian-med-commit
mailing list