rpipe 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +23 -0
- data/LICENSE +20 -0
- data/README +0 -0
- data/README.rdoc +33 -0
- data/Rakefile +78 -0
- data/VERSION +1 -0
- data/bin/create_driver.rb +79 -0
- data/bin/rpipe +131 -0
- data/bin/swallow_batch_run.rb +21 -0
- data/lib/core_additions.rb +5 -0
- data/lib/custom_methods/JohnsonMerit220Visit1Preproc.m +26 -0
- data/lib/custom_methods/JohnsonMerit220Visit1Preproc.rb +43 -0
- data/lib/custom_methods/JohnsonMerit220Visit1Preproc_job.m +80 -0
- data/lib/custom_methods/JohnsonMerit220Visit1Stats.m +74 -0
- data/lib/custom_methods/JohnsonMerit220Visit1Stats.rb +63 -0
- data/lib/custom_methods/JohnsonMerit220Visit1Stats_job.m +63 -0
- data/lib/custom_methods/JohnsonTbiLongitudinalSnodPreproc.m +26 -0
- data/lib/custom_methods/JohnsonTbiLongitudinalSnodPreproc.rb +41 -0
- data/lib/custom_methods/JohnsonTbiLongitudinalSnodPreproc_job.m +69 -0
- data/lib/custom_methods/JohnsonTbiLongitudinalSnodStats.m +76 -0
- data/lib/custom_methods/JohnsonTbiLongitudinalSnodStats.rb +67 -0
- data/lib/custom_methods/JohnsonTbiLongitudinalSnodStats_job.m +59 -0
- data/lib/custom_methods/ReconWithHello.rb +7 -0
- data/lib/default_logger.rb +13 -0
- data/lib/default_methods/default_preproc.rb +76 -0
- data/lib/default_methods/default_recon.rb +80 -0
- data/lib/default_methods/default_stats.rb +94 -0
- data/lib/default_methods/recon/physionoise_helper.rb +69 -0
- data/lib/default_methods/recon/raw_sequence.rb +109 -0
- data/lib/generators/job_generator.rb +36 -0
- data/lib/generators/preproc_job_generator.rb +31 -0
- data/lib/generators/recon_job_generator.rb +76 -0
- data/lib/generators/stats_job_generator.rb +70 -0
- data/lib/generators/workflow_generator.rb +128 -0
- data/lib/global_additions.rb +18 -0
- data/lib/logfile.rb +310 -0
- data/lib/matlab_helpers/CreateFunctionalVolumeStruct.m +6 -0
- data/lib/matlab_helpers/import_csv.m +32 -0
- data/lib/matlab_helpers/matlab_queue.rb +37 -0
- data/lib/matlab_helpers/prepare_onsets_xls.m +30 -0
- data/lib/rpipe.rb +254 -0
- data/rpipe.gemspec +177 -0
- data/spec/generators/preproc_job_generator_spec.rb +27 -0
- data/spec/generators/recon_job_generator_spec.rb +33 -0
- data/spec/generators/stats_job_generator_spec.rb +50 -0
- data/spec/generators/workflow_generator_spec.rb +97 -0
- data/spec/helper_spec.rb +40 -0
- data/spec/integration/johnson.merit220.visit1_spec.rb +47 -0
- data/spec/integration/johnson.tbi.longitudinal.snod_spec.rb +48 -0
- data/spec/logfile_spec.rb +96 -0
- data/spec/matlab_queue_spec.rb +40 -0
- data/spec/merit220_stats_spec.rb +81 -0
- data/spec/physio_spec.rb +98 -0
- data/test/drivers/merit220_workflow_sample.yml +15 -0
- data/test/drivers/mrt00000.yml +65 -0
- data/test/drivers/mrt00015.yml +62 -0
- data/test/drivers/mrt00015_hello.yml +41 -0
- data/test/drivers/mrt00015_withphys.yml +81 -0
- data/test/drivers/tbi000.yml +129 -0
- data/test/drivers/tbi000_separatevisits.yml +137 -0
- data/test/drivers/tmp.yml +58 -0
- data/test/fixtures/faces3_recognitionA.mat +0 -0
- data/test/fixtures/faces3_recognitionA.txt +86 -0
- data/test/fixtures/faces3_recognitionA_equal.csv +25 -0
- data/test/fixtures/faces3_recognitionA_unequal.csv +21 -0
- data/test/fixtures/faces3_recognitionB_incmisses.txt +86 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_CPd3R_40.txt +13360 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_CPd3_40.txt +13360 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_CPttl_40.txt +13360 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_CRTd3R_40.txt +13360 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_CRTd3_40.txt +13360 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_CRTttl_40.txt +13360 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_HalfTR_CRTd3R_40.txt +334 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_HalfTR_CRTd3_40.txt +334 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_HalfTR_CRTttl_40.txt +334 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_HalfTR_RRT_40.txt +334 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_HalfTR_RVT_40.txt +334 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_HalfTR_card_spline_40.txt +334 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_HalfTR_resp_spline_40.txt +334 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_RRT_40.txt +9106 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_RVT_40.txt +9106 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_TR_CRTd3R_40.txt +167 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_TR_CRTd3_40.txt +167 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_TR_CRTttl_40.txt +167 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_TR_RRT_40.txt +167 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_TR_RVT_40.txt +167 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_TR_card_spline_40.txt +167 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_TR_resp_spline_40.txt +167 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_card_spline_40.txt +13360 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_resp_spline_40.txt +9106 -0
- data/test/fixtures/physionoise_regressors/EPI__fMRI_Task1_resp_spline_downsampled_40.txt +9106 -0
- data/test/fixtures/ruport_summary.yml +123 -0
- data/test/fixtures/valid_scans.yaml +35 -0
- data/test/helper.rb +10 -0
- data/test/test_dynamic_method_inclusion.rb +10 -0
- data/test/test_includes.rb +11 -0
- data/test/test_integrative_johnson.merit220.visit1.rb +31 -0
- data/test/test_preproc.rb +11 -0
- data/test/test_recon.rb +11 -0
- data/test/test_rpipe.rb +19 -0
- data/vendor/output_catcher.rb +93 -0
- data/vendor/trollop.rb +781 -0
- metadata +260 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'logfile'
|
|
2
|
+
module JohnsonMerit220Visit1Stats
|
|
3
|
+
|
|
4
|
+
DEFAULT_CONDITIONS = [:new_correct_, :new_incorrect_, :old_correct_, :old_incorrect, {:misses => [:new_misses, :old_misses]} ]
|
|
5
|
+
|
|
6
|
+
# runs the complete set of tasks using data in a subject's "proc" directory and a preconfigured template spm job.
|
|
7
|
+
def run_first_level_stats
|
|
8
|
+
flash "Highway to the dangerzone..."
|
|
9
|
+
setup_directory(@statsdir, "STATS")
|
|
10
|
+
|
|
11
|
+
Dir.chdir(@statsdir) do
|
|
12
|
+
link_files_from_proc_directory(File.join(@procdir, "sw*.nii"), File.join(@procdir, "rp*.txt"))
|
|
13
|
+
setup_onsets
|
|
14
|
+
run_stats_spm_job
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias_method :perform, :run_first_level_stats
|
|
19
|
+
|
|
20
|
+
def setup_onsets
|
|
21
|
+
setup_conditions
|
|
22
|
+
create_or_link_onsets_files
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def setup_conditions
|
|
26
|
+
@conditions = @conditions ? @conditions.collect! {|c| c.to_sym if c.respond_to? :to_sym } : DEFAULT_CONDITIONS
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def create_or_link_onsets_files
|
|
30
|
+
if @onsetsfiles.nil?
|
|
31
|
+
if @responses.nil?
|
|
32
|
+
raise ScriptError, "Condition vectors cannot be created because neither log response files nor onsets mat files have been specified."
|
|
33
|
+
else
|
|
34
|
+
@onsetsfiles = create_onsets_files(@responses, conditions)
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
link_onsets_files
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Finally runs the stats job
|
|
42
|
+
def run_stats_spm_job
|
|
43
|
+
images = Dir.glob(File.join(@statsdir, "sw*#{@subid}*[Tt]ask*.nii"))
|
|
44
|
+
raise ScriptError, "Can't find any smoothed, warped images in #{@statsdir}" if images.empty?
|
|
45
|
+
|
|
46
|
+
queue = MatlabQueue.new
|
|
47
|
+
queue.paths << ['/Applications/spm/spm8/spm8_current',
|
|
48
|
+
'/apps/spm/spm8_current',
|
|
49
|
+
File.join(@libdir, 'custom_methods'),
|
|
50
|
+
File.join(@libdir, 'matlab_helpers') ]
|
|
51
|
+
|
|
52
|
+
queue << "#{@method}('#{@statsdir}/', \
|
|
53
|
+
{ #{images.collect {|im| "'#{File.basename(im)}'"}.join(' ')} }, \
|
|
54
|
+
{ #{@bold_reps.join(' ') } }, \
|
|
55
|
+
{ #{@onsetsfiles.collect { |file| "'#{File.basename(file)}'"}.join(' ') } }, \
|
|
56
|
+
{ #{@regressorsfiles.collect { |file| "'#{File.basename(file)}'"}.join(' ') } }, \
|
|
57
|
+
'#{@method}_job.m')"
|
|
58
|
+
|
|
59
|
+
# puts queue.to_s
|
|
60
|
+
queue.run!
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
%-----------------------------------------------------------------------
|
|
2
|
+
% Job configuration created by cfg_util (rev $Rev: 3599 $)
|
|
3
|
+
%-----------------------------------------------------------------------
|
|
4
|
+
%% Specification
|
|
5
|
+
matlabbatch{1}.spm.stats.fmri_spec.dir = '<UNDEFINED>';
|
|
6
|
+
matlabbatch{1}.spm.stats.fmri_spec.timing.units = 'scans';
|
|
7
|
+
matlabbatch{1}.spm.stats.fmri_spec.timing.RT = 2;
|
|
8
|
+
matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t = 16;
|
|
9
|
+
matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t0 = 1;
|
|
10
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(1).scans = '<UNDEFINED>';
|
|
11
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(1).cond = struct('name', {}, 'onset', {}, 'duration', {}, 'tmod', {}, 'pmod', {});
|
|
12
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(1).multi = '<UNDEFINED>';
|
|
13
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(1).regress = struct('name', {}, 'val', {});
|
|
14
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(1).multi_reg = '<UNDEFINED>';
|
|
15
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(1).hpf = 128;
|
|
16
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(2).scans = '<UNDEFINED>';
|
|
17
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(2).cond = struct('name', {}, 'onset', {}, 'duration', {}, 'tmod', {}, 'pmod', {});
|
|
18
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(2).multi = '<UNDEFINED>';
|
|
19
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(2).regress = struct('name', {}, 'val', {});
|
|
20
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(2).multi_reg = '<UNDEFINED>';
|
|
21
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(2).hpf = 128;
|
|
22
|
+
matlabbatch{1}.spm.stats.fmri_spec.fact = struct('name', {}, 'levels', {});
|
|
23
|
+
matlabbatch{1}.spm.stats.fmri_spec.bases.hrf.derivs = [0 0];
|
|
24
|
+
matlabbatch{1}.spm.stats.fmri_spec.volt = 1;
|
|
25
|
+
matlabbatch{1}.spm.stats.fmri_spec.global = 'None';
|
|
26
|
+
matlabbatch{1}.spm.stats.fmri_spec.mask = {''};
|
|
27
|
+
matlabbatch{1}.spm.stats.fmri_spec.cvi = 'AR(1)';
|
|
28
|
+
%% Estimation
|
|
29
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1) = cfg_dep;
|
|
30
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tname = 'Select SPM.mat';
|
|
31
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tgt_spec{1}(1).name = 'filter';
|
|
32
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tgt_spec{1}(1).value = 'mat';
|
|
33
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tgt_spec{1}(2).name = 'strtype';
|
|
34
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tgt_spec{1}(2).value = 'e';
|
|
35
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).sname = 'fMRI model specification: SPM.mat File';
|
|
36
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).src_exbranch = substruct('.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1});
|
|
37
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).src_output = substruct('.','spmmat');
|
|
38
|
+
matlabbatch{2}.spm.stats.fmri_est.method.Classical = 1;
|
|
39
|
+
%% Contrast Creation
|
|
40
|
+
matlabbatch{3}.spm.stats.con.spmmat(1) = cfg_dep;
|
|
41
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tname = 'Select SPM.mat';
|
|
42
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tgt_spec{1}(1).name = 'filter';
|
|
43
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tgt_spec{1}(1).value = 'mat';
|
|
44
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tgt_spec{1}(2).name = 'strtype';
|
|
45
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tgt_spec{1}(2).value = 'e';
|
|
46
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).sname = 'Model estimation: SPM.mat File';
|
|
47
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).src_exbranch = substruct('.','val', '{}',{2}, '.','val', '{}',{1}, '.','val', '{}',{1});
|
|
48
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).src_output = substruct('.','spmmat');
|
|
49
|
+
matlabbatch{3}.spm.stats.con.consess{1}.fcon.name = '<UNDEFINED>';
|
|
50
|
+
matlabbatch{3}.spm.stats.con.consess{1}.fcon.convec{1} = '<UNDEFINED>';
|
|
51
|
+
matlabbatch{3}.spm.stats.con.consess{1}.fcon.sessrep = 'repl';
|
|
52
|
+
matlabbatch{3}.spm.stats.con.consess{2}.tcon.name = '<UNDEFINED>';
|
|
53
|
+
matlabbatch{3}.spm.stats.con.consess{2}.tcon.convec = '<UNDEFINED>';
|
|
54
|
+
matlabbatch{3}.spm.stats.con.consess{2}.tcon.sessrep = 'repl';
|
|
55
|
+
matlabbatch{3}.spm.stats.con.consess{3}.tcon.name = '<UNDEFINED>';
|
|
56
|
+
matlabbatch{3}.spm.stats.con.consess{3}.tcon.convec = '<UNDEFINED>';
|
|
57
|
+
matlabbatch{3}.spm.stats.con.consess{3}.tcon.sessrep = 'repl';
|
|
58
|
+
matlabbatch{3}.spm.stats.con.delete = 0;
|
|
59
|
+
|
|
60
|
+
% NOTE! F-contrasts expect cells containing contrast arrays, while
|
|
61
|
+
% T-contrasts expect the arrays themslves (hence the cell reference in
|
|
62
|
+
% F-contrast definition (convec{1} = [];) but not in T-contrast definition
|
|
63
|
+
% (convec = [];)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function [] = JohnsonTbiLongitudinalSnodPreproc(studypath, images, image_boldreps, job_mfile)
|
|
2
|
+
% [] = Calls and runs TBI Longitudinal preproc job.
|
|
3
|
+
% merit_preproc('/private/tmp/mrt00015_orig/', ...
|
|
4
|
+
% {'amrt00015_task1.nii' 'amrt00015_task2.nii' 'amrt00015_rest.nii'}, ...
|
|
5
|
+
% {164 164 164}, ...
|
|
6
|
+
% '/private/tmp/mrt00015_orig/mrt00015_preproc_job.m')
|
|
7
|
+
%
|
|
8
|
+
|
|
9
|
+
spm('defaults', 'FMRI');
|
|
10
|
+
|
|
11
|
+
% List of open inputs
|
|
12
|
+
% Realign: Estimate: Session - cfg_files
|
|
13
|
+
% Realign: Estimate: Session - cfg_files
|
|
14
|
+
% Realign: Estimate: Session - cfg_files
|
|
15
|
+
nrun = 1; % enter the number of runs here
|
|
16
|
+
jobfile = {job_mfile};
|
|
17
|
+
jobs = repmat(jobfile, 1, nrun);
|
|
18
|
+
inputs = cell(3, nrun);
|
|
19
|
+
|
|
20
|
+
for crun = 1:nrun
|
|
21
|
+
for index = 1:length(images)
|
|
22
|
+
inputs{index, crun} = CreateFunctionalVolumeStruct(studypath, images{index}, image_boldreps{index}); % Realign: Estimate: Session - cfg_files
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
spm_jobman('serial', jobs, '', inputs{:});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'matlab_helpers/matlab_queue'
|
|
2
|
+
module JohnsonTbiLongitudinalSnodPreproc
|
|
3
|
+
|
|
4
|
+
# Runs the preprocessing job, including spm job customization, run spm job, and handling motion issues.
|
|
5
|
+
# This function assumes a destination directory is set up; it will overwrite preexisting data. Careful!
|
|
6
|
+
def preproc_visit
|
|
7
|
+
flash "Spatial Preprocessing Subject: #{@subid}"
|
|
8
|
+
setup_directory(@procdir, "PREPROC")
|
|
9
|
+
|
|
10
|
+
Dir.chdir(@procdir) do
|
|
11
|
+
link_files_into_proc
|
|
12
|
+
run_preproc_mfile
|
|
13
|
+
deal_with_motion
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
alias_method :perform, :preproc_visit
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def run_preproc_mfile
|
|
22
|
+
images = @scan_labels ? @scan_labels.collect! { |label| Dir.glob("a*#{label}*.nii").to_s } : Dir.glob(File.join(@origdir, "a*#{@subid}*.nii"))
|
|
23
|
+
|
|
24
|
+
raise ScriptError, "Can't find any slice-time corrected images in #{@origdir}" if images.empty?
|
|
25
|
+
queue = MatlabQueue.new
|
|
26
|
+
queue.paths << ['/Applications/spm/spm8/spm8_current',
|
|
27
|
+
'/apps/spm/spm8_current',
|
|
28
|
+
File.join(@libdir, 'custom_methods'),
|
|
29
|
+
File.join(@libdir, 'matlab_helpers')
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
queue << "JohnsonTbiLongitudinalSnodPreproc('#{@procdir}/', \
|
|
33
|
+
{ #{images.collect {|im| "'#{File.basename(im)}'"}.join(' ')} }, \
|
|
34
|
+
{ #{@bold_reps.join(' ') } }, \
|
|
35
|
+
'JohnsonTbiLongitudinalSnodPreproc_job.m')"
|
|
36
|
+
|
|
37
|
+
puts queue.to_s
|
|
38
|
+
queue.run!
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
%-----------------------------------------------------------------------------
|
|
2
|
+
% Unfortunately, there is no easy way to pass in the number of images to this
|
|
3
|
+
% template job, short of writing a function to build one on the fly. Number of
|
|
4
|
+
% sessions is hardcoded.
|
|
5
|
+
nsessions = 6;
|
|
6
|
+
%-----------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
%-----------------------------------------------------------------------
|
|
9
|
+
% Job configuration created by cfg_util (rev $Rev: 3599 $)
|
|
10
|
+
%-----------------------------------------------------------------------
|
|
11
|
+
for i = 1:nsessions
|
|
12
|
+
matlabbatch{1}.spm.spatial.realign.estimate.data{i} = '<UNDEFINED>';
|
|
13
|
+
end
|
|
14
|
+
matlabbatch{1}.spm.spatial.realign.estimate.eoptions.quality = 0.9;
|
|
15
|
+
matlabbatch{1}.spm.spatial.realign.estimate.eoptions.sep = 4;
|
|
16
|
+
matlabbatch{1}.spm.spatial.realign.estimate.eoptions.fwhm = 5;
|
|
17
|
+
matlabbatch{1}.spm.spatial.realign.estimate.eoptions.rtm = 1;
|
|
18
|
+
matlabbatch{1}.spm.spatial.realign.estimate.eoptions.interp = 2;
|
|
19
|
+
matlabbatch{1}.spm.spatial.realign.estimate.eoptions.wrap = [0 0 0];
|
|
20
|
+
matlabbatch{1}.spm.spatial.realign.estimate.eoptions.weight = {''};
|
|
21
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1) = cfg_dep;
|
|
22
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1).tname = 'Source Image';
|
|
23
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1).tgt_spec{1}(1).name = 'filter';
|
|
24
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1).tgt_spec{1}(1).value = 'image';
|
|
25
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1).tgt_spec{1}(2).name = 'strtype';
|
|
26
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1).tgt_spec{1}(2).value = 'e';
|
|
27
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1).sname = 'Realign: Estimate: Realigned Images (Sess 1)';
|
|
28
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1).src_exbranch = substruct('.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1});
|
|
29
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.source(1).src_output = substruct('.','sess', '()',{1}, '.','cfiles');
|
|
30
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.wtsrc = '';
|
|
31
|
+
for i = 1:nsessions
|
|
32
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i) = cfg_dep;
|
|
33
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i).tname = 'Images to Write';
|
|
34
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i).tgt_spec{1}(1).name = 'filter';
|
|
35
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i).tgt_spec{1}(1).value = 'image';
|
|
36
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i).tgt_spec{1}(2).name = 'strtype';
|
|
37
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i).tgt_spec{1}(2).value = 'e';
|
|
38
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i).sname = ['Realign: Estimate: Realigned Images (Sess' i ')'];
|
|
39
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i).src_exbranch = substruct('.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1});
|
|
40
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.subj.resample(i).src_output = substruct('.','sess', '()',{i}, '.','cfiles');
|
|
41
|
+
end
|
|
42
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.eoptions.template = {[spm('Dir') '/templates/EPI.nii,1']};
|
|
43
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.eoptions.weight = '';
|
|
44
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.eoptions.smosrc = 8;
|
|
45
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.eoptions.smoref = 0;
|
|
46
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.eoptions.regtype = 'mni';
|
|
47
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.eoptions.cutoff = 25;
|
|
48
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.eoptions.nits = 16;
|
|
49
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.eoptions.reg = 1;
|
|
50
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.roptions.preserve = 0;
|
|
51
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.roptions.bb = [-78 -112 -50
|
|
52
|
+
78 76 85];
|
|
53
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.roptions.vox = [2 2 2];
|
|
54
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.roptions.interp = 1;
|
|
55
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.roptions.wrap = [0 0 0];
|
|
56
|
+
matlabbatch{2}.spm.spatial.normalise.estwrite.roptions.prefix = 'w';
|
|
57
|
+
matlabbatch{3}.spm.spatial.smooth.data(1) = cfg_dep;
|
|
58
|
+
matlabbatch{3}.spm.spatial.smooth.data(1).tname = 'Images to Smooth';
|
|
59
|
+
matlabbatch{3}.spm.spatial.smooth.data(1).tgt_spec{1}(1).name = 'filter';
|
|
60
|
+
matlabbatch{3}.spm.spatial.smooth.data(1).tgt_spec{1}(1).value = 'image';
|
|
61
|
+
matlabbatch{3}.spm.spatial.smooth.data(1).tgt_spec{1}(2).name = 'strtype';
|
|
62
|
+
matlabbatch{3}.spm.spatial.smooth.data(1).tgt_spec{1}(2).value = 'e';
|
|
63
|
+
matlabbatch{3}.spm.spatial.smooth.data(1).sname = 'Normalise: Estimate & Write: Normalised Images (Subj 1)';
|
|
64
|
+
matlabbatch{3}.spm.spatial.smooth.data(1).src_exbranch = substruct('.','val', '{}',{2}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1});
|
|
65
|
+
matlabbatch{3}.spm.spatial.smooth.data(1).src_output = substruct('()',{1}, '.','files');
|
|
66
|
+
matlabbatch{3}.spm.spatial.smooth.fwhm = [8 8 8];
|
|
67
|
+
matlabbatch{3}.spm.spatial.smooth.dtype = 0;
|
|
68
|
+
matlabbatch{3}.spm.spatial.smooth.im = 0;
|
|
69
|
+
matlabbatch{3}.spm.spatial.smooth.prefix = 's';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
function [] = JohnsonTbiLongitudinalSnodStats(statsdir, images, image_boldreps, conditions, regressors, job_mfile)
|
|
2
|
+
|
|
3
|
+
% List of open inputs
|
|
4
|
+
% fMRI model specification: Directory - cfg_entry
|
|
5
|
+
% 6 Scans Each with:
|
|
6
|
+
% fMRI model specification: Scans
|
|
7
|
+
% fMRI model specification: Multiple Conditions File - cfg_entry
|
|
8
|
+
% fMRI model specification: Multiple Regressors File - cfg_entry
|
|
9
|
+
|
|
10
|
+
spm('defaults', 'FMRI');
|
|
11
|
+
|
|
12
|
+
% statsdir = '/private/tmp/mrt00015_stats/'
|
|
13
|
+
% images = { 'swamrt00015_task1.nii' 'swamrt00015_task2.nii' }
|
|
14
|
+
% image_boldreps = {164 164}
|
|
15
|
+
% regressors = { 'mrt00015_faces3_recognitionA.mat' 'mrt00015_faces3_recognitionB.mat' }
|
|
16
|
+
% job_mfile = '/private/tmp/mrt00015_stats/Merit220Stats_job.m'
|
|
17
|
+
|
|
18
|
+
nrun = 1; % enter the number of runs here
|
|
19
|
+
% jobfile = {'/private/tmp/mrt00015_proc/Merit220_Stats_job.m'};
|
|
20
|
+
jobfile = {job_mfile};
|
|
21
|
+
jobs = repmat(jobfile, 1, nrun);
|
|
22
|
+
inputs = cell(length(images) + 1, nrun);
|
|
23
|
+
|
|
24
|
+
% Load the first conditions file to get the length of the names.
|
|
25
|
+
eval(['load ' conditions{1}]);
|
|
26
|
+
|
|
27
|
+
switch numel(names)
|
|
28
|
+
case 2 % New, Old
|
|
29
|
+
fcontrast_vector = [1 0
|
|
30
|
+
0 1];
|
|
31
|
+
tcontrast_1_vector = [-1 1];
|
|
32
|
+
tcontrast_2_vector = [1 -1];
|
|
33
|
+
% case 4 % New_correct, New_incorrect, Old_correct, Old_incorrect
|
|
34
|
+
% fcontrast_vector = [1 0 0 0
|
|
35
|
+
% 0 1 0 0
|
|
36
|
+
% 0 0 1 0
|
|
37
|
+
% 0 0 0 1 ];
|
|
38
|
+
% tcontrast_1_vector = [-1 0 1 0];
|
|
39
|
+
% tcontrast_2_vector = [ 1 0 -1 0];
|
|
40
|
+
% case 5 % New_correct, New_incorrect, Old_correct, Old_incorrect, Misses
|
|
41
|
+
% fcontrast_vector = [1 0 0 0
|
|
42
|
+
% 0 1 0 0
|
|
43
|
+
% 0 0 1 0
|
|
44
|
+
% 0 0 0 1 ];
|
|
45
|
+
% tcontrast_1_vector = [-1 0 1 0];
|
|
46
|
+
% tcontrast_2_vector = [ 1 0 -1 0];
|
|
47
|
+
otherwise
|
|
48
|
+
error('Incorrect number of conditions detected: %d', numel(conditions));
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
for crun = 1:nrun
|
|
52
|
+
inputs{1, crun} = { statsdir }; % fMRI model specification: Directory - cfg_entry
|
|
53
|
+
|
|
54
|
+
% fMRI model specification: Directory - cfg_entry
|
|
55
|
+
for index = 1:length(images)
|
|
56
|
+
offset = (index - 1) .* 3;
|
|
57
|
+
inputs{offset + 2, crun} = CreateFunctionalVolumeStruct(statsdir, images{index}, image_boldreps{index}); % fMRI model specification: Scans - cfg_entry
|
|
58
|
+
inputs{offset + 3, crun} = { strcat(statsdir, conditions{index} ) }; % fMRI model specification: Multiple Conditions File - cfg_entry
|
|
59
|
+
inputs{offset + 4, crun} = { strcat(statsdir, regressors{index} ) }; % fMRI model specification: Multiple Regressors File - cfg_entry
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
image_offset = (length(images) .* 3) + 1;
|
|
63
|
+
inputs{image_offset + 1, crun} = 'Omnibus F'; % fMRI model specification: Omnibus Title - cfg_entry
|
|
64
|
+
inputs{image_offset + 2, crun} = fcontrast_vector; % fMRI model specification: Omnibus Contrast - cfg_entry
|
|
65
|
+
|
|
66
|
+
inputs{image_offset + 3, crun} = 'NV > PV'; % fMRI model specification: T Contrast 1 Title - cfg_entry
|
|
67
|
+
inputs{image_offset + 4, crun} = tcontrast_1_vector; % fMRI model specification: T Contrast 1 Vector - cfg_entry
|
|
68
|
+
|
|
69
|
+
inputs{image_offset + 5, crun} = 'PV > NV'; % fMRI model specification: T Contrast 2 Title - cfg_entry
|
|
70
|
+
inputs{image_offset + 6, crun} = tcontrast_2_vector; % fMRI model specification: T Contrast 2 Vector - cfg_entry
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
spm_jobman('serial', jobs, '', inputs{:});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# require 'logfile'
|
|
2
|
+
module JohnsonTbiLongitudinalSnodStats
|
|
3
|
+
|
|
4
|
+
DEFAULT_CONDITIONS = [:new, :old]
|
|
5
|
+
|
|
6
|
+
# runs the complete set of tasks using data in a subject's "proc" directory and a preconfigured template spm job.
|
|
7
|
+
def run_first_level_stats
|
|
8
|
+
flash "Highway to the dangerzone..."
|
|
9
|
+
setup_directory(@statsdir, "STATS")
|
|
10
|
+
|
|
11
|
+
Dir.chdir(@statsdir) do
|
|
12
|
+
link_files_from_proc_directory(File.join(@procdir, "sw*.nii"), File.join(@procdir, "rp*.txt"))
|
|
13
|
+
setup_onsets
|
|
14
|
+
run_stats_spm_job
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias_method :perform, :run_first_level_stats
|
|
19
|
+
|
|
20
|
+
def setup_onsets
|
|
21
|
+
setup_conditions
|
|
22
|
+
create_or_link_onsets_files
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def setup_conditions
|
|
26
|
+
@conditions = @conditions ? @conditions.collect {|c| c.to_sym if c.respond_to? :to_sym } : DEFAULT_CONDITIONS
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def create_or_link_onsets_files
|
|
30
|
+
if @onsetsfiles.nil?
|
|
31
|
+
if @responses.nil?
|
|
32
|
+
raise ScriptError, "Condition vectors cannot be created because neither log response files nor onsets mat files have been specified."
|
|
33
|
+
else
|
|
34
|
+
@onsetsfiles = create_onsets_files(@responses, conditions)
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
link_onsets_files
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Finally runs the stats job
|
|
42
|
+
def run_stats_spm_job
|
|
43
|
+
images = @scan_labels ? @scan_labels.collect! { |label| Dir.glob("sw*#{label}*.nii").to_s } : Dir.glob(File.join(@origdir, "sw*#{@subid}*.nii"))
|
|
44
|
+
raise ScriptError, "Can't find any smoothed, warped images in #{@statsdir}" if images.empty?
|
|
45
|
+
unless @onsetsfiles.length == @regressorsfiles.length && @regressorsfiles.length == @bold_reps.length
|
|
46
|
+
raise ScriptError, "Mismatch between #{@bold_reps.length} reps, #{@onsetsfiles.length} onsets and #{@regressorsfiles.length} regressors files."
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
queue = MatlabQueue.new
|
|
50
|
+
queue.paths << [
|
|
51
|
+
'/Applications/spm/spm8/spm8_current',
|
|
52
|
+
'/apps/spm/spm8_current',
|
|
53
|
+
File.join(@libdir, 'custom_methods'),
|
|
54
|
+
File.join(@libdir, 'matlab_helpers') ]
|
|
55
|
+
|
|
56
|
+
queue << "JohnsonTbiLongitudinalSnodStats('#{@statsdir}/', \
|
|
57
|
+
{ #{images.collect {|im| "'#{File.basename(im)}'"}.join(' ')} }, \
|
|
58
|
+
{ #{@bold_reps.join(' ') } }, \
|
|
59
|
+
{ #{@onsetsfiles.collect { |file| "'#{File.basename(file)}'"}.join(' ') } }, \
|
|
60
|
+
{ #{@regressorsfiles.collect { |file| "'#{File.basename(file)}'"}.join(' ') } }, \
|
|
61
|
+
'JohnsonTbiLongitudinalSnodStats_job.m')"
|
|
62
|
+
|
|
63
|
+
# puts queue.to_s
|
|
64
|
+
queue.run!
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
%-----------------------------------------------------------------------
|
|
2
|
+
% Job configuration created by cfg_util (rev $Rev: 3599 $)
|
|
3
|
+
%-----------------------------------------------------------------------
|
|
4
|
+
%% Specification
|
|
5
|
+
matlabbatch{1}.spm.stats.fmri_spec.dir = '<UNDEFINED>';
|
|
6
|
+
matlabbatch{1}.spm.stats.fmri_spec.timing.units = 'scans';
|
|
7
|
+
matlabbatch{1}.spm.stats.fmri_spec.timing.RT = 2;
|
|
8
|
+
matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t = 16;
|
|
9
|
+
matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t0 = 1;
|
|
10
|
+
for i = 1:2
|
|
11
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(i).scans = '<UNDEFINED>';
|
|
12
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(i).cond = struct('name', {}, 'onset', {}, 'duration', {}, 'tmod', {}, 'pmod', {});
|
|
13
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(i).multi = '<UNDEFINED>';
|
|
14
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(i).regress = struct('name', {}, 'val', {});
|
|
15
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(i).multi_reg = '<UNDEFINED>';
|
|
16
|
+
matlabbatch{1}.spm.stats.fmri_spec.sess(i).hpf = 128;
|
|
17
|
+
end
|
|
18
|
+
matlabbatch{1}.spm.stats.fmri_spec.fact = struct('name', {}, 'levels', {});
|
|
19
|
+
matlabbatch{1}.spm.stats.fmri_spec.bases.hrf.derivs = [0 0];
|
|
20
|
+
matlabbatch{1}.spm.stats.fmri_spec.volt = 1;
|
|
21
|
+
matlabbatch{1}.spm.stats.fmri_spec.global = 'None';
|
|
22
|
+
matlabbatch{1}.spm.stats.fmri_spec.mask = {''};
|
|
23
|
+
matlabbatch{1}.spm.stats.fmri_spec.cvi = 'AR(1)';
|
|
24
|
+
%% Estimation
|
|
25
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1) = cfg_dep;
|
|
26
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tname = 'Select SPM.mat';
|
|
27
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tgt_spec{1}(1).name = 'filter';
|
|
28
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tgt_spec{1}(1).value = 'mat';
|
|
29
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tgt_spec{1}(2).name = 'strtype';
|
|
30
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).tgt_spec{1}(2).value = 'e';
|
|
31
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).sname = 'fMRI model specification: SPM.mat File';
|
|
32
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).src_exbranch = substruct('.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1});
|
|
33
|
+
matlabbatch{2}.spm.stats.fmri_est.spmmat(1).src_output = substruct('.','spmmat');
|
|
34
|
+
matlabbatch{2}.spm.stats.fmri_est.method.Classical = 1;
|
|
35
|
+
%% Contrast Creation
|
|
36
|
+
matlabbatch{3}.spm.stats.con.spmmat(1) = cfg_dep;
|
|
37
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tname = 'Select SPM.mat';
|
|
38
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tgt_spec{1}(1).name = 'filter';
|
|
39
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tgt_spec{1}(1).value = 'mat';
|
|
40
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tgt_spec{1}(2).name = 'strtype';
|
|
41
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).tgt_spec{1}(2).value = 'e';
|
|
42
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).sname = 'Model estimation: SPM.mat File';
|
|
43
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).src_exbranch = substruct('.','val', '{}',{2}, '.','val', '{}',{1}, '.','val', '{}',{1});
|
|
44
|
+
matlabbatch{3}.spm.stats.con.spmmat(1).src_output = substruct('.','spmmat');
|
|
45
|
+
matlabbatch{3}.spm.stats.con.consess{1}.fcon.name = '<UNDEFINED>';
|
|
46
|
+
matlabbatch{3}.spm.stats.con.consess{1}.fcon.convec{1} = '<UNDEFINED>';
|
|
47
|
+
matlabbatch{3}.spm.stats.con.consess{1}.fcon.sessrep = 'repl';
|
|
48
|
+
matlabbatch{3}.spm.stats.con.consess{2}.tcon.name = '<UNDEFINED>';
|
|
49
|
+
matlabbatch{3}.spm.stats.con.consess{2}.tcon.convec = '<UNDEFINED>';
|
|
50
|
+
matlabbatch{3}.spm.stats.con.consess{2}.tcon.sessrep = 'repl';
|
|
51
|
+
matlabbatch{3}.spm.stats.con.consess{3}.tcon.name = '<UNDEFINED>';
|
|
52
|
+
matlabbatch{3}.spm.stats.con.consess{3}.tcon.convec = '<UNDEFINED>';
|
|
53
|
+
matlabbatch{3}.spm.stats.con.consess{3}.tcon.sessrep = 'repl';
|
|
54
|
+
matlabbatch{3}.spm.stats.con.delete = 0;
|
|
55
|
+
|
|
56
|
+
% NOTE! F-contrasts expect cells containing contrast arrays, while
|
|
57
|
+
% T-contrasts expect the arrays themslves (hence the cell reference in
|
|
58
|
+
% F-contrast definition (convec{1} = [];) but not in T-contrast definition
|
|
59
|
+
% (convec = [];)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'log4r'
|
|
2
|
+
|
|
3
|
+
# Setup Command and General Logs to point to STDOUT if not defined.
|
|
4
|
+
module DefaultLogger
|
|
5
|
+
def setup_logger
|
|
6
|
+
%w{$Log $CommandLog}.each do |log|
|
|
7
|
+
unless eval(log)
|
|
8
|
+
eval("#{log} = Log4r::Logger.new('output')")
|
|
9
|
+
eval("#{log}.add Log4r::StdoutOutputter.new(:stdout)")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module DefaultPreproc
|
|
2
|
+
|
|
3
|
+
# Runs the preprocessing job, including spm job customization, run spm job, and handling motion issues.
|
|
4
|
+
# This function assumes a destination directory is set up; it will overwrite preexisting data. Careful!
|
|
5
|
+
def preproc_visit
|
|
6
|
+
$Log.info "Spatial Preprocessing Subject: #{@subid}"
|
|
7
|
+
|
|
8
|
+
setup_directory(@procdir, "PREPROC")
|
|
9
|
+
|
|
10
|
+
Dir.chdir(@procdir) do
|
|
11
|
+
link_files_into_proc
|
|
12
|
+
customize_templates
|
|
13
|
+
run_spm_jobs
|
|
14
|
+
deal_with_motion
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias_method :perform, :preproc_visit
|
|
19
|
+
|
|
20
|
+
# Links all the slice timing corrected data from the source "orig" directory using a wildcard a${subid}*.nii,
|
|
21
|
+
# where subid is the subject id specified in the preproc_spec hash.
|
|
22
|
+
def link_files_into_proc
|
|
23
|
+
flash "Linking files from #{@origdir} into #{@procdir}"
|
|
24
|
+
wildcard = File.join(@origdir,"a*#{@subid}*.nii")
|
|
25
|
+
files = Dir.glob(wildcard)
|
|
26
|
+
unless files.empty?
|
|
27
|
+
system("ln -s #{wildcard} #{@procdir}")
|
|
28
|
+
else
|
|
29
|
+
raise(IOError, "No files matching #{wildcard} found.")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def check_permissions(files)
|
|
34
|
+
unwritable = []
|
|
35
|
+
files.collect { |file| unwritable << file unless File.writable?(file) }
|
|
36
|
+
raise IOError, "Cannot write to #{unwritable.join(", ")} files." unless unwritable.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Customizes the template job in preproc_spec to be specific for this particular preproc job.
|
|
40
|
+
# Performs to recursive string replacements inside the spm job:
|
|
41
|
+
# - path inside template is replaced with destination "proc" directory
|
|
42
|
+
# - subid inside template is replaced with the current subid
|
|
43
|
+
def customize_templates
|
|
44
|
+
flash "Customizing template SPM job: #{@tspec['job']}"
|
|
45
|
+
replacecmd = "spmjobStringReplace.sh"
|
|
46
|
+
|
|
47
|
+
templatejob = File.join(@spmdir, @tspec['job'])
|
|
48
|
+
thisjob = @subid + '_preproc.mat'
|
|
49
|
+
|
|
50
|
+
File.copy(templatejob, thisjob)
|
|
51
|
+
system("#{replacecmd} #{thisjob} #{@tspec['path']} #{@procdir} #{thisjob}")
|
|
52
|
+
system("#{replacecmd} #{thisjob} #{@tspec['subid']} #{@subid} #{thisjob}")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Runs the customized spm job using the shell script runSpmJob.sh. Make sure this is available at your site.
|
|
56
|
+
def run_spm_jobs
|
|
57
|
+
thisjob = "#{@subid}_preproc.mat"
|
|
58
|
+
flash "Running spatial preprocessing SPM job: #{thisjob}"
|
|
59
|
+
system("runSpmJob.sh #{thisjob}")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Calculates the realignment motion derivatives and checks that displacement
|
|
63
|
+
# in all directions was less than the MOTION_THRESHOLD. Operates on all files
|
|
64
|
+
# in the current working directory that match rp_a*txt (SPM convention). Uses
|
|
65
|
+
# two shell scripts that must both be available on the local machine:
|
|
66
|
+
# - calc_derivs.sh
|
|
67
|
+
# - fmri_motion_check.sh
|
|
68
|
+
def deal_with_motion
|
|
69
|
+
flash "Calculating motion derivatives and checking for excessive motion"
|
|
70
|
+
Dir.glob("rp_a*txt").each do |rp|
|
|
71
|
+
run("calc_derivs.sh #{rp}")
|
|
72
|
+
run("fmri_motion_check.sh #{rp} #{@motion_threshold}")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'physionoise/lib')
|
|
2
|
+
|
|
3
|
+
require 'metamri/core_additions'
|
|
4
|
+
require 'physionoise'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
require 'default_methods/recon/physionoise_helper'
|
|
7
|
+
require 'default_methods/recon/raw_sequence'
|
|
8
|
+
|
|
9
|
+
module DefaultRecon
|
|
10
|
+
|
|
11
|
+
# Reconstructs, strips, and slice timing corrects all scans specified in the recon_spec.
|
|
12
|
+
# This function assumes a destination directory is set up in the filesystem and begins writing
|
|
13
|
+
# to it with no further checking. It will overwrite data if it already exists, be careful.
|
|
14
|
+
def recon_visit
|
|
15
|
+
|
|
16
|
+
setup_directory(@origdir, "RECON")
|
|
17
|
+
|
|
18
|
+
Dir.chdir(@origdir) do
|
|
19
|
+
@scans.each_with_index do |scan_spec, i|
|
|
20
|
+
outfile = "%s_%s.nii" % [@subid, scan_spec['label']]
|
|
21
|
+
|
|
22
|
+
reconstruct_scan(scan_spec, outfile)
|
|
23
|
+
|
|
24
|
+
if scan_spec['type'] == "func"
|
|
25
|
+
# if scan_spec['physio_files']
|
|
26
|
+
# create_physiosnoise_regressors(scan_spec)
|
|
27
|
+
# outfile = run_retroicor(scan_spec['physio_files'], outfile)
|
|
28
|
+
# end
|
|
29
|
+
|
|
30
|
+
slice_time_correct(outfile)
|
|
31
|
+
else
|
|
32
|
+
File.copy('tmp.nii', outfile)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
File.delete('tmp.nii') if File.exist? 'tmp.nii'
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
alias_method :perform, :recon_visit
|
|
41
|
+
|
|
42
|
+
# Reconstructs a scan from dicoms or pfile to nifti, anatomical or functional.
|
|
43
|
+
# Uses a scan_spec hash to drive. Writes the result in current working
|
|
44
|
+
# directory. Raises an error if to3d system call fails. Conventions: I****.dcm
|
|
45
|
+
# filenaming, I0002.dcm is second file in series,
|
|
46
|
+
def reconstruct_scan(scan_spec, outfile)
|
|
47
|
+
if scan_spec['dir']
|
|
48
|
+
sequence = DicomRawSequence.new(scan_spec, @rawdir)
|
|
49
|
+
sequence.prepare('tmp.nii')
|
|
50
|
+
strip_leading_volumes('tmp.nii', outfile, @volume_skip, scan_spec['bold_reps'])
|
|
51
|
+
elsif scan_spec['pfile']
|
|
52
|
+
sequence = PfileRawSequence.new(scan_spec, @rawdir)
|
|
53
|
+
sequence.prepare(outfile)
|
|
54
|
+
else
|
|
55
|
+
raise ConfigError, "Scan must list either a pfile or a dicom directory."
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Removes the specified number of volumes from the beginning of a 4D functional nifti file.
|
|
60
|
+
# In most cases this will be 3 volumes. Writes result in current working directory.
|
|
61
|
+
def strip_leading_volumes(infile, outfile, volume_skip, bold_reps)
|
|
62
|
+
$Log.info "Stripping #{volume_skip.to_s} leading volumes: #{infile}"
|
|
63
|
+
cmd_fmt = "fslroi %s %s %s %s"
|
|
64
|
+
cmd_options = [infile, outfile, volume_skip.to_s, bold_reps.to_s]
|
|
65
|
+
cmd = cmd_fmt % cmd_options
|
|
66
|
+
unless run(cmd)
|
|
67
|
+
raise ScriptError, "Failed to strip volumes: #{cmd}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Uses to3d to slice time correct a 4D functional nifti file. Writes result in the current working directory.
|
|
72
|
+
def slice_time_correct(infile)
|
|
73
|
+
$Log.info "Slice Timing Correction: #{infile}"
|
|
74
|
+
cmd = "3dTshift -tzero 0 -tpattern alt+z -prefix a#{infile} #{infile}"
|
|
75
|
+
unless run(cmd)
|
|
76
|
+
raise ScriptError, "Failed to slice time correct: #{cmd}"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|