@@ -168,9 +168,25 @@ def __attrs_post_init__(self):
168
168
if self .space .startswith ("fs" ):
169
169
object .__setattr__ (self , "dim" , 2 )
170
170
171
+ if "volspace" in self .spec :
172
+ volspace = self .spec ["volspace" ]
173
+ if (self .space in self ._standard_spaces ) and (volspace not in self ._standard_spaces ):
174
+ raise ValueError (
175
+ f"Surface space ({ self .space } ) is a standard space, "
176
+ f"but volume space ({ volspace } ) is not. "
177
+ "Mixing standard and non-standard spaces is not currently allowed."
178
+ )
179
+ elif (self .space not in self ._standard_spaces ) and (volspace in self ._standard_spaces ):
180
+ raise ValueError (
181
+ f"Surface space ({ self .space } ) is a non-standard space, "
182
+ f"but volume space ({ volspace } ) is a standard space. "
183
+ "Mixing standard and non-standard spaces is not currently allowed."
184
+ )
185
+
171
186
if self .space in self ._standard_spaces :
172
187
object .__setattr__ (self , "standard" , True )
173
188
189
+ # Check that cohort is handled appropriately
174
190
_cohorts = ["%s" % t for t in _tfapi .TF_LAYOUT .get_cohorts (template = self .space )]
175
191
if "cohort" in self .spec :
176
192
if not _cohorts :
@@ -191,6 +207,30 @@ def __attrs_post_init__(self):
191
207
"Set a valid cohort selector from: %s." % (self .space , _cohorts )
192
208
)
193
209
210
+ # Check that cohort is handled appropriately for the volume template if necessary
211
+ if "volspace" in self .spec :
212
+ _cohorts = [
213
+ "%s" % t for t in _tfapi .TF_LAYOUT .get_cohorts (template = self .spec ["volspace" ])
214
+ ]
215
+ if "volcohort" in self .spec :
216
+ if not _cohorts :
217
+ raise ValueError (
218
+ 'standard space "%s" does not accept a cohort '
219
+ "specification." % self .spec ["volspace" ]
220
+ )
221
+
222
+ if str (self .spec ["volcohort" ]) not in _cohorts :
223
+ raise ValueError (
224
+ 'standard space "%s" does not contain any cohort '
225
+ 'named "%s".' % (self .spec ["volspace" ], self .spec ["volcohort" ])
226
+ )
227
+ elif _cohorts :
228
+ _cohorts = ", " .join (['"cohort-%s"' % c for c in _cohorts ])
229
+ raise ValueError (
230
+ 'standard space "%s" is not fully defined.\n '
231
+ "Set a valid cohort selector from: %s." % (self .spec ["volspace" ], _cohorts )
232
+ )
233
+
194
234
@property
195
235
def fullname (self ):
196
236
"""
@@ -205,9 +245,17 @@ def fullname(self):
205
245
'MNIPediatricAsym:cohort-1'
206
246
207
247
"""
208
- if "cohort" not in self .spec :
209
- return self .space
210
- return "%s:cohort-%s" % (self .space , self .spec ["cohort" ])
248
+ name = self .space
249
+
250
+ if "cohort" in self .spec :
251
+ name += f":cohort-{ self .spec ['cohort' ]} "
252
+
253
+ if "volspace" in self .spec :
254
+ name += f"::{ self .spec ['volspace' ]} "
255
+ if "volcohort" in self .spec :
256
+ name += f":cohort-{ self .spec ['volcohort' ]} "
257
+
258
+ return name
211
259
212
260
@property
213
261
def legacyname (self ):
@@ -330,13 +378,37 @@ def from_string(cls, value):
330
378
Reference(space='MNIPediatricAsym', spec={'cohort': '6', 'res': '2'}),
331
379
Reference(space='MNIPediatricAsym', spec={'cohort': '6', 'res': 'iso1.6mm'})]
332
380
381
+ >>> Reference.from_string(
382
+ ... "dhcpAsym:cohort-42:den-32k::dhcpVol:cohort-44:res-2"
383
+ ... ) # doctest: +NORMALIZE_WHITESPACE
384
+ [Reference(space='dhcpAsym', spec={'cohort': '42', 'den': '32k', 'volspace': 'dhcpVol',
385
+ 'volcohort': '44', 'res': '2'})]
386
+
333
387
"""
388
+ volume_value = None
389
+ if "::" in value :
390
+ # CIFTI definition with both surface and volume spaces defined
391
+ value , volume_value = value .split ("::" )
392
+ # We treat the surface space definition as the "primary" space
393
+ _args = value .split (":" )
394
+
334
395
_args = value .split (":" )
335
396
spec = defaultdict (list , {})
336
397
for modifier in _args [1 :]:
337
398
mitems = modifier .split ("-" , 1 )
338
399
spec [mitems [0 ]].append (len (mitems ) == 1 or mitems [1 ])
339
400
401
+ if volume_value :
402
+ # Tack on the volume space definition to the surface space definition
403
+ volume_args = volume_value .split (":" )
404
+ # There are two special entities to prevent overloading: volspace and volcohort
405
+ spec ["volspace" ] = [volume_args [0 ]]
406
+ for modifier in volume_args [1 :]:
407
+ mitems = modifier .split ("-" , 1 )
408
+ if mitems [0 ] == "cohort" :
409
+ mitems [0 ] = "volcohort"
410
+ spec [mitems [0 ]].append (len (mitems ) == 1 or mitems [1 ])
411
+
340
412
allspecs = _expand_entities (spec )
341
413
342
414
return [cls (_args [0 ], s ) for s in allspecs ]
0 commit comments