Skip to main content

A Python library for IVIM diffusion MRI model fitting

Project description

IVIMfit

IVIMfit is a modular Python library designed to fit intravoxel incoherent motion (IVIM) models to diffusion-weighted MRI (DWI) signals. It includes support for monoexponential, biexponential (free and segmented), triexponential, and Bayesian model fitting. The package is designed for use in clinical and research settings, allowing users to extract physiologically meaningful diffusion parameters from DWI datasets. User can generate synhtethic data.


📦 Installation

Install from source:

git clone https://github.com/Atakanisik/IVIMfit
cd IVIMfit
pip install -e .

Install from pip:

pip install ivimfit

Requirements:

  • numpy
  • scipy
  • matplotlib
  • pymc
  • pytensor

Supported Models

Monoexponential (ADC)

$$ S(b) = S_0 \cdot e^{-b \cdot ADC} $$

import numpy as np
import matplotlib.pyplot as plt
from ivimfit.utils import plot_fit, calculate_r_squared
from ivimfit.adc import fit_adc, monoexp_model

b = np.array([0, 50, 100, 200, 400, 600, 800])
s = np.array([800, 654,543,423,328,236,121])

adc = fit_adc(b, s)
r2 = calculate_r_squared(s / s[0], monoexp_model(b, adc))

fig, ax = plot_fit(b, s, monoexp_model, [adc], model_name=f"ADC Fit (R² = {r2:.4f})")
plt.show()

Biexponential (Free Fit)

$$ S(b)/S_0 = f \cdot e^{-b D^*} + (1-f) \cdot e^{-b D} $$

import numpy as np
import matplotlib.pyplot as plt
from ivimfit.utils import plot_fit, calculate_r_squared
from ivimfit.biexp import fit_biexp_free, biexp_model

b = np.array([0, 50, 100, 200, 400, 600, 800])
s = np.array([800, 654,543,423,328,236,121])

f, D, D_star = fit_biexp_free(b, s)
r2 = calculate_r_squared(s / s[0], biexp_model(b, f, D, D_star))

fig, ax = plot_fit(b, s, biexp_model, [f, D, D_star], model_name=f"Free Fit (R² = {r2:.4f})")
plt.show()

Biexponential (Segmented Fit)

  • Estimates $D$ using high-b values (b>=200 default)
  • Then fits $f$, $D^*$ with fixed $D$
import numpy as np
import matplotlib.pyplot as plt
from ivimfit.utils import plot_fit, calculate_r_squared
from ivimfit.segmented import fit_biexp_segmented, biexp_fixed_D_model

b = np.array([0, 50, 100, 200, 400, 600, 800])
s = np.array([800, 654,543,423,328,236,121])

f, D_fixed, D_star = fit_biexp_segmented(b, s)
r2 = calculate_r_squared(s / s[0], biexp_fixed_D_model(b, f, D_star, D_fixed))

fig, ax = plot_fit(
    b, s,
    lambda b_, f_, D_star_,D_fixed: biexp_fixed_D_model(b_, f_, D_star_, D_fixed),
    [f, D_star,D_fixed],
    model_name=f"Segmented Fit (R² = {r2:.4f})"
)
plt.show()

Triexponential

S(b)/S₀ = f₁ · exp(–b · D₁*) + f₂ · exp(–b · D₂*) + (1 – f₁ – f₂) · exp(–b · D)

import numpy as np
import matplotlib.pyplot as plt
from ivimfit.utils import plot_fit, calculate_r_squared
from ivimfit.triexp import fit_triexp_free, triexp_model

b = np.array([0, 50, 100, 200, 400, 600, 800])
s = np.array([800, 654,543,423,328,236,121])
f1, f2, D, D1_star, D2_star = fit_triexp_free(b, s)
pred = triexp_model(b, f1, f2, D, D1_star, D2_star)
r2 = calculate_r_squared(s / s[0], pred)

fig, ax = plot_fit(b, s, triexp_model, [f1, f2, D, D1_star, D2_star], model_name=f"Tri-exponential Fit (R² = {r2:.4f})")
plt.show()

Bayesian (MCMC)

import numpy as np
import matplotlib.pyplot as plt
from ivimfit.utils import plot_fit, calculate_r_squared
from ivimfit.bayesian import fit_bayesian
from ivimfit.biexp import biexp_model

b = np.array([0, 50, 100, 200, 400, 600, 800])
s = np.array([800, 654,543,423,328,236,121])

if __name__ == "__main__":
    f, D, D_star = fit_bayesian(b, s, draws=500, chains=2)
    r2 = calculate_r_squared(s / s[0], biexp_model(b, f, D, D_star))

    fig, ax = plot_fit(b, s, biexp_model, [f, D, D_star], model_name=f"Bayesian Fit (R² = {r2:.4f})")
    plt.show()

Returns posterior mean estimates for $f$, $D$, and $D^*$.


Whole Package Example Usage

# example.py
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle

from ivimfit.synthetic import PhantomParams, generate_measure_signals
from ivimfit.utils import plot_fit, calculate_r_squared
from ivimfit.adc import fit_adc, monoexp_model
from ivimfit.biexp import fit_biexp_free, biexp_model
from ivimfit.segmented import fit_biexp_segmented, biexp_fixed_D_model

def main():
    
    b = np.array([0, 50, 100, 200, 400, 600, 800,900,1000], dtype=float)

    pp = PhantomParams(
        shape=(128, 128),
        square_size=64,
        s0_bright=1.0,
        s0_dark=0.30,
        D_bright=0.0015,
        D_dark=0.0030,
        noise_sigma=0.02
    )

    stack, s, roi = generate_measure_signals(b, params=pp, seed=123)
    r0, c0, size = roi

    
    img0 = stack[np.argmin(b)]
    plt.imshow(img0, cmap="gray", origin="upper")
    plt.gca().add_patch(Rectangle((c0, r0), size, size, fill=False, linewidth=2))
    plt.title("b (en düşük) + ROI")
    plt.show()
    from ivimfit.synthetic import show_stack_grid


    show_stack_grid(stack, b, roi=roi, cols=4, suptitle="Synthetic DWI (low b → high b)")
   
    adc = fit_adc(b, s)
    r2 = calculate_r_squared(s / s[0], monoexp_model(b, adc))
    fig, ax = plot_fit(b, s, monoexp_model, [adc], model_name=f"ADC Fit (R² = {r2:.4f})")
    plt.show()

   
    f, D, D_star = fit_biexp_free(b, s)
    r2 = calculate_r_squared(s / s[0], biexp_model(b, f, D, D_star))
    fig, ax = plot_fit(b, s, biexp_model, [f, D, D_star], model_name=f"Free Fit (R² = {r2:.4f})")
    plt.show()

    
    f_seg, D_fixed, D_star_seg = fit_biexp_segmented(b, s)
    r2 = calculate_r_squared(s / s[0], biexp_fixed_D_model(b, f_seg, D_star_seg, D_fixed))
    fig, ax = plot_fit(
        b, s,
        lambda b_, f_, D_star_, D_fixed_: biexp_fixed_D_model(b_, f_, D_star_, D_fixed_),
        [f_seg, D_star_seg, D_fixed],
        model_name=f"Segmented Fit (R² = {r2:.4f})"
    )
    plt.show()
   
    
    try:
        from ivimfit.bayesian import fit_bayesian
        f_bay, D_bay, Dstar_bay = fit_bayesian(
            b, s, draws=500, chains=2
        )
        r2 = calculate_r_squared(s / s[0], biexp_model(b, f_bay, D_bay, Dstar_bay))
        fig, ax = plot_fit(b, s, biexp_model, [f_bay, D_bay, Dstar_bay],
                           model_name=f"Bayesian Fit (R² = {r2:.4f})")
        plt.show()
    except Exception as e:
        print("[Bayesian] atlandı:", repr(e))

    
    try:
        from ivimfit.triexp import fit_triexp_free, triexp_model
        f1, f2, Dm, D1s, D2s = fit_triexp_free(b, s)
        pred = triexp_model(b, f1, f2, Dm, D1s, D2s)
        r2 = calculate_r_squared(s / s[0], pred)
        fig, ax = plot_fit(b, s, triexp_model, [f1, f2, Dm, D1s, D2s],
                           model_name=f"Tri-exponential Fit (R² = {r2:.4f})")
        plt.show()
    except Exception as e:
        print("[Triexponential] atlandı:", repr(e))

if __name__ == "__main__":
    main()

License

This project is licensed under the MIT License.


Contributing

Pull requests are welcome. Please open an issue to discuss your proposed change before submitting a PR.


Acknowledgements

This work was inspired by previous IVIM modeling efforts, including:

  • ivim by Jalnefjord et al.
  • PyMC Bayesian modeling
  • Research on segmented and triexponential IVIM models in liver and kidney imaging

Citation: If you use IVIMfit, please cite it using the following DOI: DOI

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ivimfit-0.1.7.2.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ivimfit-0.1.7.2-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

Details for the file ivimfit-0.1.7.2.tar.gz.

File metadata

  • Download URL: ivimfit-0.1.7.2.tar.gz
  • Upload date:
  • Size: 12.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for ivimfit-0.1.7.2.tar.gz
Algorithm Hash digest
SHA256 36fa8b1859ecb546dd5f241b871f1eca086f8ebdc5922bb06c444c6b48134806
MD5 0830b8ed18f6f656e7d89cf30cb41ae5
BLAKE2b-256 f00a640579d0f032ee7072efe839c82666914e8bbd4ad6490f63638a07fef56d

See more details on using hashes here.

File details

Details for the file ivimfit-0.1.7.2-py3-none-any.whl.

File metadata

  • Download URL: ivimfit-0.1.7.2-py3-none-any.whl
  • Upload date:
  • Size: 13.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for ivimfit-0.1.7.2-py3-none-any.whl
Algorithm Hash digest
SHA256 747397f1890a1ce144c60b580c74566efe6770ddf3eb23f8bebdc68d4e0eaa81
MD5 0ae72ace7f833f97e5e6672eae080020
BLAKE2b-256 7c2562d2f73d5ce8c4d4c9aac738251de9325c2577233d65dfc12b31ea3d9631

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page