Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into medic-whole
Browse files Browse the repository at this point in the history
  • Loading branch information
tsalo committed Jun 27, 2024
2 parents 63aa532 + bb89bdc commit 5f84bd2
Show file tree
Hide file tree
Showing 10 changed files with 398 additions and 102 deletions.
12 changes: 6 additions & 6 deletions .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
"name": "Eilidh MacNicol",
"type": "Researcher"
},
{
"orcid": "0000-0002-8888-1572",
"affiliation": "Speech & Hearing Bioscience & Technology Program, Harvard University",
"name": "Steven Meisler",
"type": "Researcher"
},
{
"orcid": "0000-0001-9049-0135",
"affiliation": "Perelman School of Medicine, University of Pennsylvania, PA, USA",
Expand All @@ -49,12 +55,6 @@
"name": "Kevin R. Sitek",
"type": "Researcher"
},
{
"orcid": "0000-0002-8888-1572",
"affiliation": "Speech & Hearing Bioscience & Technology Program, Harvard University",
"name": "Steven L. Meisler",
"type": "Researcher"
},
{
"orcid": "0000-0001-7644-7915",
"affiliation": "Center for Lifespan Changes in Brain and Cognition, University of Oslo",
Expand Down
18 changes: 18 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
2.9.0 (June 13, 2024)
=====================
Feature release in the 2.9.x series.

The main change is that B0FieldIdentifiers with special characters
are now sanitized and exposed through a ``FieldmapEstimator.sanitized_id``
attribute.

Workflow names and input/output connections will use ``sanitized_id``,
to ensure compatibility with filenames and workflow graph generation.
Internal lookup tables will continue to use the the unsanitized ``bids_id``.

* FIX: Update suffix only when finding related fieldmap files (#436)
* FIX: Remove unused ANTs parameter that was removed in 2.4.1 (#431)
* RF: Add sanitized_id field to FieldmapEstimation (#444)
* DOC: Un-mock the already-imported numpy (#440)
* CI: Bump actions/cache from 3 to 4 (#429)

2.8.1 (January 22, 2024)
========================
Bug-fix release in the 2.8.x series.
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ RUN python -m build /src
#

# Utilities for downloading packages
FROM ${BASE_IMAGE} as downloader
FROM --platform=linux/amd64 ${BASE_IMAGE} as downloader

# Bump the date to current to refresh curl/certificates/etc
RUN echo "2023.11.09"
Expand Down Expand Up @@ -100,7 +100,7 @@ RUN /opt/conda/envs/sdcflows/bin/pip install --no-cache-dir -r /tmp/requirements
#
# Main stage
#
FROM ${BASE_IMAGE} as sdcflows
FROM --platform=linux/amd64 ${BASE_IMAGE} as sdcflows

# Configure apt
ENV DEBIAN_FRONTEND="noninteractive" \
Expand Down
1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"nilearn",
"nipy",
"nitime",
"numpy",
"pandas",
"seaborn",
"skimage",
Expand Down
412 changes: 327 additions & 85 deletions docs/notebooks/SDC - Theory and physics.ipynb

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion sdcflows/fieldmaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ class FieldmapEstimation:
bids_id = attr.ib(default=None, kw_only=True, type=str, on_setattr=_id_setter)
"""The unique ``B0FieldIdentifier`` field of this fieldmap."""

sanitized_id = attr.ib(init=False, repr=False)
"""Sanitized version of the bids_id with special characters replaced by underscores."""

_wf = attr.ib(init=False, default=None, repr=False)
"""Internal pointer to a workflow."""

Expand Down Expand Up @@ -442,6 +445,10 @@ def __attrs_post_init__(self):
for intent_file in intents_meta:
_intents[intent_file].add(self.bids_id)

# Provide a sanitized identifier that can be used in cases where
# special characters are not allowed.
self.sanitized_id = re.sub(r'[^a-zA-Z0-9]', '_', self.bids_id)

def paths(self):
"""Return a tuple of paths that are sorted."""
return tuple(sorted(str(f.path) for f in self.sources))
Expand All @@ -452,7 +459,7 @@ def get_workflow(self, set_inputs=True, **kwargs):
return self._wf

# Override workflow name
kwargs["name"] = f"wf_{self.bids_id}"
kwargs["name"] = f"wf_{self.sanitized_id}"

if self.method in (EstimatorType.MAPPED, EstimatorType.PHASEDIFF):
from .workflows.fit.fieldmap import init_fmap_wf
Expand Down
28 changes: 28 additions & 0 deletions sdcflows/tests/test_fieldmaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def test_FieldmapEstimation(dsA_dir, inputfiles, method, nsources, raises):
assert fe.method == method
assert len(fe.sources) == nsources
assert fe.bids_id is not None and fe.bids_id.startswith("auto_")
assert fe.bids_id == fe.sanitized_id # Auto-generated IDs are sanitized

# Attempt to change bids_id
with pytest.raises(ValueError):
Expand Down Expand Up @@ -243,6 +244,33 @@ def test_FieldmapEstimationIdentifier(monkeypatch, dsA_dir):

fm.clear_registry()

fe = fm.FieldmapEstimation(
[
fm.FieldmapFile(
dsA_dir / "sub-01" / "fmap/sub-01_fieldmap.nii.gz",
metadata={
"Units": "Hz",
"B0FieldIdentifier": "fmap-with^special#chars",
"IntendedFor": ["file1.nii.gz", "file2.nii.gz"],
},
),
fm.FieldmapFile(
dsA_dir / "sub-01" / "fmap/sub-01_magnitude.nii.gz",
metadata={"Units": "Hz", "B0FieldIdentifier": "fmap-with^special#chars"},
),
]
)
assert fe.bids_id == "fmap-with^special#chars"
assert fe.sanitized_id == "fmap_with_special_chars"
# The unsanitized ID is used for lookups
assert fm.get_identifier("file1.nii.gz") == ("fmap-with^special#chars",)
assert fm.get_identifier("file2.nii.gz") == ("fmap-with^special#chars",)

wf = fe.get_workflow()
assert wf.name == "wf_fmap_with_special_chars"

fm.clear_registry()


def test_type_setter():
"""Cover the _type_setter routine."""
Expand Down
6 changes: 3 additions & 3 deletions sdcflows/workflows/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def init_fmap_preproc_wf(
output_dir=str(output_dir),
write_coeff=True,
bids_fmap_id=estimator.bids_id,
name=f"fmap_derivatives_wf_{estimator.bids_id}",
name=f"fmap_derivatives_wf_{estimator.sanitized_id}",
)
fmap_derivatives_wf.inputs.inputnode.source_files = source_files
fmap_derivatives_wf.inputs.inputnode.fmap_meta = [
Expand All @@ -135,15 +135,15 @@ def init_fmap_preproc_wf(
output_dir=str(output_dir),
fmap_type=str(estimator.method).rpartition(".")[-1].lower(),
bids_fmap_id=estimator.bids_id,
name=f"fmap_reports_wf_{estimator.bids_id}",
name=f"fmap_reports_wf_{estimator.sanitized_id}",
)
fmap_reports_wf.inputs.inputnode.source_files = source_files

if estimator.method not in (EstimatorType.MAPPED, EstimatorType.PHASEDIFF):
fields = INPUT_FIELDS[estimator.method]
inputnode = pe.Node(
niu.IdentityInterface(fields=fields),
name=f"in_{estimator.bids_id}",
name=f"in_{estimator.sanitized_id}",
)
# fmt:off
workflow.connect([
Expand Down
4 changes: 2 additions & 2 deletions sdcflows/workflows/fit/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def init_sdcflows_wf():
output_dir=config.execution.output_dir,
bids_fmap_id=estim.bids_id,
write_coeff=True,
name=f"fmap_derivatives_{estim.bids_id}",
name=f"fmap_derivatives_{estim.sanitized_id}",
)

source_paths = [
Expand All @@ -76,7 +76,7 @@ def init_sdcflows_wf():
fmap_type=estim.method,
output_dir=config.execution.output_dir,
bids_fmap_id=estim.bids_id,
name=f"fmap_reports_{estim.bids_id}",
name=f"fmap_reports_{estim.sanitized_id}",
)
reportlets_wf.inputs.inputnode.source_files = source_paths

Expand Down
6 changes: 4 additions & 2 deletions sdcflows/workflows/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
# https://www.nipreps.org/community/licensing/
#
"""Writing out outputs."""
import re

from nipype.pipeline import engine as pe
from nipype.interfaces import utility as niu
from niworkflows.interfaces.bids import DerivativesDataSink as _DDS
Expand Down Expand Up @@ -77,7 +79,7 @@ def init_fmap_reports_wf(

custom_entities = custom_entities or {}
if bids_fmap_id:
custom_entities["fmapid"] = bids_fmap_id.replace("_", "")
custom_entities["fmapid"] = re.sub(r'[^a-zA-Z0-9]', '', bids_fmap_id)

workflow = pe.Workflow(name=name)
inputnode = pe.Node(
Expand Down Expand Up @@ -156,7 +158,7 @@ def init_fmap_derivatives_wf(
"""
custom_entities = custom_entities or {}
if bids_fmap_id:
custom_entities["fmapid"] = bids_fmap_id.replace("_", "")
custom_entities["fmapid"] = re.sub(r'[^a-zA-Z0-9]', '', bids_fmap_id)

workflow = pe.Workflow(name=name)
inputnode = pe.Node(
Expand Down

0 comments on commit 5f84bd2

Please sign in to comment.