dti_extractor
tit.pre.qsi.dti_extractor ¶
DTI tensor for SimNIBS, fitted with DIPY on QSIPrep's preprocessed DWI.
Route (DECISIONS.md, 2026-09-27 "DTI via DIPY on QSIPrep output"):
- DIPY
TensorModelWLS fit on the ACPC-space DWI, shells b <= 1500 only, with QSIPrep's.bgradient table (MRtrix convention: scanner/world RAS), so the fitted quadratic form is already a world-frame tensor. - The exact QSIPrep ACPC -> raw-T1 map from QSIPrep's own files
(:func:
tit.pre.qsi.tensor_math.acpc_to_t1_world). A same-modality NCC rigid refinement of QSIPrep's ACPC T1 against the m2m T1 is a QC check, never the map. - Normalised trilinear resampling onto the m2m
T1.nii.gzgrid, every tensor rotated by the polar factor of the map, then a brain mask. - Stored in the frame SimNIBS
cond2elmdata(correct_FSL=True)reads back as the world tensor, besideDTI_coregT1_qc.json. A tensor that fails the QC gate is not written. - Non-blocking advisories and provenance (:mod:
tit.pre.qsi.dti_advisories) join the QC record, and a DTI QC report is always written, on a failed gate too.
No QSIRecon, no DSI Studio.
DtiQc
dataclass
¶
DtiQc(ncc_chain: float, chain_vs_ncc_mm: float, pct_pd: float, pct_wm_covered: float, pct_gm_covered: float, pct_wmgm_zero: float, wm_md_median: float, wm_fa_median: float, n_out_of_brain: int, passed: bool = False, failures: list[str] = list(), acpc_to_t1: list[list[float]] = list(), thresholds: dict = _gate_thresholds())
What DTI_coregT1_qc.json records.
gate ¶
Fill passed/failures from the measured values and thresholds.
Source code in tit/pre/qsi/dti_extractor.py
fit_tensor ¶
fit_tensor(dwi_path: Path, grad_path: Path, mask_path: Path, bmax: float = DTI_BMAX) -> tuple[ndarray, ndarray, ndarray]
DIPY WLS tensor fit on shells b <= bmax.
grad_path is QSIPrep's MRtrix .b table (x y z b per volume, directions in
scanner RAS), so the result is a world-frame tensor field. Returns
(tensors (X, Y, Z, 3, 3), affine, mask), zero outside the mask.
Source code in tit/pre/qsi/dti_extractor.py
read_itk_transform ¶
An ANTs/ITK .mat (as QSIPrep writes it) -> 4x4 RAS point map.
Source code in tit/pre/qsi/dti_extractor.py
check_registration ¶
check_registration(chain: ndarray, acpc_t1: ndarray, acpc_aff: ndarray, acpc_mask: ndarray, m2m_t1: ndarray, m2m_aff: ndarray) -> tuple[float, float]
(NCC under the chain, mean brain displacement chain vs NCC refinement, mm).
Same-modality (QSIPrep's ACPC T1 vs the m2m T1) rigid refinement, Powell on -NCC, started from the chain. Only a QC measurement: the tensor always uses the chain.
Source code in tit/pre/qsi/dti_extractor.py
resample_tensor ¶
resample_tensor(tensors_src: ndarray, src_affine: ndarray, src_valid: ndarray, src_to_tgt: ndarray, tgt_shape, tgt_affine: ndarray, chunk: int = 4000000, min_weight: float = 0.5) -> tuple[ndarray, ndarray]
Pull a world-frame tensor field onto a target grid through the map src_to_tgt.
Components are interpolated trilinearly (order 1, monotone: no spline ringing) as
a normalised convolution over valid voxels (divided by the interpolated validity),
so edge voxels are not shrunk towards zero. Every tensor is then rotated by the
polar factor of src_to_tgt. Returns (tensors (X, Y, Z, 3, 3), valid).
Source code in tit/pre/qsi/dti_extractor.py
qsiprep_inputs ¶
Locate the QSIPrep files the DTI step reads, or raise naming the missing one.
Source code in tit/pre/qsi/dti_extractor.py
run_config ¶
run_config() -> dict
Every setting that can move the tensor or its checks; hashed into the QC record.
Source code in tit/pre/qsi/dti_extractor.py
record_advisories ¶
record_advisories(qc: dict, vols, project_dir: str, subject_id: str, *, recorded_by: str, logger: Logger) -> None
Add advisories, measurements and provenance to a QC record, in place.
Never blocks: a failure is logged and kept as advisories_error, and the QC record and
report are still written.
Source code in tit/pre/qsi/dti_extractor.py
extract_dti_tensor ¶
Fit, register and write DTI_coregT1_tensor.nii.gz for subject_id.
Reads QSIPrep output and the charm m2m folder; writes the tensor and
DTI_coregT1_qc.json into the m2m folder, then a DTI QC report.
Raises¶
tit.pre.utils.PreprocessError Missing inputs, an existing tensor, an m2m T1 that is not the T1w QSIPrep used, or a failed QC gate (the QC JSON and the report are still written; the tensor is not).
Source code in tit/pre/qsi/dti_extractor.py
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 | |
check_dti_tensor_exists ¶
Whether DTI_coregT1_tensor.nii.gz exists in subject_id's m2m folder.