junifer 0.0.7.dev332__py3-none-any.whl → 0.0.8__py3-none-any.whl

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 (293) hide show
  1. junifer/_version.py +9 -19
  2. junifer/api/__init__.pyi +17 -2
  3. junifer/api/functions.py +222 -39
  4. junifer/api/queue_context/__init__.pyi +11 -3
  5. junifer/api/queue_context/gnu_parallel_local_adapter.py +81 -120
  6. junifer/api/queue_context/htcondor_adapter.py +118 -181
  7. junifer/api/queue_context/queue_context_adapter.py +51 -7
  8. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +10 -35
  9. junifer/api/queue_context/tests/test_htcondor_adapter.py +13 -50
  10. junifer/api/res/fsl/run_fsl_docker.sh +4 -0
  11. junifer/api/tests/test_functions.py +863 -36
  12. junifer/cli/__init__.py +1 -7
  13. junifer/cli/cli.py +41 -22
  14. junifer/cli/parser.py +23 -147
  15. junifer/cli/tests/data/gmd_mean.yaml +6 -6
  16. junifer/cli/tests/data/gmd_mean_htcondor.yaml +6 -5
  17. junifer/cli/tests/data/partly_cloudy_agg_mean_tian.yml +1 -0
  18. junifer/cli/tests/test_cli.py +120 -4
  19. junifer/cli/tests/test_cli_utils.py +23 -6
  20. junifer/cli/utils.py +14 -9
  21. junifer/configs/__init__.py +5 -0
  22. junifer/configs/__init__.pyi +0 -0
  23. junifer/configs/juseless/datagrabbers/__init__.pyi +4 -2
  24. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +18 -24
  25. junifer/configs/juseless/datagrabbers/camcan_vbm.py +20 -27
  26. junifer/configs/juseless/datagrabbers/ixi_vbm.py +44 -52
  27. junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py +0 -7
  28. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -19
  29. junifer/configs/juseless/datagrabbers/ucla.py +111 -104
  30. junifer/configs/juseless/datagrabbers/ukb_vbm.py +19 -25
  31. junifer/configs/py.typed +0 -0
  32. junifer/conftest.py +63 -24
  33. junifer/data/_dispatch.py +9 -19
  34. junifer/data/coordinates/_ants_coordinates_warper.py +4 -1
  35. junifer/data/coordinates/_coordinates.py +51 -6
  36. junifer/data/coordinates/_fsl_coordinates_warper.py +4 -1
  37. junifer/data/coordinates/tests/test_coordinates.py +15 -3
  38. junifer/data/coordinates/tests/test_coordinates_names.py +37 -0
  39. junifer/data/maps/_ants_maps_warper.py +18 -12
  40. junifer/data/maps/_fsl_maps_warper.py +7 -3
  41. junifer/data/maps/_maps.py +12 -8
  42. junifer/data/maps/tests/test_maps.py +13 -21
  43. junifer/data/masks/_ants_mask_warper.py +18 -12
  44. junifer/data/masks/_fsl_mask_warper.py +7 -3
  45. junifer/data/masks/_masks.py +15 -12
  46. junifer/data/masks/tests/test_masks.py +20 -17
  47. junifer/data/parcellations/_ants_parcellation_warper.py +18 -12
  48. junifer/data/parcellations/_fsl_parcellation_warper.py +7 -5
  49. junifer/data/parcellations/_parcellations.py +125 -91
  50. junifer/data/parcellations/tests/test_parcellations.py +122 -1
  51. junifer/data/template_spaces.py +117 -50
  52. junifer/data/tests/test_template_spaces.py +10 -7
  53. junifer/data/utils.py +10 -8
  54. junifer/datagrabber/__init__.pyi +38 -5
  55. junifer/datagrabber/aomic/__init__.pyi +8 -1
  56. junifer/datagrabber/aomic/_types.py +22 -0
  57. junifer/datagrabber/aomic/id1000.py +193 -183
  58. junifer/datagrabber/aomic/piop1.py +215 -259
  59. junifer/datagrabber/aomic/piop2.py +211 -244
  60. junifer/datagrabber/aomic/tests/test_id1000.py +70 -53
  61. junifer/datagrabber/aomic/tests/test_piop1.py +98 -102
  62. junifer/datagrabber/aomic/tests/test_piop2.py +88 -85
  63. junifer/datagrabber/base.py +253 -79
  64. junifer/datagrabber/datalad_base.py +127 -76
  65. junifer/datagrabber/dmcc13_benchmark.py +204 -289
  66. junifer/datagrabber/hcp1200/__init__.pyi +7 -2
  67. junifer/datagrabber/hcp1200/datalad_hcp1200.py +61 -40
  68. junifer/datagrabber/hcp1200/hcp1200.py +151 -164
  69. junifer/datagrabber/hcp1200/tests/test_hcp1200.py +116 -128
  70. junifer/datagrabber/multiple.py +183 -63
  71. junifer/datagrabber/pattern.py +358 -227
  72. junifer/datagrabber/pattern_datalad.py +84 -124
  73. junifer/datagrabber/pattern_validation_mixin.py +22 -50
  74. junifer/datagrabber/tests/test_base.py +17 -4
  75. junifer/datagrabber/tests/test_datalad_base.py +20 -27
  76. junifer/datagrabber/tests/test_dmcc13_benchmark.py +110 -122
  77. junifer/datagrabber/tests/test_multiple.py +293 -31
  78. junifer/datagrabber/tests/test_pattern.py +577 -18
  79. junifer/datagrabber/tests/test_pattern_datalad.py +177 -107
  80. junifer/datagrabber/tests/test_pattern_validation_mixin.py +9 -51
  81. junifer/datareader/default.py +8 -5
  82. junifer/datareader/tests/test_default_reader.py +1 -1
  83. junifer/external/BrainPrint/.codecov.yml +2 -0
  84. junifer/external/BrainPrint/.codespellignore +2 -0
  85. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/bug-report.md +45 -0
  86. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/documentation.md +12 -0
  87. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/feature-request.md +24 -0
  88. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/questions-help-support.md +28 -0
  89. junifer/external/BrainPrint/.github/dependabot.yml +6 -0
  90. junifer/external/BrainPrint/.github/workflows/build.yml +53 -0
  91. junifer/external/BrainPrint/.github/workflows/code-style.yml +44 -0
  92. junifer/external/BrainPrint/.github/workflows/doc.yml +65 -0
  93. junifer/external/BrainPrint/.github/workflows/publish.yml +31 -0
  94. junifer/external/BrainPrint/.github/workflows/pytest.yml +54 -0
  95. junifer/external/BrainPrint/.gitignore +123 -0
  96. junifer/external/BrainPrint/LICENSE +21 -0
  97. junifer/external/BrainPrint/README.md +108 -0
  98. junifer/external/BrainPrint/brainprint/cli/__init__.py +11 -0
  99. junifer/external/BrainPrint/brainprint/cli/help_text.py +169 -0
  100. junifer/external/BrainPrint/brainprint/cli/parser.py +150 -0
  101. junifer/external/BrainPrint/brainprint/cli/utils.py +14 -0
  102. junifer/external/BrainPrint/brainprint/commands/__init__.py +0 -0
  103. junifer/external/BrainPrint/brainprint/commands/sys_info.py +18 -0
  104. junifer/external/BrainPrint/brainprint/utils/tests/__init__.py +0 -0
  105. junifer/external/BrainPrint/brainprint/utils/tests/test_config.py +33 -0
  106. junifer/external/BrainPrint/doc/Makefile +20 -0
  107. junifer/external/BrainPrint/doc/_static/.gitkeep +0 -0
  108. junifer/external/BrainPrint/doc/_templates/autosummary/class.rst +10 -0
  109. junifer/external/BrainPrint/doc/_templates/autosummary/function.rst +8 -0
  110. junifer/external/BrainPrint/doc/_templates/autosummary/module.rst +6 -0
  111. junifer/external/BrainPrint/doc/api/index.rst +11 -0
  112. junifer/external/BrainPrint/doc/conf.py +272 -0
  113. junifer/external/BrainPrint/doc/index.rst +140 -0
  114. junifer/external/BrainPrint/doc/links.inc +36 -0
  115. junifer/external/BrainPrint/doc/make.bat +35 -0
  116. junifer/external/BrainPrint/doc/references.bib +23 -0
  117. junifer/external/BrainPrint/pyproject.toml +170 -0
  118. junifer/external/BrainPrint/setup.py +3 -0
  119. junifer/external/__init__.py +5 -0
  120. junifer/external/__init__.pyi +0 -0
  121. junifer/external/nilearn/junifer_connectivity_measure.py +95 -39
  122. junifer/external/nilearn/junifer_nifti_spheres_masker.py +226 -67
  123. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +39 -27
  124. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +231 -21
  125. junifer/external/py.typed +0 -0
  126. junifer/markers/__init__.pyi +6 -3
  127. junifer/markers/base.py +126 -76
  128. junifer/markers/brainprint.py +30 -39
  129. junifer/markers/complexity/__init__.py +20 -3
  130. junifer/markers/complexity/complexity_base.py +40 -41
  131. junifer/markers/complexity/hurst_exponent.py +22 -35
  132. junifer/markers/complexity/multiscale_entropy_auc.py +53 -41
  133. junifer/markers/complexity/perm_entropy.py +22 -36
  134. junifer/markers/complexity/range_entropy.py +22 -35
  135. junifer/markers/complexity/range_entropy_auc.py +27 -36
  136. junifer/markers/complexity/sample_entropy.py +22 -36
  137. junifer/markers/complexity/tests/test_complexity_registry.py +48 -0
  138. junifer/markers/complexity/tests/test_hurst_exponent.py +47 -36
  139. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +50 -36
  140. junifer/markers/complexity/tests/test_perm_entropy.py +48 -36
  141. junifer/markers/complexity/tests/test_range_entropy.py +47 -36
  142. junifer/markers/complexity/tests/test_range_entropy_auc.py +47 -36
  143. junifer/markers/complexity/tests/test_sample_entropy.py +48 -36
  144. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +50 -36
  145. junifer/markers/complexity/weighted_perm_entropy.py +22 -36
  146. junifer/markers/ets_rss.py +35 -31
  147. junifer/markers/falff/__init__.pyi +7 -1
  148. junifer/markers/falff/_afni_falff.py +22 -9
  149. junifer/markers/falff/_junifer_falff.py +47 -31
  150. junifer/markers/falff/falff_base.py +80 -60
  151. junifer/markers/falff/falff_maps.py +17 -41
  152. junifer/markers/falff/falff_parcels.py +26 -51
  153. junifer/markers/falff/falff_spheres.py +34 -61
  154. junifer/markers/falff/tests/test_falff_maps.py +20 -23
  155. junifer/markers/falff/tests/test_falff_mask.py +99 -0
  156. junifer/markers/falff/tests/test_falff_parcels.py +14 -10
  157. junifer/markers/falff/tests/test_falff_spheres.py +14 -10
  158. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +32 -34
  159. junifer/markers/functional_connectivity/edge_functional_connectivity_maps.py +12 -25
  160. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +19 -34
  161. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +24 -44
  162. junifer/markers/functional_connectivity/functional_connectivity_base.py +50 -40
  163. junifer/markers/functional_connectivity/functional_connectivity_maps.py +12 -25
  164. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +19 -34
  165. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +24 -45
  166. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +21 -22
  167. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_maps.py +8 -7
  168. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +8 -4
  169. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +8 -4
  170. junifer/markers/functional_connectivity/tests/test_functional_connectivity_maps.py +8 -7
  171. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +9 -5
  172. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +8 -12
  173. junifer/markers/maps_aggregation.py +77 -55
  174. junifer/markers/parcel_aggregation.py +91 -70
  175. junifer/markers/reho/__init__.pyi +7 -1
  176. junifer/markers/reho/_afni_reho.py +23 -14
  177. junifer/markers/reho/_junifer_reho.py +112 -123
  178. junifer/markers/reho/reho_base.py +115 -37
  179. junifer/markers/reho/reho_maps.py +18 -32
  180. junifer/markers/reho/reho_parcels.py +26 -41
  181. junifer/markers/reho/reho_spheres.py +33 -54
  182. junifer/markers/reho/tests/test_junifer_reho.py +178 -0
  183. junifer/markers/reho/tests/test_reho_maps.py +27 -25
  184. junifer/markers/reho/tests/test_reho_parcels.py +28 -22
  185. junifer/markers/reho/tests/test_reho_spheres.py +16 -12
  186. junifer/markers/sphere_aggregation.py +88 -72
  187. junifer/markers/temporal_snr/temporal_snr_base.py +32 -30
  188. junifer/markers/temporal_snr/temporal_snr_maps.py +9 -18
  189. junifer/markers/temporal_snr/temporal_snr_parcels.py +19 -27
  190. junifer/markers/temporal_snr/temporal_snr_spheres.py +27 -41
  191. junifer/markers/temporal_snr/tests/test_temporal_snr_base.py +2 -2
  192. junifer/markers/temporal_snr/tests/test_temporal_snr_maps.py +17 -22
  193. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +11 -3
  194. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +9 -9
  195. junifer/markers/tests/test_brainprint.py +10 -9
  196. junifer/markers/tests/test_ets_rss.py +7 -3
  197. junifer/markers/tests/test_lost_regions.py +279 -0
  198. junifer/markers/tests/test_maps_aggregation.py +67 -114
  199. junifer/markers/tests/test_marker_utils.py +40 -1
  200. junifer/markers/tests/test_markers_base.py +275 -6
  201. junifer/markers/tests/test_parcel_aggregation.py +91 -53
  202. junifer/markers/tests/test_sphere_aggregation.py +53 -47
  203. junifer/markers/utils.py +267 -5
  204. junifer/onthefly/__init__.py +2 -3
  205. junifer/onthefly/__init__.pyi +4 -0
  206. junifer/onthefly/_brainprint.py +3 -5
  207. junifer/onthefly/py.typed +0 -0
  208. junifer/onthefly/read_transform.py +11 -9
  209. junifer/onthefly/tests/test_read_transform.py +7 -7
  210. junifer/pipeline/__init__.pyi +4 -2
  211. junifer/pipeline/marker_collection.py +14 -10
  212. junifer/pipeline/pipeline_component_registry.py +25 -6
  213. junifer/pipeline/pipeline_step_mixin.py +5 -12
  214. junifer/pipeline/tests/test_data_object_dumper.py +10 -10
  215. junifer/pipeline/tests/test_marker_collection.py +145 -168
  216. junifer/pipeline/tests/test_pipeline_component_registry.py +52 -8
  217. junifer/pipeline/tests/test_pipeline_step_mixin.py +12 -26
  218. junifer/pipeline/tests/test_update_meta_mixin.py +4 -5
  219. junifer/pipeline/tests/test_workdir_manager.py +39 -0
  220. junifer/pipeline/update_meta_mixin.py +13 -10
  221. junifer/pipeline/utils.py +22 -17
  222. junifer/pipeline/workdir_manager.py +41 -32
  223. junifer/preprocess/__init__.pyi +9 -4
  224. junifer/preprocess/_temporal_filter.py +34 -33
  225. junifer/preprocess/_temporal_slicer.py +17 -30
  226. junifer/preprocess/base.py +99 -55
  227. junifer/preprocess/confounds/__init__.pyi +10 -2
  228. junifer/preprocess/confounds/fmriprep_confound_remover.py +87 -109
  229. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +64 -45
  230. junifer/preprocess/smoothing/__init__.pyi +2 -2
  231. junifer/preprocess/smoothing/_afni_smoothing.py +8 -7
  232. junifer/preprocess/smoothing/_fsl_smoothing.py +6 -4
  233. junifer/preprocess/smoothing/_nilearn_smoothing.py +7 -5
  234. junifer/preprocess/smoothing/smoothing.py +59 -40
  235. junifer/preprocess/smoothing/tests/test_smoothing.py +28 -8
  236. junifer/preprocess/tests/test_preprocess_base.py +17 -9
  237. junifer/preprocess/tests/test_temporal_filter.py +37 -16
  238. junifer/preprocess/tests/test_temporal_slicer.py +12 -12
  239. junifer/preprocess/warping/__init__.pyi +2 -2
  240. junifer/preprocess/warping/_ants_warper.py +56 -40
  241. junifer/preprocess/warping/_fsl_warper.py +49 -36
  242. junifer/preprocess/warping/_utils.py +106 -0
  243. junifer/preprocess/warping/space_warper.py +99 -98
  244. junifer/preprocess/warping/tests/test_space_warper.py +46 -41
  245. junifer/preprocess/warping/tests/test_warping_utils.py +163 -0
  246. junifer/stats.py +46 -34
  247. junifer/storage/__init__.pyi +8 -4
  248. junifer/storage/base.py +129 -64
  249. junifer/storage/hdf5.py +307 -199
  250. junifer/storage/pandas_base.py +46 -24
  251. junifer/storage/sqlite.py +99 -62
  252. junifer/storage/tests/data/collected_h5io_fork.hdf5 +0 -0
  253. junifer/storage/tests/test_hdf5.py +147 -12
  254. junifer/storage/tests/test_repeated_storage.py +293 -0
  255. junifer/storage/tests/test_sqlite.py +9 -20
  256. junifer/storage/tests/test_storage_base.py +18 -21
  257. junifer/storage/tests/test_utils.py +83 -22
  258. junifer/storage/utils.py +58 -38
  259. junifer/testing/__init__.pyi +2 -2
  260. junifer/testing/datagrabbers.py +480 -44
  261. junifer/testing/registry.py +12 -0
  262. junifer/testing/tests/test_adhdtesting_datagrabber.py +24 -0
  263. junifer/testing/tests/test_oasisvmbtesting_datagrabber.py +5 -0
  264. junifer/testing/tests/test_partlycloudytesting_datagrabber.py +52 -0
  265. junifer/testing/tests/test_spmauditory_datagrabber.py +16 -0
  266. junifer/testing/tests/test_testing_registry.py +31 -0
  267. junifer/testing/tests/test_testing_utils.py +35 -0
  268. junifer/testing/tests/test_uclacnpvbmtesting_datagrabber.py +81 -0
  269. junifer/testing/utils.py +33 -1
  270. junifer/tests/test_stats.py +1 -5
  271. junifer/typing/__init__.pyi +2 -0
  272. junifer/typing/_typing.py +34 -19
  273. junifer/typing/py.typed +0 -0
  274. junifer/utils/__init__.pyi +10 -1
  275. junifer/utils/_config.py +1 -2
  276. junifer/utils/helpers.py +68 -2
  277. junifer/utils/logging.py +31 -7
  278. junifer/utils/tests/test_helpers.py +36 -1
  279. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/METADATA +43 -35
  280. junifer-0.0.8.dist-info/RECORD +402 -0
  281. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/WHEEL +1 -1
  282. junifer/cli/tests/test_parser.py +0 -280
  283. junifer/external/h5io/h5io/__init__.py +0 -15
  284. junifer/external/h5io/h5io/_h5io.py +0 -767
  285. junifer/external/h5io/h5io/_version.py +0 -1
  286. junifer/external/h5io/h5io/chunked_array.py +0 -94
  287. junifer/external/h5io/h5io/chunked_list.py +0 -65
  288. junifer/markers/complexity/__init__.pyi +0 -17
  289. junifer-0.0.7.dev332.dist-info/RECORD +0 -353
  290. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/entry_points.txt +0 -0
  291. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/AUTHORS.rst +0 -0
  292. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/LICENSE.md +0 -0
  293. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/top_level.txt +0 -0
@@ -6,16 +6,19 @@
6
6
  # Synchon Mandal <s.mandal@fz-juelich.de>
7
7
  # License: AGPL
8
8
 
9
- from typing import Any, ClassVar, Optional, Union
9
+ from typing import Annotated, Any, ClassVar
10
10
 
11
11
  import numpy as np
12
+ from pydantic import BeforeValidator
12
13
 
13
14
  from ..api.decorators import register_marker
15
+ from ..datagrabber import DataType
16
+ from ..storage import StorageType
14
17
  from ..typing import Dependencies, MarkerInOutMappings
15
- from ..utils import logger
16
- from .base import BaseMarker
18
+ from ..utils import ensure_list, ensure_list_or_none
19
+ from .base import BaseMarker, logger
17
20
  from .parcel_aggregation import ParcelAggregation
18
- from .utils import _ets
21
+ from .utils import _ets, _has_data
19
22
 
20
23
 
21
24
  __all__ = ["RSSETSMarker"]
@@ -31,47 +34,42 @@ class RSSETSMarker(BaseMarker):
31
34
  The name(s) of the parcellation(s) to use.
32
35
  See :func:`.list_data` for options.
33
36
  agg_method : str, optional
34
- The method to perform aggregation using. Check valid options in
35
- :func:`.get_aggfunc_by_name` (default "mean").
36
- agg_method_params : dict, optional
37
- Parameters to pass to the aggregation function. Check valid options in
38
- :func:`.get_aggfunc_by_name` (default None).
39
- masks : str, dict or list of dict or str, optional
37
+ The aggregation function to use.
38
+ See :func:`.get_aggfunc_by_name` for options
39
+ (default "mean").
40
+ agg_method_params : dict or None, optional
41
+ The parameters to pass to the aggregation function.
42
+ See :func:`.get_aggfunc_by_name` for options (default None).
43
+ masks : str, dict, list of them or None, optional
40
44
  The specification of the masks to apply to regions before extracting
41
45
  signals. Check :ref:`Using Masks <using_masks>` for more details.
42
46
  If None, will not apply any mask (default None).
43
- name : str, optional
44
- The name of the marker. If None, will use the class name (default
45
- None).
47
+ name : str or None, optional
48
+ The name of the marker.
49
+ If None, will use the class name (default None).
46
50
 
47
51
  """
48
52
 
49
53
  _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn"}
50
54
 
51
55
  _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = {
52
- "BOLD": {
53
- "rss_ets": "timeseries",
56
+ DataType.BOLD: {
57
+ "rss_ets": StorageType.Timeseries,
54
58
  },
55
59
  }
56
60
 
57
- def __init__(
58
- self,
59
- parcellation: Union[str, list[str]],
60
- agg_method: str = "mean",
61
- agg_method_params: Optional[dict] = None,
62
- masks: Union[str, dict, list[Union[dict, str]], None] = None,
63
- name: Optional[str] = None,
64
- ) -> None:
65
- self.parcellation = parcellation
66
- self.agg_method = agg_method
67
- self.agg_method_params = agg_method_params
68
- self.masks = masks
69
- super().__init__(name=name)
61
+ parcellation: Annotated[str | list[str], BeforeValidator(ensure_list)]
62
+ agg_method: str = "mean"
63
+ agg_method_params: dict | None = None
64
+ masks: Annotated[
65
+ dict | str | list[dict | str] | None,
66
+ BeforeValidator(ensure_list_or_none),
67
+ ] = None
70
68
 
71
69
  def compute(
72
70
  self,
73
71
  input: dict[str, Any],
74
- extra_input: Optional[dict] = None,
72
+ extra_input: dict | None = None,
75
73
  ) -> dict:
76
74
  """Compute.
77
75
 
@@ -110,12 +108,18 @@ class RSSETSMarker(BaseMarker):
110
108
  parcellation=self.parcellation,
111
109
  method=self.agg_method,
112
110
  method_params=self.agg_method_params,
111
+ on=DataType.BOLD,
113
112
  masks=self.masks,
114
113
  ).compute(input=input, extra_input=extra_input)
115
114
  # Compute edgewise timeseries
116
115
  edge_ts, _ = _ets(aggregation["aggregation"]["data"])
117
- # Compute the RSS of edgewise timeseries
118
- rss = np.sum(edge_ts**2, 1) ** 0.5
116
+ # Compute the RSS of edgewise timeseries, only using the edges with
117
+ # data (e.g. regions lost in resampling have none)
118
+ edge_ts = edge_ts[:, _has_data(edge_ts)]
119
+ if edge_ts.shape[1] > 0:
120
+ rss = np.sum(edge_ts**2, 1) ** 0.5
121
+ else:
122
+ rss = np.full(edge_ts.shape[0], np.nan)
119
123
 
120
124
  return {
121
125
  "rss_ets": {
@@ -1,5 +1,11 @@
1
- __all__ = ["ALFFMaps", "ALFFParcels", "ALFFSpheres"]
1
+ __all__ = [
2
+ "ALFFImpl",
3
+ "ALFFMaps",
4
+ "ALFFParcels",
5
+ "ALFFSpheres",
6
+ ]
2
7
 
8
+ from .falff_base import ALFFImpl
3
9
  from .falff_maps import ALFFMaps
4
10
  from .falff_parcels import ALFFParcels
5
11
  from .falff_spheres import ALFFSpheres
@@ -3,20 +3,21 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
+ import atexit
6
7
  from functools import lru_cache
7
8
  from pathlib import Path
8
9
  from typing import (
9
10
  TYPE_CHECKING,
10
11
  ClassVar,
11
- Optional,
12
12
  )
13
13
 
14
14
  import nibabel as nib
15
15
 
16
- from ...pipeline import WorkDirManager
16
+ from ...pipeline import ExtDep, WorkDirManager
17
17
  from ...typing import ExternalDependencies
18
- from ...utils import logger, run_ext_cmd
18
+ from ...utils import run_ext_cmd
19
19
  from ...utils.singleton import Singleton
20
+ from ..base import logger
20
21
 
21
22
 
22
23
  if TYPE_CHECKING:
@@ -36,13 +37,15 @@ class AFNIALFF(metaclass=Singleton):
36
37
 
37
38
  _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
38
39
  {
39
- "name": "afni",
40
+ "name": ExtDep.AFNI,
40
41
  "commands": ["3dRSFC", "3dAFNItoNIFTI"],
41
42
  },
42
43
  ]
43
44
 
44
- def __del__(self) -> None:
45
- """Terminate the class."""
45
+ def __init__(self) -> None:
46
+ atexit.register(self._del)
47
+
48
+ def _del(self) -> None:
46
49
  # Clear the computation cache
47
50
  logger.debug("Clearing cache for ALFF computation via AFNI")
48
51
  self.compute.cache_clear()
@@ -53,7 +56,8 @@ class AFNIALFF(metaclass=Singleton):
53
56
  input_path: Path,
54
57
  highpass: float,
55
58
  lowpass: float,
56
- tr: Optional[float],
59
+ tr: float | None,
60
+ mask_path: Path | None = None,
57
61
  ) -> tuple["Nifti1Image", "Nifti1Image", Path, Path]:
58
62
  """Compute ALFF + fALFF map.
59
63
 
@@ -67,6 +71,10 @@ class AFNIALFF(metaclass=Singleton):
67
71
  Lowpass cutoff frequency.
68
72
  tr : positive float, optional
69
73
  The Repetition Time of the BOLD data.
74
+ mask_path : pathlib.Path, optional
75
+ Path to the mask to restrict the computation to. The voxels
76
+ outside the mask are set to 0. If None, all the voxels are used
77
+ (default None).
70
78
 
71
79
  Returns
72
80
  -------
@@ -87,18 +95,23 @@ class AFNIALFF(metaclass=Singleton):
87
95
  prefix="afni_lff"
88
96
  )
89
97
 
90
- # Set 3dRSFC command
98
+ # Set 3dRSFC command; only the parameters are needed, not the
99
+ # bandpassed time series (-no_rs_out)
91
100
  lff_out_path_prefix = element_tempdir / "output"
92
101
  bp_cmd = [
93
102
  "3dRSFC",
94
103
  f"-prefix {lff_out_path_prefix.resolve()}",
95
104
  f"-input {input_path.resolve()}",
96
105
  f"-band {highpass} {lowpass}",
97
- "-no_rsfa -nosat -nodetrend",
106
+ "-no_rsfa -nosat -nodetrend -no_rs_out",
98
107
  ]
99
108
  # Check tr
100
109
  if tr is not None:
101
110
  bp_cmd.append(f"-dt {tr}")
111
+ # Restrict the computation to the mask, which reduces the memory and
112
+ # time used by 3dRSFC
113
+ if mask_path is not None:
114
+ bp_cmd.append(f"-mask {mask_path.resolve()}")
102
115
  # Call 3dRSFC
103
116
  run_ext_cmd(name="3dRSFC", cmd=bp_cmd)
104
117
 
@@ -8,7 +8,6 @@ from pathlib import Path
8
8
  from typing import (
9
9
  TYPE_CHECKING,
10
10
  ClassVar,
11
- Optional,
12
11
  )
13
12
 
14
13
  import nibabel as nib
@@ -18,8 +17,8 @@ from nilearn import image as nimg
18
17
 
19
18
  from ...pipeline import WorkDirManager
20
19
  from ...typing import Dependencies
21
- from ...utils import logger
22
20
  from ...utils.singleton import Singleton
21
+ from ..base import logger
23
22
 
24
23
 
25
24
  if TYPE_CHECKING:
@@ -50,7 +49,8 @@ class JuniferALFF(metaclass=Singleton):
50
49
  input_path: Path,
51
50
  highpass: float,
52
51
  lowpass: float,
53
- tr: Optional[float],
52
+ tr: float | None,
53
+ mask_path: Path | None = None,
54
54
  ) -> tuple["Nifti1Image", "Nifti1Image", Path, Path]:
55
55
  """Compute ALFF + fALFF map.
56
56
 
@@ -64,6 +64,10 @@ class JuniferALFF(metaclass=Singleton):
64
64
  Lowpass cutoff frequency.
65
65
  tr : positive float, optional
66
66
  The Repetition Time of the BOLD data.
67
+ mask_path : pathlib.Path, optional
68
+ Path to the mask to restrict the computation to. The voxels
69
+ outside the mask are set to 0. If None, all the voxels are used
70
+ (default None).
67
71
 
68
72
  Returns
69
73
  -------
@@ -79,47 +83,59 @@ class JuniferALFF(metaclass=Singleton):
79
83
  """
80
84
  logger.debug("Creating cache for ALFF computation via junifer")
81
85
 
82
- # Get scan data
86
+ # Get scan data (no extra copy, don't keep nibabel's cached copy)
83
87
  niimg = nib.load(input_path)
84
- niimg_data = niimg.get_fdata().copy()
88
+ niimg_data = niimg.get_fdata(caching="unchanged")
85
89
  if tr is None:
86
90
  tr = float(niimg.header["pixdim"][4]) # type: ignore
87
91
  logger.info(f"`tr` not provided, using `tr` from header: {tr}")
88
92
 
89
- # Bandpass the data within the lowpass and highpass cutoff freqs
90
- fft_data = sp.fft.fft(niimg_data, axis=-1)
91
- fft_freqs = np.abs(sp.fft.fftfreq(niimg_data.shape[-1], tr))
92
- # Frequency difference
93
- fft_freqs_diff = fft_freqs[1] - fft_freqs[0]
94
- # Nyquist frequency
95
- nyquist = np.max(fft_freqs)
96
- # FFT sample frequency count
97
- n_fft = len(fft_freqs)
93
+ n_timepoints = niimg_data.shape[-1]
94
+ # One-sided spectrum of a real signal; weights reproduce the
95
+ # two-sided sums (each non-zero bin appears twice, Nyquist once)
96
+ fft_freqs = sp.fft.rfftfreq(n_timepoints, tr)
97
+ weights = np.full(fft_freqs.shape, 2.0)
98
+ weights[0] = 0.0 # exclude DC
99
+ if n_timepoints % 2 == 0:
100
+ weights[-1] = 1.0 # Nyquist bin appears only once
101
+ band_weights = np.where(
102
+ (fft_freqs > highpass) & (fft_freqs < lowpass), weights, 0.0
103
+ )
98
104
  logger.info(
99
- f"FFT: nfft = {n_fft}, dFreq = {fft_freqs_diff}, "
100
- f"nyquist = {nyquist}"
105
+ f"FFT: nfft = {n_timepoints}, "
106
+ f"dFreq = {fft_freqs[1] - fft_freqs[0]}, "
107
+ f"nyquist = {fft_freqs[-1]}"
101
108
  )
102
109
 
103
- # Compute the denominator on the broadband signal
104
- all_freq_mask = fft_freqs > 0
105
- denominator = np.sum(np.abs(fft_data[..., all_freq_mask]), axis=-1)
106
-
107
- # Compute the numerator on the bandpassed signal
108
- freq_mask = np.logical_and(fft_freqs > highpass, fft_freqs < lowpass)
109
-
110
- # Compute ALFF
111
- numerator = np.sum(np.abs(fft_data[..., freq_mask]), axis=-1)
110
+ # Process voxels (only the ones in the mask, if any) in chunks to
111
+ # bound FFT memory
112
+ flat = niimg_data.reshape(-1, n_timepoints)
113
+ if mask_path is not None:
114
+ mask_data = np.squeeze(np.asarray(nib.load(mask_path).dataobj))
115
+ voxels = np.flatnonzero(mask_data.reshape(-1) != 0)
116
+ else:
117
+ voxels = np.arange(flat.shape[0])
118
+ numerator = np.zeros(flat.shape[0])
119
+ denominator = np.zeros(flat.shape[0])
120
+ chunk = 20_000
121
+ for start in range(0, len(voxels), chunk):
122
+ t_voxels = voxels[start : start + chunk]
123
+ amp = np.abs(sp.fft.rfft(flat[t_voxels], axis=-1))
124
+ denominator[t_voxels] = amp @ weights
125
+ numerator[t_voxels] = amp @ band_weights
126
+ spatial_shape = niimg_data.shape[:-1]
127
+ numerator = numerator.reshape(spatial_shape)
128
+ denominator = denominator.reshape(spatial_shape)
129
+ del niimg_data, flat
112
130
 
113
131
  # Compute fALFF, but avoid division by zero
114
132
  denom_mask = denominator <= 0.000001
115
- denominator[denom_mask] = 1 # set to 1 to avoid division by zero
116
- # Calculate fALFF
133
+ denominator[denom_mask] = 1
117
134
  falff = np.divide(numerator, denominator)
118
- # Set the values where denominator is zero to zero
119
135
  falff[denom_mask] = 0
120
136
 
121
137
  # Calculate ALFF
122
- alff = numerator / np.sqrt(niimg_data.shape[-1])
138
+ alff = numerator / np.sqrt(n_timepoints)
123
139
  alff_data = nimg.new_img_like(
124
140
  ref_niimg=niimg,
125
141
  data=alff,
@@ -133,8 +149,8 @@ class JuniferALFF(metaclass=Singleton):
133
149
  element_tempdir = WorkDirManager().get_element_tempdir(
134
150
  prefix="junifer_lff"
135
151
  )
136
- output_alff_path = element_tempdir / "output_alff.nii.gz"
137
- output_falff_path = element_tempdir / "output_falff.nii.gz"
152
+ output_alff_path = element_tempdir / "output_alff.nii"
153
+ output_falff_path = element_tempdir / "output_falff.nii"
138
154
  # Save computed data to file
139
155
  nib.save(alff_data, output_alff_path)
140
156
  nib.save(falff_data, output_falff_path)
@@ -6,17 +6,24 @@
6
6
  # Synchon Mandal <s.mandal@fz-juelich.de>
7
7
  # License: AGPL
8
8
 
9
+ from enum import StrEnum
9
10
  from pathlib import Path
10
11
  from typing import (
11
12
  TYPE_CHECKING,
13
+ Annotated,
12
14
  Any,
13
15
  ClassVar,
14
- Optional,
15
16
  )
16
17
 
18
+ from pydantic import BeforeValidator, PositiveFloat
19
+
20
+ from ...data import get_data
21
+ from ...datagrabber import DataType
22
+ from ...storage import StorageType
17
23
  from ...typing import ConditionalDependencies, MarkerInOutMappings
18
- from ...utils.logging import logger, raise_error
19
- from ..base import BaseMarker
24
+ from ...utils import ensure_list_or_none
25
+ from ..base import BaseMarker, logger
26
+ from ..utils import _save_mask
20
27
  from ._afni_falff import AFNIALFF
21
28
  from ._junifer_falff import JuniferALFF
22
29
 
@@ -25,7 +32,19 @@ if TYPE_CHECKING:
25
32
  from nibabel.nifti1 import Nifti1Image
26
33
 
27
34
 
28
- __all__ = ["ALFFBase"]
35
+ __all__ = ["ALFFBase", "ALFFImpl"]
36
+
37
+
38
+ class ALFFImpl(StrEnum):
39
+ """Accepted ALFF implementations.
40
+
41
+ * ``junifer`` : ``junifer``'s ALFF
42
+ * ``afni`` : AFNI's ``3dRSFC``
43
+
44
+ """
45
+
46
+ junifer = "junifer"
47
+ afni = "afni"
29
48
 
30
49
 
31
50
  class ALFFBase(BaseMarker):
@@ -33,22 +52,30 @@ class ALFFBase(BaseMarker):
33
52
 
34
53
  Parameters
35
54
  ----------
36
- highpass : positive float
37
- Highpass cutoff frequency.
38
- lowpass : positive float
39
- Lowpass cutoff frequency.
40
- using : {"junifer", "afni"}
41
- Implementation to use for computing ALFF:
42
-
43
- * "junifer" : Use ``junifer``'s own ALFF implementation
44
- * "afni" : Use AFNI's ``3dRSFC``
45
-
55
+ using : :enum:`.ALFFImpl`
56
+ highpass : positive float, optional
57
+ Highpass cutoff frequency (default 0.01).
58
+ lowpass : positive float, optional
59
+ Lowpass cutoff frequency (default 0.1).
46
60
  tr : positive float, optional
47
- The Repetition Time of the BOLD data. If None, will extract
48
- the TR from NIfTI header (default None).
49
- name : str, optional
50
- The name of the marker. If None, it will use the class name
51
- (default None).
61
+ The repetition time of the BOLD data.
62
+ If None, will extract the TR from NIfTI header (default None).
63
+ agg_method : str, optional
64
+ The aggregation function to use.
65
+ See :func:`.get_aggfunc_by_name` for options
66
+ (default "mean").
67
+ agg_method_params : dict or None, optional
68
+ The parameters to pass to the aggregation function.
69
+ See :func:`.get_aggfunc_by_name` for options (default None).
70
+ masks : str, dict, list of them or None, optional
71
+ The specification of the masks to apply. The ALFF and fALFF
72
+ computation is restricted to the voxels in the mask, and the mask is
73
+ also applied to regions before extracting signals. Check
74
+ :ref:`Using Masks <using_masks>` for more details.
75
+ If None, will not apply any mask (default None).
76
+ name : str or None, optional
77
+ The name of the marker.
78
+ If None, it will use the class name (default None).
52
79
 
53
80
  Notes
54
81
  -----
@@ -58,63 +85,41 @@ class ALFFBase(BaseMarker):
58
85
  reported that some preprocessed data might not have the correct ``tr`` in
59
86
  the NIfTI header.
60
87
 
61
- Raises
62
- ------
63
- ValueError
64
- If ``highpass`` is not positive or zero or
65
- if ``lowpass`` is not positive or
66
- if ``highpass`` is higher than ``lowpass`` or
67
- if ``using`` is invalid.
68
-
69
88
  """
70
89
 
71
90
  _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [
72
91
  {
73
- "using": "afni",
74
- "depends_on": AFNIALFF,
92
+ "using": ALFFImpl.afni,
93
+ "depends_on": [AFNIALFF],
75
94
  },
76
95
  {
77
- "using": "junifer",
78
- "depends_on": JuniferALFF,
96
+ "using": ALFFImpl.junifer,
97
+ "depends_on": [JuniferALFF],
79
98
  },
80
99
  ]
81
100
 
82
101
  _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = {
83
- "BOLD": {
84
- "alff": "vector",
85
- "falff": "vector",
102
+ DataType.BOLD: {
103
+ "alff": StorageType.Vector,
104
+ "falff": StorageType.Vector,
86
105
  },
87
106
  }
88
107
 
89
- def __init__(
90
- self,
91
- highpass: float,
92
- lowpass: float,
93
- using: str,
94
- tr: Optional[float] = None,
95
- name: Optional[str] = None,
96
- ) -> None:
97
- if highpass < 0:
98
- raise_error("Highpass must be positive or 0")
99
- if lowpass <= 0:
100
- raise_error("Lowpass must be positive")
101
- if highpass >= lowpass:
102
- raise_error("Highpass must be lower than lowpass")
103
- self.highpass = highpass
104
- self.lowpass = lowpass
105
- # Validate `using` parameter
106
- valid_using = [dep["using"] for dep in self._CONDITIONAL_DEPENDENCIES]
107
- if using not in valid_using:
108
- raise_error(
109
- f"Invalid value for `using`, should be one of: {valid_using}"
110
- )
111
- self.using = using
112
- self.tr = tr
113
- super().__init__(on="BOLD", name=name)
108
+ using: ALFFImpl
109
+ highpass: PositiveFloat = 0.01
110
+ lowpass: PositiveFloat = 0.1
111
+ tr: PositiveFloat | None = None
112
+ agg_method: str = "mean"
113
+ agg_method_params: dict | None = None
114
+ masks: Annotated[
115
+ dict | str | list[dict | str] | None,
116
+ BeforeValidator(ensure_list_or_none),
117
+ ] = None
114
118
 
115
119
  def _compute(
116
120
  self,
117
121
  input_data: dict[str, Any],
122
+ extra_input: dict[str, Any] | None = None,
118
123
  ) -> tuple["Nifti1Image", "Nifti1Image", Path, Path]:
119
124
  """Compute ALFF and fALFF.
120
125
 
@@ -123,7 +128,8 @@ class ALFFBase(BaseMarker):
123
128
  input_data : dict
124
129
  The input to the marker.
125
130
  extra_input : dict, optional
126
- The other fields in the pipeline data object (default None).
131
+ The other fields in the pipeline data object. Used to compute
132
+ the mask in the space of ``input_data`` (default None).
127
133
 
128
134
  Returns
129
135
  -------
@@ -144,12 +150,26 @@ class ALFFBase(BaseMarker):
144
150
  estimator = AFNIALFF()
145
151
  elif self.using == "junifer":
146
152
  estimator = JuniferALFF()
153
+ # Get mask in the space of the input data
154
+ mask_path = None
155
+ if self.masks is not None:
156
+ logger.debug(f"Masking with {self.masks}")
157
+ mask_path = _save_mask(
158
+ get_data(
159
+ kind="mask",
160
+ names=self.masks,
161
+ target_data=input_data,
162
+ extra_input=extra_input,
163
+ ),
164
+ prefix="alff_mask",
165
+ )
147
166
  # Compute ALFF + fALFF
148
167
  alff, falff, alff_path, falff_path = estimator.compute( # type: ignore
149
168
  input_path=input_data["path"],
150
169
  highpass=self.highpass,
151
170
  lowpass=self.lowpass,
152
171
  tr=self.tr,
172
+ mask_path=mask_path,
153
173
  )
154
174
 
155
175
  # If the input data space is native already, the original path should
@@ -3,10 +3,11 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
- from typing import Any, Optional, Union
6
+ from typing import Any
7
7
 
8
8
  from ...api.decorators import register_marker
9
- from ...utils import logger
9
+ from ...datagrabber import DataType
10
+ from ..base import logger
10
11
  from ..maps_aggregation import MapsAggregation
11
12
  from .falff_base import ALFFBase
12
13
 
@@ -23,27 +24,21 @@ class ALFFMaps(ALFFBase):
23
24
  maps : str
24
25
  The name of the map(s) to use.
25
26
  See :func:`.list_data` for options.
26
- using : {"junifer", "afni"}
27
- Implementation to use for computing ALFF:
28
-
29
- * "junifer" : Use ``junifer``'s own ALFF implementation
30
- * "afni" : Use AFNI's ``3dRSFC``
31
-
27
+ using : :enum:`.ALFFImpl`
32
28
  highpass : positive float, optional
33
- The highpass cutoff frequency for the bandpass filter. If 0,
34
- it will not apply a highpass filter (default 0.01).
29
+ Highpass cutoff frequency (default 0.01).
35
30
  lowpass : positive float, optional
36
- The lowpass cutoff frequency for the bandpass filter (default 0.1).
31
+ Lowpass cutoff frequency (default 0.1).
37
32
  tr : positive float, optional
38
- The Repetition Time of the BOLD data. If None, will extract
39
- the TR from NIfTI header (default None).
40
- masks : str, dict or list of dict or str, optional
33
+ The repetition time of the BOLD data.
34
+ If None, will extract the TR from NIfTI header (default None).
35
+ masks : str, dict, list of them or None, optional
41
36
  The specification of the masks to apply to regions before extracting
42
37
  signals. Check :ref:`Using Masks <using_masks>` for more details.
43
38
  If None, will not apply any mask (default None).
44
- name : str, optional
45
- The name of the marker. If None, will use the class name (default
46
- None).
39
+ name : str or None, optional
40
+ The name of the marker.
41
+ If None, will use the class name (default None).
47
42
 
48
43
  Notes
49
44
  -----
@@ -59,31 +54,12 @@ class ALFFMaps(ALFFBase):
59
54
 
60
55
  """
61
56
 
62
- def __init__(
63
- self,
64
- maps: str,
65
- using: str,
66
- highpass: float = 0.01,
67
- lowpass: float = 0.1,
68
- tr: Optional[float] = None,
69
- masks: Union[str, dict, list[Union[dict, str]], None] = None,
70
- name: Optional[str] = None,
71
- ) -> None:
72
- # Superclass init first to validate `using` parameter
73
- super().__init__(
74
- highpass=highpass,
75
- lowpass=lowpass,
76
- using=using,
77
- tr=tr,
78
- name=name,
79
- )
80
- self.maps = maps
81
- self.masks = masks
57
+ maps: str
82
58
 
83
59
  def compute(
84
60
  self,
85
61
  input: dict[str, Any],
86
- extra_input: Optional[dict[str, Any]] = None,
62
+ extra_input: dict[str, Any] | None = None,
87
63
  ) -> dict[str, Any]:
88
64
  """Compute.
89
65
 
@@ -116,7 +92,7 @@ class ALFFMaps(ALFFBase):
116
92
 
117
93
  # Compute ALFF + fALFF
118
94
  alff_output, falff_output, alff_output_path, falff_output_path = (
119
- self._compute(input_data=input)
95
+ self._compute(input_data=input, extra_input=extra_input)
120
96
  )
121
97
 
122
98
  # Perform aggregation on ALFF + fALFF
@@ -132,7 +108,7 @@ class ALFFMaps(ALFFBase):
132
108
  **MapsAggregation(
133
109
  maps=self.maps,
134
110
  masks=self.masks,
135
- on="BOLD",
111
+ on=DataType.BOLD,
136
112
  ).compute(
137
113
  input=aggregation_alff_input,
138
114
  extra_input=extra_input,
@@ -142,7 +118,7 @@ class ALFFMaps(ALFFBase):
142
118
  **MapsAggregation(
143
119
  maps=self.maps,
144
120
  masks=self.masks,
145
- on="BOLD",
121
+ on=DataType.BOLD,
146
122
  ).compute(
147
123
  input=aggregation_falff_input,
148
124
  extra_input=extra_input,