test meeg chan neighbors

function test_suite=test_meeg_chan_neighbors()
% tests for cosmo_meeg_chan_neighbors
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #
    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite;


function test_meeg_neighbors()
    if cosmo_skip_test_if_no_external('fieldtrip')
        return;
    end

    % switch off warnings by fieldtrip
    warning_state=warning('query','all');
    cleaner=onCleanup(@()warning(warning_state));
    warning('off','all');

    props=get_props();
    n=numel(props);

    % test a subset
    ntest=round(n*.5);


    % test a subset for fieldtrip
    % (fieldtrip is very slow, so testing all would take too long)
    ntest_fieldtrip=1;

    % visit in random order
    rp=randperm(n);

    prev_sens='';
    for k=1:ntest
        prop=props{rp(k)};

        sens=prop{1};
        layout_name=prop{2};
        args=prop{3};
        nchan=prop{4};
        chan_stats=prop{5};
        chan_labels=prop{6};

        if ~isequal(sens,prev_sens)
            ds=cosmo_synthetic_dataset('type','meeg',...
                                        'sens',sens,...
                                        'size','big');
        end

        nbrs=cosmo_meeg_chan_neighbors(ds,args{:});
        assertEqual(numel(nbrs),nchan);


        chan_count=cellfun(@numel,{nbrs.neighblabel});
        stats=[min(chan_count), max(chan_count), mean(chan_count)];
        assertElementsAlmostEqual(stats, chan_stats,'relative',1e-3);

        % test neighbor labels
        for j=1:numel(chan_labels)
            chan_label=chan_labels{j};
            center=chan_label{1};
            around=chan_label{2};

            % little optimization for finding first and last channel
            if j==1
                pos=1;
            else
                pos=nchan;
            end


            if ~strcmp(center,nbrs(pos).label)
                pos=find(cosmo_match({nbrs.label},center));
                assert(numel(pos)==1);
            end


            assertEqual(sort(around(:)),sort(nbrs(pos).neighblabel));
        end

        can_test_fieldtrip=~isempty(layout_name) && ...
                                isequal(args{4},'layout') && ...
                                ~strcmp(args{1},'count');
        if can_test_fieldtrip && ntest_fieldtrip>0
            cfg=struct();
            cfg.layout=layout_name;
            switch args{1}
                case 'delaunay'
                    cfg.method='triangulation';
                case 'radius'
                    cfg.method='distance';
                    cfg.neighbourdist=args{2};
                otherwise
                    assert(false);
            end
            y=ft_prepare_neighbours(cfg);

            % reorder the labels if necessary
            nbrs_cell=cellfun(@(x){x},{nbrs.label},'UniformOutput',false);
            y_cell=cellfun(@(x){x},{y.label},'UniformOutput',false);

            p=cosmo_overlap(nbrs_cell,y_cell);
            [i,j]=find(p==1);
            y=y(i);

            assertEqual({nbrs.label},{y.label});

            [p,q]=cosmo_overlap({nbrs.neighblabel},{y.neighblabel});
            dp=diag(p);
            dq=diag(q);
            assert(mean(dp(isfinite(dp)))>.9);
            assert(mean(dq(isfinite(dq)))>.8);

            ntest_fieldtrip=ntest_fieldtrip-1;
        end
    end







function props=get_props()

    % properties to test; each cell has these elements:
    % - dataset type
    % - arguments for neighbors
    % - number of neighbors
    % - min, max, mean number of channels
    % - a few channel labels and their neighbors
    props={{'neuromag306_all',...
                'neuromag306mag.lay',...
                {'delaunay',true,'label','layout','chantype',...
                    'meg_axial'},...
                102,[5 11 7.9412],...
                {{'MEG0111',...
                        {'MEG0111','MEG0121','MEG0131',...
                            'MEG0141','MEG0341','MEG0511'}},...
                    {'MEG2641',...
                        {'MEG1331','MEG2421','MEG2431',...
                            'MEG2441','MEG2521','MEG2611',...
                            'MEG2621','MEG2631','MEG2641'}}}},...
            {'neuromag306_all',...
                'neuromag306planar.lay',...
                {'delaunay',true,'label','layout','chantype',...
                    'meg_planar'},...
                204,[4 12 8.0392],...
                {{'MEG0113',...
                        {'MEG0113','MEG0112','MEG0122',...
                            'MEG0132','MEG0133','MEG0142',...
                            'MEG0343'}},...
                    {'MEG2643',...
                        {'MEG1333','MEG2423','MEG2422',...
                            'MEG2612','MEG2623','MEG2622',...
                            'MEG2642','MEG2643'}}}},...
            {'neuromag306_planar',...
                'neuromag306planar.lay',...
                {'radius',0.1,'label','dataset','chantype',...
                    'meg_planar'},...
                204,[4 14 8.9118],...
                {{'MEG0113',...
                        {'MEG0113','MEG0112','MEG0122',...
                            'MEG0132','MEG0133'}},...
                    {'MEG2643',...
                        {'MEG2423','MEG2422','MEG2623',...
                            'MEG2622','MEG2632','MEG2642',...
                            'MEG2643'}}}},...
            {'neuromag306_planar',...
                'neuromag306planar.lay',...
                {'radius',0.1,'label','dataset','chantype',...
                    'meg_combined_from_planar'},...
                102,[4 16 8.9804],...
                {{'MEG0112+0113',...
                        {'MEG0112','MEG0113','MEG0122',...
                            'MEG0123','MEG0132','MEG0133'}},...
                    {'MEG2642+2643',...
                        {'MEG2422','MEG2423','MEG2622',...
                            'MEG2623','MEG2632','MEG2633',...
                            'MEG2642','MEG2643'}}}},...
            {'neuromag306_planar_combined',...
                'neuromag306cmb.lay',...
                {'count',5,'label','layout','chantype',...
                    'meg_planar_combined'},...
                102,[5 5 5],...
                {{'MEG0112+0113',...
                        {'MEG0112+0113','MEG0122+0123',...
                            'MEG0132+0133','MEG0212+0213',...
                            'MEG0342+0343'}},...
                    {'MEG2642+2643',...
                        {'MEG2422+2423','MEG2432+2433',...
                            'MEG2622+2623','MEG2632+2633',...
                            'MEG2642+2643'}}}},...
            {'ctf151',...
                'CTF151.lay',...
                {'delaunay',true,'label','dataset','chantype',...
                    'meg_axial'},...
                151,[5 11 8.404],...
                {{'MLC11',...
                        {'MLC11','MLC12','MLC21','MLF41',...
                            'MLF51','MLF52','MRC11','MZC01',...
                            'MZF03'}},...
                    {'MZP02',...
                        {'MLO11','MLP21','MLP31','MRO11',...
                            'MRP21','MRP31','MZO01','MZP01',...
                            'MZP02'}}}},...
            {'ctf151',...
                'CTF151.lay',...
                {'delaunay',true,'label','dataset','chantype',...
                    'meg_planar_combined'},...
                151,[5 11 8.404],...
                {{'MLC11',...
                        {'MLC11','MLC12','MLC21','MLF41',...
                            'MLF51','MLF52','MRC11','MZC01',...
                            'MZF03'}},...
                    {'MZP02',...
                        {'MLO11','MLP21','MLP31','MRO11',...
                            'MRP21','MRP31','MZO01','MZP01',...
                            'MZP02'}}}},...
            {'ctf151_planar',...
                [],...
                {'radius',0.1,'label',...
                    {'MLC11_dH','MLC12_dH','MLC13_dH',...
                        'MLC14_dH','MLC15_dH','MLC21_dH',...
                        'MRT41_dV','MRT42_dV','MRT43_dV',...
                        'MRT44_dV','MZC01_dV','MZC02_dV'},...
                    'chantype','meg_planar'},...
                12,[1 4 2.3333],...
                {{'MLC11_dH',...
                        {'MLC11_dH','MLC12_dH','MLC21_dH',...
                            'MZC01_dV'}},...
                    {'MZC02_dV',{'MZC02_dV'}}}},...
            {'ctf151_planar',...
                [],...
                {'radius',0.1,'label',...
                    {'MLC11_dH','MLC12_dH','MLC13_dH',...
                        'MLC14_dH','MLC15_dH','MLC21_dH',...
                        'MRT41_dV','MRT42_dV','MRT43_dV',...
                        'MRT44_dV','MZC01_dV','MZC02_dV'},...
                    'chantype','meg_combined_from_planar'},...
                12,[1 4 2.3333],...
                {{'MLC11',...
                        {'MLC11_dH','MLC12_dH','MLC21_dH',...
                            'MZC01_dV'}},...
                    {'MZC02',{ 'MZC02_dV' }}}},...
            {'ctf151_planar_combined',...
                'CTF151.lay',...
                {'count',5,'label','dataset','chantype',...
                    'meg_axial'},...
                151,[5 5 5],...
                {{'MLC11',...
                        {'MLC11','MLC12','MLF51','MRC11',...
                            'MZF03'}},...
                    {'MZP02',...
                        {'MLO11','MLP21','MRO11','MRP21',...
                            'MZP02'}}}},...
            {'ctf151_planar_combined',...
                'CTF151.lay',...
                {'count',5,'label','dataset','chantype',...
                    'meg_planar_combined'},...
                151,[5 5 5],...
                {{'MLC11',...
                        {'MLC11','MLC12','MLF51','MRC11',...
                            'MZF03'}},...
                    {'MZP02',...
                        {'MLO11','MLP21','MRO11','MRP21',...
                            'MZP02'}}}},...
            {'4d148',...
                '4D148.lay',...
                {'delaunay',true,'label',...
                    {'A148','A147','A146','A145','A144',...
                        'A143','A13','A12','A11','A10','A9',...
                        'A8'},...
                    'chantype','meg_axial'},...
                12,[4 9 6.8333],...
                {{'A8',{'A8','A9','A10','A11','A13','A143'}},...
                    {'A148',...
                        {'A10','A11','A12','A13','A143',...
                            'A147','A148'}}}},...
            {'4d148',...
                '4D148.lay',...
                {'delaunay',true,'label',...
                    {'A148','A147','A146','A145','A144',...
                        'A143','A13','A12','A11','A10','A9',...
                        'A8'},...
                    'chantype','meg_planar_combined'},...
                12,[4 9 6.8333],...
                {{'A8',{'A8','A9','A10','A11','A13','A143'}},...
                    {'A148',...
                        {'A10','A11','A12','A13','A143',...
                            'A147','A148'}}}},...
            {'4d148_planar',...
                [],...
                {'radius',0.1,'label','layout','chantype',...
                    'meg_planar'},...
                296,[4 20 13.1351],...
                {{'A1_dH',...
                        {'A1_dH','A1_dV','A2_dH','A2_dV',...
                            'A3_dH','A3_dV','A5_dH','A5_dV',...
                            'A6_dH','A6_dV','A7_dH','A7_dV',...
                            'A10_dH','A10_dV','A11_dH','A11_dV',...
                            'A12_dH','A12_dV'}},...
                    {'A148_dV',...
                        {'A129_dH','A129_dV','A130_dH',...
                            'A130_dV','A148_dH','A148_dV'}}}},...
            {'4d148_planar',...
                [],...
                {'radius',0.1,'label','layout','chantype',...
                    'meg_combined_from_planar'},...
                148,[4 20 13.1351],...
                {{'A1',...
                        {'A10_dH','A10_dV','A11_dH','A11_dV',...
                            'A12_dH','A12_dV','A1_dH','A1_dV',...
                            'A2_dH','A2_dV','A3_dH','A3_dV',...
                            'A5_dH','A5_dV','A6_dH','A6_dV',...
                            'A7_dH','A7_dV'}},...
                    {'A148',...
                        {'A129_dH','A129_dV','A130_dH',...
                            'A130_dV','A148_dH','A148_dV'}}}},...
            {'4d148_planar_combined',...
                '4D148.lay',...
                {'count',5,'label',...
                    {'A148','A147','A146','A145','A144',...
                        'A143','A13','A12','A11','A10','A9',...
                        'A8'},...
                    'chantype','meg_axial'},...
                12,[5 5 5],...
                {{'A8',{'A8','A9','A10','A11','A12'}},...
                    {'A148',{'A12','A145','A146','A147','A148'}}}},...
            {'4d148_planar_combined',...
                '4D148.lay',...
                {'count',5,'label',...
                    {'A148','A147','A146','A145','A144',...
                        'A143','A13','A12','A11','A10','A9',...
                        'A8'},...
                    'chantype','meg_planar_combined'},...
                12,[5 5 5],...
                {{'A8',{'A8','A9','A10','A11','A12'}},...
                    {'A148',{'A12','A145','A146','A147','A148'}}}},...
            {'4d248',...
                '4D248.lay',...
                {'delaunay',true,'label','layout','chantype',...
                    'meg_axial'},...
                248,[5 12 8.2903],...
                {{'A1',...
                        {'A1','A2','A9','A10','A11','A12',...
                            'A13','A14'}},...
                    {'A248',...
                        {'A151','A152','A194','A195','A227',...
                            'A228','A246','A247','A248'}}}},...
            {'4d248',...
                '4D248.lay',...
                {'delaunay',true,'label','layout','chantype',...
                    'meg_planar_combined'},...
                248,[5 12 8.2903],...
                {{'A1',...
                        {'A1','A2','A9','A10','A11','A12',...
                            'A13','A14'}},...
                    {'A248',...
                        {'A151','A152','A194','A195','A227',...
                            'A228','A246','A247','A248'}}}},...
            {'4d248_planar',...
                [],...
                {'radius',0.1,'label','dataset','chantype',...
                    'meg_planar'},...
                496,[8 32 22.1452],...
                {{'A1_dH',...
                        {'A1_dH','A1_dV','A2_dH','A2_dV',...
                            'A9_dH','A9_dV','A10_dH','A10_dV',...
                            'A11_dH','A11_dV','A12_dH','A12_dV',...
                            'A13_dH','A13_dV','A14_dH','A14_dV',...
                            'A15_dH','A15_dV','A25_dH','A25_dV',...
                            'A28_dH','A28_dV','A30_dH','A30_dV',...
                            'A31_dH','A31_dV'}},...
                    {'A248_dV',...
                        {'A194_dH','A194_dV','A227_dH',...
                            'A227_dV','A228_dH','A228_dV',...
                            'A247_dH','A247_dV','A248_dH',...
                            'A248_dV'}}}},...
            {'4d248_planar',...
                [],...
                {'radius',0.1,'label','dataset','chantype',...
                    'meg_combined_from_planar'},...
                248,[8 32 22.1452],...
                {{'A1',...
                        {'A10_dH','A10_dV','A11_dH','A11_dV',...
                            'A12_dH','A12_dV','A13_dH','A13_dV',...
                            'A14_dH','A14_dV','A15_dH','A15_dV',...
                            'A1_dH','A1_dV','A25_dH','A25_dV',...
                            'A28_dH','A28_dV','A2_dH','A2_dV',...
                            'A30_dH','A30_dV','A31_dH','A31_dV',...
                            'A9_dH','A9_dV'}},...
                    {'A248',...
                        {'A194_dH','A194_dV','A227_dH',...
                            'A227_dV','A228_dH','A228_dV',...
                            'A247_dH','A247_dV','A248_dH',...
                            'A248_dV'}}}},...
            {'4d248_planar_combined',...
                '4D248.lay',...
                {'count',5,'label','layout','chantype',...
                    'meg_axial'},...
                248,[5 5 5],...
                {{'A1',{'A1','A2','A10','A12','A14'}},...
                    {'A248',{'A194','A227','A228','A247','A248'}}}},...
            {'4d248_planar_combined',...
                '4D248.lay',...
                {'count',5,'label','layout','chantype',...
                    'meg_planar_combined'},...
                248,[5 5 5],...
                {{'A1',{'A1','A2','A10','A12','A14'}},...
                    {'A248',{'A194','A227','A228','A247','A248'}}}},...
            {'eeg1005',...
                'EEG1005.lay',...
                {'delaunay',true,'label','dataset','chantype',...
                    'eeg'},...
                335,[5 11 8.3851],...
                {{'Fp1',...
                        {'Fp1','AFp9h','AFp7h','AFp5h','Fp1h',...
                            'AFp9','AFp7','AFp5','AFp3'}},...
                    {'OI2',...
                        {'O2','I2','POO8h','POO10h','OI2h',...
                            'O2h','I2h','POO6','POO8','POO10',...
                            'OI2'}}}},...
            {'eeg1010',...
                'EEG1010.lay',...
                {'radius',0.1,'label',...
                    {'TP10','TP7','TP8','TP9','CP1','CP2',...
                        'PO8','PO9','POz','O1','O2','Oz'},...
                    'chantype','eeg'},...
                12,[1 2 1.5],{{'TP9',{'TP9','TP7'}},{'O2',{'O2'}}}},...
            {'eeg1020',...
                'EEG1020.lay',...
                {'count',5,'label','layout','chantype',...
                    'eeg'},...
                21,[5 6 5.0952],...
                {{'Fp1',{'Fp1','Fpz','F7','F3','Fz'}},...
                    {'O2',{'Pz','P4','O1','Oz','O2'}}}}
        };