test meeg layout collection

function test_suite=test_meeg_layout_collection
% tests for cosmo_meeg_layout_collection
%
% #   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_fieldtrip_correspondence
    if cosmo_skip_test_if_no_external('fieldtrip')
        return;
    end


    lc=cosmo_meeg_layout_collection();
    rp_lay=randperm(numel(lc));

    ntest_layout=2;
    ntest_chan_max=10;

    % may or may not be present
    ignore_labels={'COMNT','SCALE'};

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

    % shorter form
    tolerance=1e-4;
    aeae=@(x,y)max(abs(x(:)-y(:)))<tolerance && isequal(size(x),size(y));

    for ii=1:ntest_layout
        layout=lc{rp_lay(ii)};

        cfg=struct();
        cfg.layout=layout.name;
        layout_ft=ft_prepare_layout(cfg);

        % test outlnie
        for j=1:max(numel(layout_ft.outline),numel(layout.outline))
            aeae(layout_ft.outline{j},layout.outline{j});
        end

        % test mask
        for j=1:max(numel(layout_ft.mask),numel(layout.mask))
            aeae(layout_ft.outline{j},layout.outline{j});
        end

        % test labels
        keep_idxs=find(~cosmo_match(layout.label,ignore_labels));
        keep_ft_idxs=find(~cosmo_match(layout_ft.label,ignore_labels));
        assertEqual(sort(layout.label(keep_idxs)),...
                        sort(layout_ft.label(keep_ft_idxs)));

        % test positions
        ntest_chan=min(numel(keep_idxs),ntest_chan_max);
        rp_chan=randperm(numel(keep_idxs));
        for jj=1:ntest_chan
            test_label_idx=keep_idxs(rp_chan(jj));
            label=layout.label{test_label_idx};
            if strcmp(layout_ft.label{test_label_idx},label)
                % little optimization
                pos=test_label_idx;
            else
                pos=find(cosmo_match(layout_ft.label,{label}));
                assert(numel(pos)==1);
            end
            aeae(layout_ft.width(pos,:),layout.width(test_label_idx,:));
            aeae(layout_ft.height(pos,:),layout.height(test_label_idx,:));
            aeae(layout_ft.pos(pos,:),layout.pos(test_label_idx,:));
        end
    end

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

    % get layout properties
    % order is:
    % - layout name
    % - number of channels
    % - some channel positions
    % - labels of channel positions
    lay_props=get_layout_properties();

    % test each one
    n=numel(lay_props);

    clear('cosmo_meeg_layout_collection');
    lc=cosmo_meeg_layout_collection();
    lc_cached=cosmo_meeg_layout_collection();
    assertEqual(lc,lc_cached);
    lc_names=cellfun(@(x) x.name,lc,'UniformOutput',false);
    for k=1:n
        lay_prop=lay_props{k};
        name=lay_prop{1};
        nchan=lay_prop{2};
        pos=lay_prop{3};
        label=lay_prop{4};

        i=find(cosmo_match(lc_names,name));
        assertEqual(numel(i),1);

        lay=lc{i};
        keep=find(~cosmo_match(lay.label,{'COMNT','SCALE'}));
        assertEqual(numel(keep),nchan);

        for j=1:numel(label)
            lab_i=find(cosmo_match(lay.label,label{j}));
            assert(numel(lab_i)==1);
            assertElementsAlmostEqual(lay.pos(lab_i,:),pos(j,:),...
                                    'absolute',1e-4);
        end
    end

function lay_props=get_layout_properties()
    % the layout properties below were generated with the following code:
    % names={'yokogawa440.lay', 'neuromag306planar.lay',...
    %      'neuromag306mag.lay', 'neuromag306cmb.lay',...
    %      'neuromag306all.lay', 'elec1020.lay',...
    %      'elec1010.lay', 'elec1005.lay', 'biosemi32.lay',...
    %      'biosemi128.lay', 'biosemi256.lay', 'EEG1020.lay',...
    %      'EEG1010.lay', 'EEG1005.lay', 'CTF151.lay',...
    %      'CTF275.lay', '4D148.lay', '4D248.lay'};
    % lc=cosmo_meeg_layout_collection();
    % lcn=cellfun(@(x) x.name,lc,'UniformOutput',false);
    % for k=1:numel(names)
    %     fn=[names{k}];
    %     m=find(cosmo_match(lcn,fn));
    %     lay=lc{m};
    %     keep=find(~cosmo_match(lay.label,{'COMNT','SCALE'}));
    %     nch=numel(keep);
    %     desc=sprintf(['{''%s'',%d,...\n\t\t\t[%.4f %.4f;%.4f %.4f],'...
    %                     '...\n\t\t\t{''%s'',''%s''}},...'],...
    %                     lay.name,nch,lay.pos(keep([1 end]),:)',...
    %                     lay.label{keep(1)},lay.label{keep(end)});
    %     fprintf('%s\n',desc);
    % end


    lay_props={ {'4D248.lay',248,...
                            [0.0038 0.0232;0.3897 0.3453],...
                            {'A1','A248'}},...
                {'yokogawa440.lay',440,...
                            [-0.3337 0.3729;-0.0108 0.0726],...
                            {'AG001','AG440'}},...
                {'neuromag306planar.lay',204,...
                            [-0.4084 0.2532;0.3733 -0.0820],...
                            {'MEG0113','MEG2643'}},...
                {'neuromag306mag.lay',102,...
                            [-0.4084 0.2732;0.3733 -0.1036],...
                            {'MEG0111','MEG2641'}},...
                {'neuromag306cmb.lay',102,...
                            [-0.4084 0.2732;0.3733 -0.1036],...
                            {'MEG0112+0113','MEG2642+2643'}},...
                {'neuromag306all.lay',306,...
                            [-0.4099 0.2532;0.3761 -0.0976],...
                            {'MEG0113','MEG2641'}},...
                {'elec1020.lay',21,...
                            [-0.1710 0.4010;0.1710 -0.4010],...
                            {'Fp1','O2'}},...
                {'elec1010.lay',86,...
                            [-0.1112 0.4261;0.1391 -0.4257],...
                            {'Fp1','I2'}},...
                {'elec1005.lay',335,...
                            [-0.1112 0.3881;0.1252 -0.3814],...
                            {'Fp1','OI2'}},...
                {'biosemi32.lay',32,...
                            [-0.1391 0.4500;0.0000 0.0113],...
                            {'Fp1','Cz'}},...
                {'biosemi128.lay',128,...
                            [0.0000 0.0500;-0.4096 -0.2145],...
                            {'A1','D32'}},...
                {'biosemi256.lay',256,...
                            [0.0000 0.0587;-0.2290 -0.4060],...
                            {'A1','H32'}},...
                {'EEG1020.lay',21,...
                            [-0.1390 0.4280;0.1390 -0.4280],...
                            {'Fp1','O2'}},...
                {'EEG1010.lay',86,...
                            [-0.1112 0.4260;0.1390 -0.4256],...
                            {'Fp1','I2'}},...
                {'EEG1005.lay',335,...
                            [-0.1112 0.3880;0.1252 -0.3814],...
                            {'Fp1','OI2'}},...
                {'CTF151.lay',151,...
                            [-0.0344 0.1732;0.0008 -0.2668],...
                            {'MLC11','MZP02'}},...
                {'CTF275.lay',275,...
                            [-0.0171 0.1815;0.0002 -0.2056],...
                            {'MLC11','MZP01'}},...
                {'4D148.lay',148,...
                            [-0.0109 0.0939;0.3709 0.3364],...
                            {'A1','A148'}},...
                {'4D248.lay',248,...
                            [0.0038 0.0232;0.3897 0.3453],...
                            {'A1','A248'}}};