oceanproc 1.3.1__tar.gz → 1.3.3__tar.gz

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.
Files changed (21) hide show
  1. {oceanproc-1.3.1 → oceanproc-1.3.3}/PKG-INFO +1 -1
  2. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/ocean_proc.py +7 -5
  3. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/preprocessing_wrapper.py +50 -37
  4. {oceanproc-1.3.1 → oceanproc-1.3.3}/pyproject.toml +1 -1
  5. {oceanproc-1.3.1 → oceanproc-1.3.3}/README.md +0 -0
  6. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/__init__.py +0 -0
  7. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/bids_wrapper.py +0 -0
  8. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/events_long.py +0 -0
  9. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/firstlevel/__init__.py +0 -0
  10. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/firstlevel/run_glm.py +0 -0
  11. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/firstlevel/tests/__init__.py +0 -0
  12. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/firstlevel/tests/test_run_glm.py +0 -0
  13. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/group_series.py +0 -0
  14. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/grouplevel/__init__.py +0 -0
  15. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/grouplevel/computations.py +0 -0
  16. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/grouplevel/design_mat_utils.py +0 -0
  17. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/grouplevel/dscalar_utils.py +0 -0
  18. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/grouplevel/utils.py +0 -0
  19. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/oceanparse.py +0 -0
  20. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/segmentation_wrapper.py +0 -0
  21. {oceanproc-1.3.1 → oceanproc-1.3.3}/oceanproc/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: oceanproc
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: MRI preprocessing for WUSTL Ocean labs
5
5
  Author-Email: Ramone Agard <rhagard@wustl.edu>, Joey Scanga <joeyscanga92@gmail.com>
6
6
  Requires-Python: <3.13,>=3.10
@@ -103,7 +103,7 @@ def main():
103
103
  epilog="An arguments file can be accepted with @FILEPATH.\nAny additional arguments not listed in the help message will be passed to the preprocessing subprocess.",
104
104
  allow_abbrev=False
105
105
  )
106
- parser.add_argument("--version", action="version", version='%(prog)s v1.3.1')
106
+ parser.add_argument("--version", action="version", version='%(prog)s v1.3.3')
107
107
  session_args = parser.add_argument_group("Session Specific")
108
108
  config_args = parser.add_argument_group("Configuration Arguments", "These arguments are saved to a file if the '--export_args' option is used")
109
109
 
@@ -157,11 +157,13 @@ def main():
157
157
  help="framewise displacement threshold (in mm) to determine outlier framee (Default is 0.9).")
158
158
  config_args.add_argument("--skip_bids_validation", action=argparse.BooleanOptionalAction,
159
159
  help="Specifies skipping BIDS validation (only enabled for fMRIprep step)")
160
- config_args.add_argument("--fs_subjects_dir", "-fs", type=ExistingDir,
160
+ config_args.add_argument("--fs_subjects_dir", "--fs-subjects-dir", "-fs", type=ExistingDir, dest="fs_subjects_dir",
161
161
  help="The path to the directory that contains previous FreeSurfer outputs/derivatives to use for fMRIPrep. If empty, this is the path where new FreeSurfer outputs will be stored.")
162
+ config_args.add_argument("--topup_config", "--topup-config", "-tc", type=ExistingFile, dest="topup_config",
163
+ help="Path to a TOPUP config file.")
162
164
  config_args.add_argument("--allow_uneven_fmap_groups", action="store_true",
163
165
  help="Flag to allow for automated fieldmap pairing when there's more AP- than PA-encoded fieldmaps, or vice versa (will still error out if at least one of each is not present.)")
164
- config_args.add_argument("--extract_best_fmap", action="store_true",
166
+ config_args.add_argument("--extract_best_fmap", action=argparse.BooleanOptionalAction,
165
167
  help="Flag to specify that the lowest variance fieldmap volume should be extracted from each fieldmap, and used for distortion correction (opposed to all volumes being used)")
166
168
  config_args.add_argument("--dscans_path", type=ExistingDir,
167
169
  help="""The path to the directory containing 'dscans' files for inserting dummy scans into bold runs. Must be named exactly as corresponding bold image except with 'dscans' as
@@ -170,7 +172,7 @@ def main():
170
172
  help="A list of paths to any BIDS-style precomputed derivatives that should be used in preprocessing. (Ex. /path/to/bibsnet)")
171
173
  config_args.add_argument("--work_dir", "-w", type=ExistingDir, required=True,
172
174
  help="The path to the working directory used to store intermediate files")
173
- config_args.add_argument("--fs_license", "-l", type=ExistingFile, required=True,
175
+ config_args.add_argument("--fs_license", "--fs-license-file", "-l", type=ExistingFile, dest="fs_license", required=True,
174
176
  help="The path to the license file for the local installation of FreeSurfer")
175
177
  config_args.add_argument("--image_version", "-iv", default=None,
176
178
  help=f"""The version of fmriprep to use; It is reccomended that an entire study use the same version.
@@ -296,7 +298,7 @@ def main():
296
298
  ignore_list = ["tmp_dcm2bids"]
297
299
  if (bids_path / ".bidsignore").is_file():
298
300
  with open(bids_path / ".bidsignore", "r") as f:
299
- ignore_list.extend(f.readlines())
301
+ ignore_list.extend([l.strip() for l in f.readlines()])
300
302
  ignore_list = list(set(ignore_list))
301
303
  other_sub_paths = [
302
304
  p.name for p in bids_path.glob("sub-*")
@@ -13,6 +13,7 @@ import nibabel as nib
13
13
  import json
14
14
  import os
15
15
  import copy
16
+ import subprocess
16
17
  from types import SimpleNamespace
17
18
 
18
19
  logger = logging.getLogger(__name__)
@@ -31,8 +32,12 @@ infant_defaults = SimpleNamespace(
31
32
  )
32
33
 
33
34
  # Preprocessing arguments that need to have their paths binded when running docker
34
- mount_opts = {"fs_subjects_dir",
35
- "derivatives"}
35
+ mount_opts = {
36
+ "fs_subjects_dir",
37
+ "derivatives",
38
+ "topup_config"
39
+ }
40
+
36
41
 
37
42
  @debug_logging
38
43
  def run_preprocessing(subject:str,
@@ -68,7 +73,7 @@ def run_preprocessing(subject:str,
68
73
  :raise RuntimeError: If preprocessing throws an error, or exits with a non-zero exit code.
69
74
  """
70
75
  def clean_up(): return shutil.rmtree(work_path) if remove_work_folder else None
71
-
76
+
72
77
  log_linebreak()
73
78
  logger.info(f"####### Starting {title} #######\n")
74
79
  if not bids_path.exists():
@@ -80,12 +85,19 @@ def run_preprocessing(subject:str,
80
85
  bids_mount = "/data"
81
86
  derivs_mount = "/out"
82
87
  work_mount = "/work"
83
-
88
+
84
89
  if flags.apptainer:
85
90
  cmd_prelude = f"apptainer run --nv --cleanenv --no-mount cwd --pwd {work_mount}"
86
91
  mount_flag = "-B"
87
- else:
92
+ else:
88
93
  cmd_prelude = f"docker run --rm -i -u {flags.uid}:{flags.gid}"
94
+ import grp
95
+ mygids = (
96
+ grp.getgrnam(groupname).gr_gid for groupname in
97
+ subprocess.run('groups', capture_output=True).stdout.decode().strip().split()
98
+ )
99
+ for mygid in mygids:
100
+ cmd_prelude += f" --group-add {mygid} "
89
101
  mount_flag = "-v"
90
102
 
91
103
  additional_mount_paths = []
@@ -118,7 +130,7 @@ def run_preprocessing(subject:str,
118
130
  -w {work_mount} --verbose
119
131
  {additional_mount_args}
120
132
  {option_chain}"""
121
-
133
+
122
134
  success = True
123
135
  try:
124
136
  run_subprocess(preproc_command, title=title)
@@ -132,6 +144,7 @@ def run_preprocessing(subject:str,
132
144
 
133
145
  return success
134
146
 
147
+
135
148
  @debug_logging
136
149
  def add_fd_plot_to_report(subject:str,
137
150
  session:str,
@@ -222,7 +235,7 @@ def add_fd_plot_to_report(subject:str,
222
235
  # Add the new elements into the file
223
236
  logger.debug(f" inserting the new html elements into the {title} report")
224
237
  confounds_plot_div.insert_after(fd_plot_div)
225
- else:
238
+ else:
226
239
  confounds_plot_reference_div = confounds_plot_div.find_next_sibling("div", class_="elem-filename")
227
240
  fd_plot_reference_div = copy.copy(confounds_plot_reference_div)
228
241
  fd_plot_reference_div.a["href"] = "./" + rel_path
@@ -244,9 +257,9 @@ def insert_dummy_frames(subject:str,
244
257
  session:str,
245
258
  dscan_dir:Path,
246
259
  bids_layout:BIDSLayout):
247
-
260
+
248
261
  dscans_suffix = "dscans"
249
- dscans_path_pattern = "sub-{subject}[/ses-{session}]/{datatype<func|meg|beh>|func}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix<"+dscans_suffix+">}{extension<.tsv|.json>|.tsv}"
262
+ dscans_path_pattern = "sub-{subject}[/ses-{session}]/{datatype<func|meg|beh>|func}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix<" + dscans_suffix + ">}{extension<.tsv|.json>|.tsv}"
250
263
 
251
264
  log_linebreak()
252
265
  logger.info(f"####### Inserting Dummy Scans #######\n")
@@ -298,27 +311,27 @@ def insert_dummy_frames(subject:str,
298
311
  frame_list = []
299
312
  dscans_index = 0
300
313
  for f in range(num_bold_frames):
301
- copy_dex = f-1 if f > 0 else f
314
+ copy_dex = f - 1 if f > 0 else f
302
315
  while dscans_list[dscans_index] != 0:
303
316
  frame_list.append(bold_data[:,:,:,copy_dex])
304
317
  dscans_index += 1
305
318
  frame_list.append(bold_data[:,:,:,f])
306
319
  dscans_index += 1
307
320
  # check if end of run needs to be extended
308
- if (f == num_bold_frames-1) and (dscans_index < len(dscans_list)):
321
+ if (f == num_bold_frames - 1) and (dscans_index < len(dscans_list)):
309
322
  while dscans_index < len(dscans_list):
310
323
  frame_list.append(bold_data[:,:,:,f])
311
324
  dscans_index += 1
312
325
 
313
326
  if len(frame_list) != len(dscans_list):
314
327
  exit_program_early(f"Something went wrong when creating dummy scans, lengths do not match. bold frames: {len(frame_list)}, dscan length: {len(dscans_list)}")
315
-
328
+
316
329
  # save new image
317
330
  extended_bold_data = np.stack(frame_list, axis=3)
318
331
  extended_bold_img = bold_img.__class__(extended_bold_data, header=bold_img.header, affine=bold_img.affine)
319
332
  logger.info(f" saving extended bold image")
320
333
  nib.save(extended_bold_img, bfile.path)
321
-
334
+
322
335
 
323
336
  @debug_logging
324
337
  def process_data(subject:str,
@@ -356,23 +369,23 @@ def process_data(subject:str,
356
369
  preproc_title = "NiBabies" if flags.infant else "fMRIPrep"
357
370
 
358
371
  preproc_success = run_preprocessing(subject=subject,
359
- session=session if flags.infant else None,
360
- bids_path=bids_path,
361
- derivs_path=derivs_path,
362
- work_path=work_path,
363
- license_file=license_file,
364
- image_name=image_name,
365
- title=preproc_title,
366
- option_chain=option_chain,
367
- additional_mounts=additional_mounts,
368
- remove_work_folder=remove_work_folder)
369
-
372
+ session=session if flags.infant else None,
373
+ bids_path=bids_path,
374
+ derivs_path=derivs_path,
375
+ work_path=work_path,
376
+ license_file=license_file,
377
+ image_name=image_name,
378
+ title=preproc_title,
379
+ option_chain=option_chain,
380
+ additional_mounts=additional_mounts,
381
+ remove_work_folder=remove_work_folder)
382
+
370
383
  if preproc_success:
371
384
  add_fd_plot_to_report(subject=subject,
372
- session=session,
373
- derivs_path=derivs_path,
374
- title=preproc_title)
375
-
385
+ session=session,
386
+ derivs_path=derivs_path,
387
+ title=preproc_title)
388
+
376
389
  paths_to_update = []
377
390
  paths_to_update.extend(sorted(derivs_path.glob(f"sub-{subject}*")))
378
391
  paths_to_update.extend(sorted(derivs_path.glob(f"sourcedata/*/sub-{subject}*")))
@@ -380,14 +393,14 @@ def process_data(subject:str,
380
393
  if out_path.exists():
381
394
  # update file permissions for preprocessing outputs
382
395
  update_permissions(
383
- permissions=flags.file_permissions,
384
- path=out_path,
396
+ permissions=flags.file_permissions,
397
+ path=out_path,
385
398
  recursive=True,
386
399
  group=flags.permissions_group
387
400
  )
388
-
401
+
389
402
  # check other top-level files
390
- other_paths = [derivs_path/"dataset_description.json", derivs_path/"logs"]
403
+ other_paths = [derivs_path / "dataset_description.json", derivs_path / "logs"]
391
404
  for op in other_paths:
392
405
  if op.exists() and (op.stat().st_uid == flags.uid):
393
406
  update_permissions(
@@ -396,15 +409,15 @@ def process_data(subject:str,
396
409
  recursive=True,
397
410
  group=flags.permissions_group
398
411
  )
399
-
412
+
400
413
  # update file permisions for working directory files
401
414
  update_permissions(
402
- permissions=flags.file_permissions,
403
- path=work_path,
415
+ permissions=flags.file_permissions,
416
+ path=work_path,
404
417
  recursive=True,
405
418
  group=flags.permissions_group,
406
419
  quiet=True
407
420
  )
408
-
421
+
409
422
  if not preproc_success:
410
- exit_program_early(f"Program '{preproc_title}' has run into an error.")
423
+ exit_program_early(f"Program '{preproc_title}' has run into an error.")
@@ -34,7 +34,7 @@ dependencies = [
34
34
  "pybids>=0.16.3",
35
35
  ]
36
36
  name = "oceanproc"
37
- version = "1.3.1"
37
+ version = "1.3.3"
38
38
  description = "MRI preprocessing for WUSTL Ocean labs"
39
39
  readme = "README.md"
40
40
 
File without changes
File without changes