0
# Core Utilities
1
2
Essential utility functions for array manipulation, coordinate transformations, and mathematical operations. DIPY's core utilities provide fundamental building blocks for diffusion MRI analysis and data processing.
3
4
## Capabilities
5
6
### Array and Data Manipulation
7
8
Utility functions for handling arrays, data types, and memory management in diffusion MRI processing.
9
10
```python { .api }
11
def normalize_v3(vec):
12
"""
13
Normalize 3D vectors to unit length.
14
15
Parameters:
16
vec (array): input vectors (..., 3)
17
18
Returns:
19
array: normalized unit vectors
20
"""
21
22
def as_native_array(arr):
23
"""
24
Convert array to native byte order to avoid endianness issues.
25
26
Parameters:
27
arr (array): input array
28
29
Returns:
30
array: array in native byte order
31
"""
32
33
def vec2vec_rotmat(u, v):
34
"""
35
Calculate rotation matrix to align vector u with vector v.
36
37
Parameters:
38
u (array): source vector (3,)
39
v (array): target vector (3,)
40
41
Returns:
42
array: rotation matrix (3, 3)
43
"""
44
45
def vector_norm(vec, axis=-1, keepdims=False):
46
"""
47
Calculate L2 norm of vectors.
48
49
Parameters:
50
vec (array): input vectors
51
axis (int): axis along which to compute norm
52
keepdims (bool): preserve dimensions
53
54
Returns:
55
array: vector norms
56
"""
57
58
def nearest_pos_semi_def(matrix):
59
"""
60
Find nearest positive semi-definite matrix.
61
62
Parameters:
63
matrix (array): input matrix (..., N, N)
64
65
Returns:
66
array: nearest PSD matrix
67
"""
68
```
69
70
### Coordinate System Transformations
71
72
Functions for converting between different coordinate systems and spatial transformations.
73
74
```python { .api }
75
def sphere2cart(r, theta, phi, deg=True):
76
"""
77
Convert spherical to Cartesian coordinates.
78
79
Parameters:
80
r (array): radial distance
81
theta (array): polar angle
82
phi (array): azimuthal angle
83
deg (bool): angles in degrees (True) or radians (False)
84
85
Returns:
86
tuple: (x, y, z) Cartesian coordinates
87
"""
88
89
def cart2sphere(x, y, z, deg=True):
90
"""
91
Convert Cartesian to spherical coordinates.
92
93
Parameters:
94
x (array): x coordinates
95
y (array): y coordinates
96
z (array): z coordinates
97
deg (bool): return angles in degrees
98
99
Returns:
100
tuple: (r, theta, phi) spherical coordinates
101
"""
102
103
def euler_matrix(ai, aj, ak, axes='sxyz'):
104
"""
105
Return homogeneous rotation matrix from Euler angles.
106
107
Parameters:
108
ai (float): rotation about first axis
109
aj (float): rotation about second axis
110
ak (float): rotation about third axis
111
axes (str): axis specification
112
113
Returns:
114
array: rotation matrix (4, 4)
115
"""
116
117
def apply_affine(aff, pts):
118
"""
119
Apply affine transformation to points.
120
121
Parameters:
122
aff (array): affine transformation matrix (4, 4)
123
pts (array): points to transform (..., 3)
124
125
Returns:
126
array: transformed points
127
"""
128
129
def voxel_order(affine):
130
"""
131
Determine voxel ordering from affine matrix.
132
133
Parameters:
134
affine (array): voxel-to-world affine (4, 4)
135
136
Returns:
137
str: voxel order code (e.g., 'RAS', 'LPS')
138
"""
139
```
140
141
### Interpolation and Resampling
142
143
Tools for data interpolation and resampling operations.
144
145
```python { .api }
146
def trilinear_interp(data, indices):
147
"""
148
Trilinear interpolation of 3D data.
149
150
Parameters:
151
data (array): 3D data array
152
indices (array): interpolation coordinates (..., 3)
153
154
Returns:
155
array: interpolated values
156
"""
157
158
def trilinear_interpolate4d(data, indices):
159
"""
160
Trilinear interpolation for 4D data.
161
162
Parameters:
163
data (array): 4D data array
164
indices (array): coordinates for interpolation
165
166
Returns:
167
array: interpolated 4D values
168
"""
169
170
def reslice(data, affine, zooms, new_zooms, order=1):
171
"""
172
Reslice volume to new voxel size.
173
174
Parameters:
175
data (array): input volume
176
affine (array): voxel-to-world transformation
177
zooms (array): current voxel sizes
178
new_zooms (array): target voxel sizes
179
order (int): interpolation order
180
181
Returns:
182
tuple: (resliced_data, new_affine)
183
"""
184
185
class Interpolator:
186
"""Base class for data interpolation."""
187
def __init__(self, data, voxel_size):
188
"""
189
Initialize interpolator.
190
191
Parameters:
192
data (array): data to interpolate
193
voxel_size (array): voxel dimensions
194
"""
195
196
def __call__(self, coordinates):
197
"""Interpolate at given coordinates."""
198
```
199
200
### Statistical and Mathematical Utilities
201
202
Mathematical functions and statistical tools for diffusion analysis.
203
204
```python { .api }
205
def auto_attr(func):
206
"""
207
Decorator for automatic attribute caching.
208
209
Parameters:
210
func (callable): function to decorate
211
212
Returns:
213
callable: decorated function with caching
214
"""
215
216
def multi_voxel_fit(single_voxel_func):
217
"""
218
Decorator to extend single-voxel functions to multi-voxel data.
219
220
Parameters:
221
single_voxel_func (callable): single voxel fitting function
222
223
Returns:
224
callable: multi-voxel version of function
225
"""
226
227
def optional_package(name, trip_msg=None):
228
"""
229
Return package or None with optional warning.
230
231
Parameters:
232
name (str): package name
233
trip_msg (str): message if package not found
234
235
Returns:
236
module or None: imported package or None
237
"""
238
239
def warn_issue(issue_no, message):
240
"""
241
Issue warning with GitHub issue reference.
242
243
Parameters:
244
issue_no (int): GitHub issue number
245
message (str): warning message
246
"""
247
248
def floating_point_precision(dtype):
249
"""
250
Get floating point precision information.
251
252
Parameters:
253
dtype: numpy data type
254
255
Returns:
256
dict: precision information
257
"""
258
```
259
260
### Memory and Performance Utilities
261
262
Tools for memory management and performance optimization.
263
264
```python { .api }
265
def chunk_size(data_shape, chunk_mb=100):
266
"""
267
Calculate optimal chunk size for processing.
268
269
Parameters:
270
data_shape (tuple): shape of data array
271
chunk_mb (float): target chunk size in MB
272
273
Returns:
274
int: optimal chunk size
275
"""
276
277
def memory_usage():
278
"""
279
Get current memory usage information.
280
281
Returns:
282
dict: memory usage statistics
283
"""
284
285
class ProgressBar:
286
"""Simple progress bar for long operations."""
287
def __init__(self, total, desc='Processing'):
288
"""
289
Initialize progress bar.
290
291
Parameters:
292
total (int): total number of steps
293
desc (str): description text
294
"""
295
296
def update(self, n=1):
297
"""Update progress by n steps."""
298
299
def close(self):
300
"""Close progress bar."""
301
302
def time_operation(func):
303
"""
304
Decorator to time function execution.
305
306
Parameters:
307
func (callable): function to time
308
309
Returns:
310
callable: timed function
311
"""
312
```
313
314
### File and Path Utilities
315
316
Utilities for file handling, path manipulation, and data I/O operations.
317
318
```python { .api }
319
def ensure_dir_exists(path):
320
"""
321
Ensure directory exists, create if necessary.
322
323
Parameters:
324
path (str): directory path
325
326
Returns:
327
str: absolute directory path
328
"""
329
330
def get_file_extension(filename):
331
"""
332
Get file extension handling compressed files.
333
334
Parameters:
335
filename (str): file name or path
336
337
Returns:
338
str: file extension
339
"""
340
341
def split_filename(filename):
342
"""
343
Split filename into components.
344
345
Parameters:
346
filename (str): file name or path
347
348
Returns:
349
tuple: (directory, basename, extension)
350
"""
351
352
def check_file_exists(filename, raise_error=True):
353
"""
354
Check if file exists with optional error raising.
355
356
Parameters:
357
filename (str): file path to check
358
raise_error (bool): raise error if file doesn't exist
359
360
Returns:
361
bool: True if file exists
362
"""
363
364
def get_data_dims(filename):
365
"""
366
Get dimensions of data file without loading.
367
368
Parameters:
369
filename (str): path to data file
370
371
Returns:
372
tuple: data dimensions
373
"""
374
```
375
376
### Random Number Generation
377
378
Utilities for reproducible random number generation in scientific computing.
379
380
```python { .api }
381
class RandomState:
382
"""Thread-safe random number generator."""
383
def __init__(self, seed=None):
384
"""
385
Initialize random state.
386
387
Parameters:
388
seed (int): random seed for reproducibility
389
"""
390
391
def uniform(self, low=0.0, high=1.0, size=None):
392
"""Generate uniform random numbers."""
393
394
def normal(self, loc=0.0, scale=1.0, size=None):
395
"""Generate normal random numbers."""
396
397
def randint(self, low, high, size=None):
398
"""Generate random integers."""
399
400
def choice(self, a, size=None, replace=True, p=None):
401
"""Random sampling from array."""
402
403
def set_random_number_generator(seed):
404
"""
405
Set global random seed for reproducibility.
406
407
Parameters:
408
seed (int): random seed value
409
"""
410
411
def get_random_state():
412
"""Get current random state."""
413
```
414
415
### Validation and Testing Utilities
416
417
Tools for data validation, testing, and quality assurance.
418
419
```python { .api }
420
def is_hemispherical(vectors):
421
"""
422
Check if vectors are hemispherical.
423
424
Parameters:
425
vectors (array): vectors to check (..., 3)
426
427
Returns:
428
bool: True if vectors are hemispherical
429
"""
430
431
def validate_gtab(gtab):
432
"""
433
Validate gradient table consistency.
434
435
Parameters:
436
gtab (GradientTable): gradient table to validate
437
438
Returns:
439
dict: validation results and warnings
440
"""
441
442
def check_multi_b(gtab, n_shells=None, tol=20):
443
"""
444
Check if gradient table has multiple b-value shells.
445
446
Parameters:
447
gtab (GradientTable): gradient table
448
n_shells (int): expected number of shells
449
tol (float): tolerance for b-value grouping
450
451
Returns:
452
tuple: (is_multi_b, shell_info)
453
"""
454
455
def assert_arrays_equal(arr1, arr2, rtol=1e-5, atol=1e-8):
456
"""
457
Assert arrays are equal within tolerance.
458
459
Parameters:
460
arr1 (array): first array
461
arr2 (array): second array
462
rtol (float): relative tolerance
463
atol (float): absolute tolerance
464
"""
465
466
class TempDirectory:
467
"""Context manager for temporary directories."""
468
def __init__(self, suffix='', prefix='dipy_'):
469
"""Initialize temporary directory context."""
470
471
def __enter__(self):
472
"""Enter context and create directory."""
473
474
def __exit__(self, exc_type, exc_val, exc_tb):
475
"""Exit context and cleanup directory."""
476
```
477
478
### Usage Examples
479
480
```python
481
# Array manipulation examples
482
from dipy.utils.arrfuncs import normalize_v3, as_native_array, vector_norm
483
import numpy as np
484
485
# Normalize vectors
486
vectors = np.random.randn(100, 3)
487
unit_vectors = normalize_v3(vectors)
488
norms = vector_norm(unit_vectors)
489
print(f"Unit vector norms: min={norms.min():.6f}, max={norms.max():.6f}")
490
491
# Handle byte order issues
492
big_endian_array = np.array([1.0, 2.0, 3.0], dtype='>f4') # Big endian
493
native_array = as_native_array(big_endian_array)
494
print(f"Original dtype: {big_endian_array.dtype}")
495
print(f"Native dtype: {native_array.dtype}")
496
497
# Coordinate transformations
498
from dipy.core.geometry import sphere2cart, cart2sphere
499
500
# Convert spherical to Cartesian
501
theta = np.linspace(0, 180, 10) # Polar angle
502
phi = np.linspace(0, 360, 20) # Azimuthal angle
503
r = 1.0
504
505
theta_grid, phi_grid = np.meshgrid(theta, phi, indexing='ij')
506
x, y, z = sphere2cart(r, theta_grid, phi_grid, deg=True)
507
508
# Convert back to spherical
509
r_back, theta_back, phi_back = cart2sphere(x, y, z, deg=True)
510
511
print(f"Coordinate conversion accuracy:")
512
print(f" Theta error: {np.abs(theta_grid - theta_back).max():.10f}")
513
print(f" Phi error: {np.abs(phi_grid - phi_back).max():.10f}")
514
515
# Interpolation example
516
from dipy.core.interpolation import trilinear_interp
517
from dipy.data import read_stanford_hardi
518
519
# Load example data
520
img, gtab = read_stanford_hardi()
521
data = img.get_fdata()
522
523
# Interpolate at fractional coordinates
524
coords = np.array([[10.5, 15.7, 8.3], [20.2, 25.1, 12.8]])
525
interpolated = trilinear_interp(data[..., 0], coords) # Interpolate b=0 volume
526
527
print(f"Interpolated values at fractional coordinates: {interpolated}")
528
529
# Random number generation for reproducibility
530
from dipy.utils.rng import RandomState
531
532
# Create reproducible random state
533
rng = RandomState(seed=42)
534
535
# Generate reproducible random data
536
random_data1 = rng.normal(0, 1, size=(5, 3))
537
rng = RandomState(seed=42) # Reset with same seed
538
random_data2 = rng.normal(0, 1, size=(5, 3))
539
540
print(f"Reproducible random generation: {np.allclose(random_data1, random_data2)}")
541
542
# File and path utilities
543
from dipy.utils.pathutils import ensure_dir_exists, get_file_extension, split_filename
544
545
# Ensure output directory exists
546
output_dir = ensure_dir_exists('./analysis_results')
547
print(f"Output directory: {output_dir}")
548
549
# Handle file extensions
550
filename = 'data.nii.gz'
551
extension = get_file_extension(filename)
552
directory, basename, ext = split_filename(filename)
553
554
print(f"File: {filename}")
555
print(f" Extension: {extension}")
556
print(f" Components: dir='{directory}', base='{basename}', ext='{ext}'")
557
558
# Progress tracking for long operations
559
from dipy.utils.progress import ProgressBar
560
import time
561
562
# Simulate long processing with progress bar
563
n_items = 100
564
pbar = ProgressBar(n_items, desc='Processing data')
565
566
for i in range(n_items):
567
# Simulate work
568
time.sleep(0.01)
569
pbar.update()
570
571
pbar.close()
572
print("Processing completed")
573
574
# Validation utilities
575
from dipy.utils.validation import validate_gtab, check_multi_b
576
577
# Validate gradient table
578
validation_results = validate_gtab(gtab)
579
is_multi_b, shell_info = check_multi_b(gtab)
580
581
print(f"Gradient table validation: {validation_results}")
582
print(f"Multi-shell data: {is_multi_b}")
583
if is_multi_b:
584
print(f"Shell information: {shell_info}")
585
586
# Memory and performance monitoring
587
from dipy.utils.memory import memory_usage, chunk_size
588
589
# Get memory usage
590
mem_info = memory_usage()
591
print(f"Memory usage: {mem_info}")
592
593
# Calculate optimal chunk size for processing
594
data_shape = data.shape
595
optimal_chunk = chunk_size(data_shape, chunk_mb=50)
596
print(f"Optimal chunk size for {data_shape}: {optimal_chunk}")
597
598
# Temporary directory context
599
from dipy.utils.tempdir import TempDirectory
600
601
# Use temporary directory for intermediate results
602
with TempDirectory(prefix='dipy_temp_') as temp_dir:
603
temp_file = temp_dir / 'intermediate_result.npy'
604
np.save(temp_file, random_data1)
605
606
# File exists within context
607
print(f"Temp file exists: {temp_file.exists()}")
608
609
# File is automatically cleaned up after context
610
print("Temporary directory cleaned up automatically")
611
612
# Mathematical utilities
613
from dipy.utils.decorators import auto_attr
614
615
class ExampleClass:
616
"""Example class using auto_attr decorator."""
617
618
def __init__(self, data):
619
self.data = data
620
621
@auto_attr
622
def expensive_computation(self):
623
"""Expensive computation cached automatically."""
624
print("Computing expensive result...")
625
return np.sum(self.data ** 2)
626
627
# Demonstrate caching
628
example = ExampleClass(np.random.randn(1000000))
629
result1 = example.expensive_computation # Computed
630
result2 = example.expensive_computation # Cached
631
print(f"Results equal: {result1 == result2}")
632
```