Пример #1
0
def test_sample_mask():
    """Test load method and sample mask."""
    # create a version with srub_mask not applied;
    # This is not recommanded
    conf = lc.Confounds(strategy=["motion", "scrub"],
                        scrub="full",
                        fd_thresh=0.15)
    reg, mask = conf.load(file_confounds)

    # the current test data has 6 time points marked as motion outliers,
    # and one nonsteady state (overlap with the first motion outlier)
    # 2 time points removed due to the "full" srubbing strategy
    assert reg.shape[0] - len(mask) == 8
    # nilearn requires unmasked confound regressors
    assert reg.shape[0] == 30

    # non steady state will always be removed
    conf = lc.Confounds(strategy=["motion"])
    reg, mask = conf.load(file_confounds)
    assert reg.shape[0] - len(mask) == 1

    # When no non-steady state volumes are present
    conf = lc.Confounds(strategy=["motion"])
    reg, mask = conf.load(file_no_none_steady)
    assert mask is None
Пример #2
0
def test_not_found_exception():

    conf = lc.Confounds(strategy=["high_pass", "motion", "global"],
                        global_signal="full",
                        motion="full")

    missing_params = ["trans_y", "trans_x_derivative1", "rot_z_power2"]
    missing_keywords = ["cosine"]

    file_missing_confounds = os.path.join(
        path_data,
        "missing_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz")
    with pytest.raises(ValueError) as exc_info:
        conf.load(file_missing_confounds)
    assert f"{missing_params}" in exc_info.value.args[0]
    assert f"{missing_keywords}" in exc_info.value.args[0]

    # loading anat compcor should also raise an error, because the json file is
    # missing for that example dataset
    with pytest.raises(ValueError):
        conf = lc.Confounds(strategy=["compcor"], compcor="anat")
        conf.load(file_missing_confounds)

    # catch invalid compcor option
    with pytest.raises(KeyError):
        conf = lc.Confounds(strategy=["compcor"], compcor="blah")
        conf.load(file_confounds)

    # catch invalid compcor option
    with pytest.raises(ValueError):
        conf = lc.Confounds(strategy=["compcor"],
                            compcor="full",
                            acompcor_combined=None)
        conf.load(file_confounds)
Пример #3
0
def test_sanitize_strategy():
    """Check that flawed strategy options generate meaningful error messages."""
    with pytest.raises(ValueError):
        lc.Confounds(strategy="string")

    with pytest.raises(ValueError):
        lc.Confounds(strategy=["error"])

    with pytest.raises(ValueError):
        lc.Confounds(strategy=[0])
Пример #4
0
def test_sanitize_strategy():
    """Check that flawed strategy options generate meaningful error messages."""
    with pytest.raises(ValueError):
        lc.Confounds(strategy="string")

    with pytest.raises(ValueError):
        lc.Confounds(strategy=["error"])

    with pytest.raises(ValueError):
        lc.Confounds(strategy=[0])

    conf = lc.Confounds(strategy=["motion"])
    assert "non_steady_state" in conf.strategy
Пример #5
0
def test_n_motion():

    conf = lc.Confounds(strategy=["motion"], motion="full", n_motion=0.2)
    conf.load(file_confounds)
    assert "motion_pca_1" in conf.confounds_.columns
    assert "motion_pca_2" not in conf.confounds_.columns

    conf = lc.Confounds(strategy=["motion"], motion="full", n_motion=0.95)
    conf.load(file_confounds)
    assert "motion_pca_6" in conf.confounds_.columns

    with pytest.raises(ValueError):
        conf = lc.Confounds(strategy=["motion"], motion="full", n_motion=50)
        conf.load(file_confounds)
Пример #6
0
def test_n_compcor():

    conf = lc.Confounds(strategy=["compcor"], compcor="anat", n_compcor=2)
    conf.load(file_confounds)
    assert "a_comp_cor_00" in conf.confounds_.columns
    assert "a_comp_cor_01" in conf.confounds_.columns
    assert "a_comp_cor_02" not in conf.confounds_.columns
Пример #7
0
def test_confounds2df():
    """Check auto-detect of confonds from an fMRI nii image."""
    conf = lc.Confounds()
    file_confounds_nii = os.path.join(
        path_data, "test_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz")
    conf.load(file_confounds_nii)
    assert "trans_x" in conf.confounds_.columns
Пример #8
0
def test_nilearn_regress():
    """Try regressing out all motion types in nilearn."""
    # Regress full motion
    confounds, _ = lc.Confounds(strategy=["motion"],
                                motion="full").load(file_confounds)
    sample_mask = None  # not testing sample mask here
    _regression(confounds, sample_mask)

    # Regress high_pass
    confounds, _ = lc.Confounds(strategy=["high_pass"]).load(file_confounds)
    _regression(confounds, sample_mask)

    # Regress wm_csf
    confounds, _ = lc.Confounds(strategy=["wm_csf"],
                                wm_csf="full").load(file_confounds)
    _regression(confounds, sample_mask)
    # Regress global
    confounds, _ = lc.Confounds(strategy=["global"],
                                global_signal="full").load(file_confounds)
    _regression(confounds, sample_mask)

    # Regress AnatCompCor
    confounds, _ = lc.Confounds(strategy=["compcor"],
                                compcor="anat").load(file_confounds)
    _regression(confounds, sample_mask)

    # Regress TempCompCor
    confounds, _ = lc.Confounds(strategy=["compcor"],
                                compcor="temp").load(file_confounds)
    _regression(confounds, sample_mask)

    # Regress ICA-AROMA
    confounds, _ = lc.Confounds(strategy=["ica_aroma"],
                                ica_aroma="basic").load(file_confounds)
    _regression(confounds, sample_mask)
Пример #9
0
def test_read_file():
    """Check that loading missing or incomplete files produce error messages."""
    conf = lc.Confounds()
    with pytest.raises(FileNotFoundError):
        conf.load(" ")

    with pytest.raises(ValueError):
        df = pd.read_csv(file_confounds, sep="\t")
        df = df.drop("trans_x", axis=1)
        conf.load(df)
Пример #10
0
def test_nilearn_regress():
    """Try regressing out all motion types in nilearn."""
    # Regress full motion
    confounds = lc.Confounds(strategy=["motion"],
                             motion="full").load(file_confounds)
    _regression(confounds)

    # Regress high_pass
    confounds = lc.Confounds(strategy=["high_pass"]).load(file_confounds)
    _regression(confounds)

    # Regress wm_csf
    confounds = lc.Confounds(strategy=["wm_csf"],
                             wm_csf="full").load(file_confounds)
    _regression(confounds)

    # Regress global
    confounds = lc.Confounds(strategy=["global"],
                             global_signal="full").load(file_confounds)
    _regression(confounds)

    # Regress AnatCompCor
    confounds = lc.Confounds(strategy=["compcor"],
                             compcor="anat").load(file_confounds)
    _regression(confounds)

    # Regress TempCompCor
    confounds = lc.Confounds(strategy=["compcor"],
                             compcor="temp").load(file_confounds)
    _regression(confounds)
Пример #11
0
def test_ica_aroma():
    """Test ICA AROMA related file input."""
    aroma_nii = os.path.join(
        path_data,
        "test_space-MNI152NLin2009cAsym_desc-smoothAROMAnonaggr_bold.nii.gz")
    # Agressive strategy
    conf = lc.Confounds(strategy=["ica_aroma"], ica_aroma="basic")
    conf.load(file_confounds)
    for col_name in conf.confounds_.columns:
        # only aroma and non-steady state columns will be present
        assert re.match("(?:aroma_motion_+|non_steady_state+)", col_name)

    # Non-agressive strategy
    conf = lc.Confounds(strategy=["ica_aroma"], ica_aroma="full")
    conf.load(aroma_nii)
    assert conf.confounds_.size == 0

    # invalid combination of strategy and option
    with pytest.raises(ValueError) as exc_info:
        conf = lc.Confounds(strategy=["ica_aroma"], ica_aroma=None)
        conf.load(file_confounds)
    assert "ICA-AROMA strategy" in exc_info.value.args[0]
Пример #12
0
def test_not_found_exception():

    conf = lc.Confounds(strategy=["high_pass", "motion", "global"],
                        global_signal="full",
                        motion="full")

    missing_params = ["trans_y", "trans_x_derivative1", "rot_z_power2"]
    missing_keywords = ["cosine"]

    file_missing_confounds = os.path.join(
        path_data,
        "missing_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz")

    with pytest.raises(ValueError) as exc_info:
        conf.load(file_missing_confounds)
    assert f"{missing_params}" in exc_info.value.args[0]
    assert f"{missing_keywords}" in exc_info.value.args[0]

    # loading anat compcor should also raise an error, because the json file is
    # missing for that example dataset
    with pytest.raises(ValueError):
        conf = lc.Confounds(strategy=["compcor"], compcor="anat")
        conf.load(file_missing_confounds)

    # catch invalid compcor option
    with pytest.raises(KeyError):
        conf = lc.Confounds(strategy=["compcor"], compcor="blah")
        conf.load(file_confounds)

    # catch invalid compcor option
    with pytest.raises(ValueError):
        conf = lc.Confounds(strategy=["compcor"],
                            compcor="full",
                            acompcor_combined=None)
        conf.load(file_confounds)

    # Aggressive ICA-AROMA strategy requires
    # default nifti and noise ICs in confound file
    # correct nifti but missing noise regressor
    with pytest.raises(ValueError) as exc_info:
        conf = lc.Confounds(strategy=["ica_aroma"], ica_aroma="basic")
        conf.load(file_missing_confounds)
    assert "aroma" in exc_info.value.args[0]

    # Aggressive ICA-AROMA strategy requires
    # default nifti
    aroma_nii = os.path.join(
        path_data,
        "test_space-MNI152NLin2009cAsym_desc-smoothAROMAnonaggr_bold.nii.gz")
    with pytest.raises(ValueError) as exc_info:
        conf.load(aroma_nii)
    assert "Invalid file type" in exc_info.value.args[0]

    # non aggressive ICA-AROMA strategy requires
    # desc-smoothAROMAnonaggr nifti file
    with pytest.raises(ValueError) as exc_info:
        conf = lc.Confounds(strategy=["ica_aroma"], ica_aroma="full")
        conf.load(file_missing_confounds)
    assert "desc-smoothAROMAnonaggr_bold" in exc_info.value.args[0]
Пример #13
0
def _simu_img(demean=True):
    """Simulate an nifti image based on confound file with some parts confounds and some parts noise."""
    # set the size of the image matrix
    nx = 5
    ny = 5
    # the actual number of slices will actually be double of that
    # as we will stack slices with confounds on top of slices with noise
    nz = 2
    # Load a simple 6 parameters motion models as confounds
    confounds, _ = lc.Confounds(strategy=["motion"],
                                motion="basic",
                                demean=demean).load(file_confounds)
    X = confounds.values
    # the first row is non-steady state, replace it with the imput from the second row
    non_steady = X[0, :]
    X[0, :] = X[1, :]
    # repeat X in length (axis = 0) three times to increase the degree of freedom
    X = np.tile(X, (3, 1))
    # put non-steady state volume back at the first sample
    X[0, :] = non_steady
    # the number of time points is based on the example confound file
    nt = X.shape[0]
    # initialize an empty 4D volume
    vol = np.zeros([nx, ny, 2 * nz, nt])
    vol_conf = np.zeros([nx, ny, 2 * nz])
    vol_rand = np.zeros([nx, ny, 2 * nz])

    # create a random mixture of confounds
    # standardized to zero mean and unit variance
    beta = np.random.rand(nx * ny * nz, X.shape[1])
    tseries_conf = scale(np.matmul(beta, X.transpose()), axis=1)
    # fill the first half of the 4D data with the mixture
    vol[:, :, 0:nz, :] = tseries_conf.reshape(nx, ny, nz, nt)
    vol_conf[:, :, 0:nz] = 1

    # create random noise in the second half of the 4D data
    tseries_rand = scale(np.random.randn(nx * ny * nz, nt), axis=1)
    vol[:, :, range(nz, 2 * nz), :] = tseries_rand.reshape(nx, ny, nz, nt)
    vol_rand[:, :, range(nz, 2 * nz)] = 1

    # Shift the mean to non-zero
    vol = vol + 100

    # create an nifti image with the data, and corresponding mask
    img = Nifti1Image(vol, np.eye(4))
    mask_conf = Nifti1Image(vol_conf, np.eye(4))
    mask_rand = Nifti1Image(vol_rand, np.eye(4))

    return img, mask_conf, mask_rand, X
Пример #14
0
def test_motion():

    conf_basic = lc.Confounds(strategy=["motion"], motion="basic")
    conf_basic.load(file_confounds)
    conf_derivatives = lc.Confounds(strategy=["motion"], motion="derivatives")
    conf_derivatives.load(file_confounds)
    conf_power2 = lc.Confounds(strategy=["motion"], motion="power2")
    conf_power2.load(file_confounds)
    conf_full = lc.Confounds(strategy=["motion"], motion="full")
    conf_full.load(file_confounds)

    params = ["trans_x", "trans_y", "trans_z", "rot_x", "rot_y", "rot_z"]
    for param in params:
        # Basic 6 params motion model
        assert f"{param}" in conf_basic.confounds_.columns
        assert f"{param}_derivative1" not in conf_basic.confounds_.columns
        assert f"{param}_power2" not in conf_basic.confounds_.columns
        assert f"{param}_derivative1_power2" not in conf_basic.confounds_.columns

        # Use a 6 params + derivatives motion model
        assert f"{param}" in conf_derivatives.confounds_.columns
        assert f"{param}_derivative1" in conf_derivatives.confounds_.columns
        assert f"{param}_power2" not in conf_derivatives.confounds_.columns
        assert f"{param}_derivative1_power2" not in conf_derivatives.confounds_.columns

        # Use a 6 params + power2 motion model
        assert f"{param}" in conf_power2.confounds_.columns
        assert f"{param}_derivative1" not in conf_power2.confounds_.columns
        assert f"{param}_power2" in conf_power2.confounds_.columns
        assert f"{param}_derivative1_power2" not in conf_power2.confounds_.columns

        # Use a 6 params + derivatives + power2 + power2d derivatives motion model
        assert f"{param}" in conf_full.confounds_.columns
        assert f"{param}_derivative1" in conf_full.confounds_.columns
        assert f"{param}_power2" in conf_full.confounds_.columns
        assert f"{param}_derivative1_power2" in conf_full.confounds_.columns
Пример #15
0
def test_invalid_filetype():
    """Invalid file types/associated files for load method."""
    # invalid fmriprep version: contain confound files before and after v20.2.0
    conf = lc.Confounds()

    invalid_ver = os.path.join(
        path_data,
        "invalid_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz")
    with pytest.raises(ValueError):
        conf.load(invalid_ver)

    # nifti with no associated confound file
    no_confound = os.path.join(
        path_data,
        "noconfound_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz")
    with pytest.raises(ValueError):
        conf.load(no_confound)
Пример #16
0
def test_load_non_nifti():
    """Test non-nifti and invalid file type as input."""
    conf = lc.Confounds()

    # tsv file - unsupported input
    tsv = os.path.join(path_data, "test_desc-confounds_regressors.tsv")
    with pytest.raises(ValueError):
        conf.load(tsv)

    # cifti file should be supported
    cifti = os.path.join(path_data,
                         "test_space-fsLR_den-91k_bold.dtseries.nii")
    conf.load(cifti)
    assert conf.confounds_.size != 0

    # gifti support
    gifti = [
        os.path.join(path_data,
                     f"test_space-fsaverage5_hemi-{hemi}_bold.func.gii")
        for hemi in ["L", "R"]
    ]
    conf.load(gifti)
    assert conf.confounds_.size != 0
Пример #17
0
def test_ica_aroma():
    conf = lc.Confounds(strategy=["ica_aroma"])
    conf.load(file_confounds)
    for col_name in conf.columns_:
        assert re.match("aroma_motion_+", col_name)