From 1dee509a8ba30455e41365dbebf7f50e27870394 Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Tue, 5 Jan 2021 14:42:34 -0500 Subject: [PATCH 1/4] fix intendedFor --- dcm2bids/dcm2bids.py | 16 +++++++++----- dcm2bids/sidecar.py | 36 +++++++++++++++++++------------ dcm2bids/structure.py | 49 ++++++++++++++++++++++++++++++++----------- 3 files changed, 71 insertions(+), 30 deletions(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index 59fe9047..4520a6ac 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -124,7 +124,6 @@ def run(self): sidecars.append( Sidecar(filename, self.config.get("compKeys", DEFAULT.compKeys)) ) - sidecars = sorted(sidecars) parser = SidecarPairing( sidecars, @@ -137,15 +136,18 @@ def run(self): parser.find_runs() self.logger.info("moving acquisitions into BIDS folder") + + intendedForList = [[] for i in range(len(parser.descriptions))] for acq in parser.acquisitions: - self.move(acq) + intendedForList = self.move(acq, intendedForList) check_latest() check_latest("dcm2niix") - def move(self, acquisition): + def move(self, acquisition, intendedForList): """Move an acquisition to BIDS format""" for srcFile in glob(acquisition.srcRoot + ".*"): + _, ext = splitext_(srcFile) dstFile = os.path.join(self.bidsDir, acquisition.dstRoot + ext) @@ -177,18 +179,22 @@ def move(self, acquisition): pass defaceTpl = self.config.get("defaceTpl") cmd = defaceTpl.format(srcFile=srcFile, dstFile=dstFile) + run_shell_command(cmd) + intendedForList[acquisition.indexSidecar].append(acquisition.dstIntendedFor + ext) - # use elif ext == ".json": - data = acquisition.dstSidecarData(self.config["descriptions"]) + data = acquisition.dstSidecarData(self.config["descriptions"], + intendedForList) save_json(dstFile, data) os.remove(srcFile) # just move else: os.rename(srcFile, dstFile) + intendedForList[acquisition.indexSidecar].append(acquisition.dstIntendedFor + ext) + return intendedForList def get_arguments(): """Load arguments for main""" diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index 73d41bad..61f90dc5 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -95,7 +95,7 @@ def __init__(self, sidecars, descriptions, searchMethod=DEFAULT.searchMethod, self._searchMethod = "" self.graph = OrderedDict() - self.aquisitions = [] + self.acquisitions = [] self.sidecars = sidecars self.descriptions = descriptions @@ -154,14 +154,14 @@ def build_graph(self): A graph (OrderedDict) """ graph = OrderedDict((_, []) for _ in self.sidecars) - possibleLinks = itertools.product(self.sidecars, self.descriptions) for sidecar, description in possibleLinks: criteria = description.get("criteria", None) if criteria and self.isLink(sidecar.data, criteria): - graph[sidecar].append(description) + graph[sidecar].append(description) self.graph = graph + return graph def isLink(self, data, criteria): @@ -213,32 +213,42 @@ def build_acquisitions(self, participant): A list of acquisition objects """ acquisitions = [] + acquisitions_intendedFor = [] self.logger.info("Sidecars pairing:") - for sidecar, descriptions in iteritems(self.graph): + for sidecar, valid_descriptions in iteritems(self.graph): + #for sidecar, descriptions in iteritems(self.graph): sidecarName = os.path.basename(sidecar.root) # only one description for the sidecar - if len(descriptions) == 1: - desc = descriptions[0] - acq = Acquisition(participant, srcSidecar=sidecar, **desc) - acquisitions.append(acq) + if len(valid_descriptions) == 1: + desc = valid_descriptions[0] + acq = Acquisition(participant, + srcSidecar=sidecar, **desc) + acq.indexSidecar = self.descriptions.index(desc) + + if acq.intendedFor != [None]: + acquisitions_intendedFor.append(acq) + else: + acquisitions.append(acq) self.logger.info("%s <- %s", acq.suffix, sidecarName) # sidecar with no link - elif len(descriptions) == 0: + elif len(valid_descriptions) == 0: self.logger.info("No Pairing <- %s", sidecarName) # sidecar with several links else: self.logger.warning("Several Pairing <- %s", sidecarName) - for desc in descriptions: - acq = Acquisition(participant, **desc) + for desc in valid_descriptions: + acq = Acquisition(participant, indexSidecar=index, + **desc) self.logger.warning(" -> %s", acq.suffix) - self.acquisitions = acquisitions - return acquisitions + self.acquisitions = acquisitions + acquisitions_intendedFor + + return acquisitions + acquisitions_intendedFor def find_runs(self): """ diff --git a/dcm2bids/structure.py b/dcm2bids/structure.py index d03c3b4d..94ea9d19 100644 --- a/dcm2bids/structure.py +++ b/dcm2bids/structure.py @@ -113,6 +113,7 @@ def __init__( participant, dataType, modalityLabel, + indexSidecar=None, customLabels="", srcSidecar=None, sidecarChanges=None, @@ -123,16 +124,19 @@ def __init__( self._modalityLabel = "" self._customLabels = "" self._intendedFor = None + self._indexSidecar = None self.participant = participant self.dataType = dataType self.modalityLabel = modalityLabel self.customLabels = customLabels self.srcSidecar = srcSidecar + if sidecarChanges is None: self.sidecarChanges = {} else: self.sidecarChanges = sidecarChanges + if intendedFor is None: self.intendedFor = IntendedFor else: @@ -206,6 +210,18 @@ def dstRoot(self): self.participant.prefix + self.suffix, ) + @property + def dstIntendedFor(self): + """ + Return: + The destination root inside the BIDS structure for intendedFor + """ + return opj( + self.participant.session, + self.dataType, + self.participant.prefix + self.suffix, + ) + @property def intendedFor(self): return self._intendedFor @@ -217,27 +233,36 @@ def intendedFor(self, value): else: self._intendedFor = [value] - def dstSidecarData(self, descriptions): + @property + def indexSidecar(self): + """ + Returns: + A int '_' + """ + return self._indexSidecar + + @indexSidecar.setter + def indexSidecar(self, value): + """ + Returns: + A int '_' + """ + self._indexSidecar = value + + + def dstSidecarData(self, descriptions, intendedForList): """ """ data = self.srcSidecar.origData data["Dcm2bidsVersion"] = __version__ + # intendedFor key if self.intendedFor != [None]: intendedValue = [] - for index in self.intendedFor: - intendedDesc = descriptions[index] - session = self.participant.session - dataType = intendedDesc["dataType"] - - niiFile = self.participant.prefix - niiFile += self.prepend(intendedDesc.get("customLabels", "")) - niiFile += self.prepend(intendedDesc["modalityLabel"]) - niiFile += ".nii.gz" - - intendedValue.append(opj(session, dataType, niiFile).replace("\\", "/")) + for index in self.intendedFor: + intendedValue = intendedValue + intendedForList[index] if len(intendedValue) == 1: data["IntendedFor"] = intendedValue[0] From b58050a092ae5d7acc856c5b06add10086a6785e Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 14 Apr 2022 11:03:26 -0400 Subject: [PATCH 2/4] intendedFor only for nii.z files --- dcm2bids/dcm2bids.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index 4520a6ac..92c7ab1d 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -192,7 +192,8 @@ def move(self, acquisition, intendedForList): # just move else: os.rename(srcFile, dstFile) - intendedForList[acquisition.indexSidecar].append(acquisition.dstIntendedFor + ext) + if ext == ".nii.gz": + intendedForList[acquisition.indexSidecar].append(acquisition.dstIntendedFor + ext) return intendedForList From 0d4373679d6ead686b05d43632d7b8d3fa2c0c46 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 14 Apr 2022 15:19:31 -0400 Subject: [PATCH 3/4] fix tests --- dcm2bids/dcm2bids.py | 8 ++++++-- dcm2bids/sidecar.py | 2 +- tests/test_structure.py | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index 92c7ab1d..a96a1b45 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -125,6 +125,8 @@ def run(self): Sidecar(filename, self.config.get("compKeys", DEFAULT.compKeys)) ) + sidecars = sorted(sidecars) + parser = SidecarPairing( sidecars, self.config["descriptions"], @@ -192,8 +194,10 @@ def move(self, acquisition, intendedForList): # just move else: os.rename(srcFile, dstFile) - if ext == ".nii.gz": - intendedForList[acquisition.indexSidecar].append(acquisition.dstIntendedFor + ext) + + intendedFile = acquisition.dstIntendedFor + ".nii.gz" + if not intendedFile in intendedForList[acquisition.indexSidecar]: + intendedForList[acquisition.indexSidecar].append(intendedFile) return intendedForList diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index 61f90dc5..2ffbd820 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -242,7 +242,7 @@ def build_acquisitions(self, participant): else: self.logger.warning("Several Pairing <- %s", sidecarName) for desc in valid_descriptions: - acq = Acquisition(participant, indexSidecar=index, + acq = Acquisition(participant, indexSidecar=self.descriptions.index(desc), **desc) self.logger.warning(" -> %s", acq.suffix) diff --git a/tests/test_structure.py b/tests/test_structure.py index 936dc600..396c3086 100644 --- a/tests/test_structure.py +++ b/tests/test_structure.py @@ -29,5 +29,5 @@ ) def test_acquisition_get_dst_path(name, session, modality, custom, expected): participant = Participant(name, session) - acquisition = Acquisition(participant, "anat", modality, custom) + acquisition = Acquisition(participant, "anat", modality, customLabels=custom) assert acquisition.dstRoot == expected From 874c3902c9f8e371f1e4b161162b63ab096b6604 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 14 Apr 2022 15:29:31 -0400 Subject: [PATCH 4/4] BF test windows --- tests/test_dcm2bids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_dcm2bids.py b/tests/test_dcm2bids.py index 6b7e00f4..7330a684 100644 --- a/tests/test_dcm2bids.py +++ b/tests/test_dcm2bids.py @@ -57,7 +57,7 @@ def test_dcm2bids(): fmapFile = os.path.join(bidsDir.name, "sub-01", "fmap", "sub-01_echo-492_fmap.json") data = load_json(fmapFile) fmapMtime = os.stat(fmapFile).st_mtime - assert data["IntendedFor"] == "dwi/sub-01_dwi.nii.gz" + assert data["IntendedFor"] == os.path.join("dwi", "sub-01_dwi.nii.gz") data = load_json( os.path.join(