diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..c1fefa2
Binary files /dev/null and b/.DS_Store differ
diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml
old mode 100644
new mode 100755
diff --git a/.github/workflows/pytest-actions.yaml b/.github/workflows/pytest-actions.yaml
old mode 100644
new mode 100755
diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
diff --git a/.idea/.gitignore b/.idea/.gitignore
old mode 100644
new mode 100755
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
old mode 100644
new mode 100755
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
old mode 100644
new mode 100755
diff --git a/.idea/misc.xml b/.idea/misc.xml
old mode 100644
new mode 100755
diff --git a/.idea/modules.xml b/.idea/modules.xml
old mode 100644
new mode 100755
diff --git a/.idea/other.xml b/.idea/other.xml
old mode 100644
new mode 100755
diff --git a/.idea/pypi.iml b/.idea/pypi.iml
old mode 100644
new mode 100755
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
old mode 100644
new mode 100755
diff --git a/LICENSE b/LICENSE
old mode 100644
new mode 100755
diff --git a/README.md b/README.md
old mode 100644
new mode 100755
diff --git a/docs/.DS_Store b/docs/.DS_Store
index b8af6b3..e8fcb8c 100644
Binary files a/docs/.DS_Store and b/docs/.DS_Store differ
diff --git a/docs/Makefile b/docs/Makefile
old mode 100644
new mode 100755
diff --git a/docs/examples/.DS_Store b/docs/examples/.DS_Store
new file mode 100644
index 0000000..6f81a2f
Binary files /dev/null and b/docs/examples/.DS_Store differ
diff --git a/docs/examples/README.rst b/docs/examples/README.rst
old mode 100644
new mode 100755
diff --git a/docs/examples/aif/README.rst b/docs/examples/aif/README.rst
old mode 100644
new mode 100755
diff --git a/docs/examples/aif/plot_aif_parker.py b/docs/examples/aif/plot_aif_parker.py
old mode 100644
new mode 100755
diff --git a/docs/examples/aif/plot_dummy.py b/docs/examples/aif/plot_dummy.py
old mode 100644
new mode 100755
diff --git a/docs/examples/tissue/README.rst b/docs/examples/tissue/README.rst
old mode 100644
new mode 100755
diff --git a/docs/examples/tissue/plot_extended_tofts.py b/docs/examples/tissue/plot_extended_tofts.py
new file mode 100755
index 0000000..a4c60d3
--- /dev/null
+++ b/docs/examples/tissue/plot_extended_tofts.py
@@ -0,0 +1,53 @@
+"""
+====================
+The Extended Tofts model
+====================
+
+Simulating tissue concentrations from extended Tofts model with different settings.
+"""
+
+# %%
+# Import necessary packages
+import numpy as np
+import matplotlib.pyplot as plt
+import osipi
+
+# %%
+# Generate Parker AIF with default settings.
+
+# Define time points in units of seconds - in this case we use a time resolution of 1 sec and a total duration of 6 minutes.
+t = np.arange(0, 6*60, 1)
+
+# Create an AIF with default settings
+ca = osipi.aif_parker(t)
+
+# %%
+# Plot the tissue concentrations for an extracellular volume fraction of 0.2 and 3 different plasma volumes of 0.05, 0.2 and 0.6
+Ktrans = 0.2 # in units of 1/min
+ve = 0.2 # volume fraction between 0 and 1
+vp = [0.05, 0.2, 0.6] # volume fraction between 0 and 1
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0])
+plt.plot(t, ct, 'b-', label=f'vp = {vp[0]}')
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[1])
+plt.plot(t, ct, 'g-', label=f'vp = {vp[1]}')
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[2])
+plt.plot(t, ct, 'm-', label=f'vp = {vp[2]}')
+plt.xlabel('Time (sec)')
+plt.ylabel('Tissue concentration (mM)')
+plt.legend()
+plt.show()
+
+# %%
+# Comparing different discretization methods for an extracellular volume fraction of 0.2, Ktrans of 0.2 /min and vp of 0.05
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0]) # Defaults to Convolution
+plt.plot(t, ct, 'b-', label='Convolution')
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0], discretization_method='exp')
+plt.plot(t, ct, 'g-', label='Exponential Convolution')
+plt.title(f'Ktrans = {Ktrans} /min')
+plt.xlabel('Time (sec)')
+plt.ylabel('Tissue concentration (mM)')
+plt.legend()
+plt.show()
+
+# Choose the last image as a thumbnail for the gallery
+# sphinx_gallery_thumbnail_number = -1
diff --git a/docs/examples/tissue/plot_tofts.py b/docs/examples/tissue/plot_tofts.py
old mode 100644
new mode 100755
diff --git a/docs/make.bat b/docs/make.bat
old mode 100644
new mode 100755
diff --git a/docs/requirements.txt b/docs/requirements.txt
old mode 100644
new mode 100755
diff --git a/docs/source/.DS_Store b/docs/source/.DS_Store
index 5008ddf..74823c7 100644
Binary files a/docs/source/.DS_Store and b/docs/source/.DS_Store differ
diff --git a/docs/source/_static/osipi.png b/docs/source/_static/osipi.png
old mode 100644
new mode 100755
diff --git a/docs/source/_templates/autosummary.rst b/docs/source/_templates/autosummary.rst
old mode 100644
new mode 100755
diff --git a/docs/source/about/index.rst b/docs/source/about/index.rst
old mode 100644
new mode 100755
diff --git a/docs/source/conf.py b/docs/source/conf.py
old mode 100644
new mode 100755
diff --git a/docs/source/developers_guide/index.rst b/docs/source/developers_guide/index.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/.DS_Store b/docs/source/generated/.DS_Store
index e717588..6e4d486 100644
Binary files a/docs/source/generated/.DS_Store and b/docs/source/generated/.DS_Store differ
diff --git a/docs/source/generated/api/osipi.aif_georgiou.rst b/docs/source/generated/api/osipi.aif_georgiou.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/api/osipi.aif_parker.rst b/docs/source/generated/api/osipi.aif_parker.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/api/osipi.aif_weinmann.rst b/docs/source/generated/api/osipi.aif_weinmann.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/api/osipi.extended_tofts.rst b/docs/source/generated/api/osipi.extended_tofts.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/api/osipi.tofts.rst b/docs/source/generated/api/osipi.tofts.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/backreferences/osipi.aif_georgiou.examples b/docs/source/generated/backreferences/osipi.aif_georgiou.examples
old mode 100644
new mode 100755
diff --git a/docs/source/generated/backreferences/osipi.aif_parker.examples b/docs/source/generated/backreferences/osipi.aif_parker.examples
old mode 100644
new mode 100755
index 955d535..e0b9646
--- a/docs/source/generated/backreferences/osipi.aif_parker.examples
+++ b/docs/source/generated/backreferences/osipi.aif_parker.examples
@@ -14,66 +14,24 @@ Examples using ``osipi.aif_parker``
.. raw:: html
-
+
.. only:: html
- .. image:: /generated/examples/aif/images/thumb/sphx_glr_plot_aif_parker_thumb.png
+ .. image:: /generated/examples/tissue/images/thumb/sphx_glr_plot_extended_tofts_thumb.png
:alt:
- :ref:`sphx_glr_generated_examples_aif_plot_aif_parker.py`
+ :ref:`sphx_glr_generated_examples_tissue_plot_extended_tofts.py`
.. raw:: html
-
The Parker AIF - a play with variables
+
The Extended Tofts model
.. only:: not html
- * :ref:`sphx_glr_generated_examples_aif_plot_aif_parker.py`
-
-.. raw:: html
-
-
-
-.. only:: html
-
- .. image:: /generated/examples/aif/images/thumb/sphx_glr_plot_dummy_thumb.png
- :alt:
-
- :ref:`sphx_glr_generated_examples_aif_plot_dummy.py`
-
-.. raw:: html
-
-
A dummy script
-
-
-
-.. only:: not html
-
- * :ref:`sphx_glr_generated_examples_aif_plot_dummy.py`
-
-.. raw:: html
-
-
-
-.. only:: html
-
- .. image:: /generated/examples/tissue/images/thumb/sphx_glr_plot_tofts_thumb.png
- :alt:
-
- :ref:`sphx_glr_generated_examples_tissue_plot_tofts.py`
-
-.. raw:: html
-
-
The Tofts model
-
-
-
-.. only:: not html
-
- * :ref:`sphx_glr_generated_examples_tissue_plot_tofts.py`
+ * :ref:`sphx_glr_generated_examples_tissue_plot_extended_tofts.py`
.. raw:: html
diff --git a/docs/source/generated/backreferences/osipi.aif_weinmann.examples b/docs/source/generated/backreferences/osipi.aif_weinmann.examples
old mode 100644
new mode 100755
diff --git a/docs/source/generated/backreferences/osipi.extended_tofts.examples b/docs/source/generated/backreferences/osipi.extended_tofts.examples
old mode 100644
new mode 100755
index e69de29..9fb76fd
--- a/docs/source/generated/backreferences/osipi.extended_tofts.examples
+++ b/docs/source/generated/backreferences/osipi.extended_tofts.examples
@@ -0,0 +1,39 @@
+
+
+Examples using ``osipi.extended_tofts``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+.. start-sphx-glr-thumbnails
+
+
+.. raw:: html
+
+
+
+
+.. raw:: html
+
+
+
+.. only:: html
+
+ .. image:: /generated/examples/tissue/images/thumb/sphx_glr_plot_extended_tofts_thumb.png
+ :alt:
+
+ :ref:`sphx_glr_generated_examples_tissue_plot_extended_tofts.py`
+
+.. raw:: html
+
+
The Extended Tofts model
+
+
+
+.. only:: not html
+
+ * :ref:`sphx_glr_generated_examples_tissue_plot_extended_tofts.py`
+
+.. raw:: html
+
+
+
diff --git a/docs/source/generated/backreferences/osipi.tofts.examples b/docs/source/generated/backreferences/osipi.tofts.examples
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/images/sphx_glr_plot_aif_parker_001.png b/docs/source/generated/examples/aif/images/sphx_glr_plot_aif_parker_001.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/images/sphx_glr_plot_aif_parker_002.png b/docs/source/generated/examples/aif/images/sphx_glr_plot_aif_parker_002.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/images/sphx_glr_plot_dummy_001.png b/docs/source/generated/examples/aif/images/sphx_glr_plot_dummy_001.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/images/sphx_glr_plot_dummy_002.png b/docs/source/generated/examples/aif/images/sphx_glr_plot_dummy_002.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/images/thumb/sphx_glr_plot_aif_parker_thumb.png b/docs/source/generated/examples/aif/images/thumb/sphx_glr_plot_aif_parker_thumb.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/images/thumb/sphx_glr_plot_dummy_thumb.png b/docs/source/generated/examples/aif/images/thumb/sphx_glr_plot_dummy_thumb.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/index.rst b/docs/source/generated/examples/aif/index.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_aif_parker.ipynb b/docs/source/generated/examples/aif/plot_aif_parker.ipynb
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_aif_parker.py b/docs/source/generated/examples/aif/plot_aif_parker.py
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_aif_parker.py.md5 b/docs/source/generated/examples/aif/plot_aif_parker.py.md5
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_aif_parker.rst b/docs/source/generated/examples/aif/plot_aif_parker.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_aif_parker_codeobj.pickle b/docs/source/generated/examples/aif/plot_aif_parker_codeobj.pickle
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_dummy.ipynb b/docs/source/generated/examples/aif/plot_dummy.ipynb
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_dummy.py b/docs/source/generated/examples/aif/plot_dummy.py
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_dummy.py.md5 b/docs/source/generated/examples/aif/plot_dummy.py.md5
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_dummy.rst b/docs/source/generated/examples/aif/plot_dummy.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/plot_dummy_codeobj.pickle b/docs/source/generated/examples/aif/plot_dummy_codeobj.pickle
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/aif/sg_execution_times.rst b/docs/source/generated/examples/aif/sg_execution_times.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/index.rst b/docs/source/generated/examples/index.rst
old mode 100644
new mode 100755
index e805eb2..8172642
--- a/docs/source/generated/examples/index.rst
+++ b/docs/source/generated/examples/index.rst
@@ -100,6 +100,23 @@ Tissue concentrations
+.. raw:: html
+
+
+
+.. only:: html
+
+ .. image:: /generated/examples/tissue/images/thumb/sphx_glr_plot_extended_tofts_thumb.png
+ :alt:
+
+ :ref:`sphx_glr_generated_examples_tissue_plot_extended_tofts.py`
+
+.. raw:: html
+
+
The Extended Tofts model
+
+
+
.. raw:: html
diff --git a/docs/source/generated/examples/sg_execution_times.rst b/docs/source/generated/examples/sg_execution_times.rst
new file mode 100755
index 0000000..e8da946
--- /dev/null
+++ b/docs/source/generated/examples/sg_execution_times.rst
@@ -0,0 +1,37 @@
+
+:orphan:
+
+.. _sphx_glr_generated_examples_sg_execution_times:
+
+
+Computation times
+=================
+**00:00.000** total execution time for 0 files **from generated/examples**:
+
+.. container::
+
+ .. raw:: html
+
+
+
+
+
+
+
+ .. list-table::
+ :header-rows: 1
+ :class: table table-striped sg-datatable
+
+ * - Example
+ - Time
+ - Mem (MB)
+ * - N/A
+ - N/A
+ - N/A
diff --git a/docs/source/generated/examples/tissue/images/sphx_glr_plot_extended_tofts_001.png b/docs/source/generated/examples/tissue/images/sphx_glr_plot_extended_tofts_001.png
new file mode 100755
index 0000000..7946b14
Binary files /dev/null and b/docs/source/generated/examples/tissue/images/sphx_glr_plot_extended_tofts_001.png differ
diff --git a/docs/source/generated/examples/tissue/images/sphx_glr_plot_extended_tofts_002.png b/docs/source/generated/examples/tissue/images/sphx_glr_plot_extended_tofts_002.png
new file mode 100755
index 0000000..f3cf070
Binary files /dev/null and b/docs/source/generated/examples/tissue/images/sphx_glr_plot_extended_tofts_002.png differ
diff --git a/docs/source/generated/examples/tissue/images/sphx_glr_plot_tofts_001.png b/docs/source/generated/examples/tissue/images/sphx_glr_plot_tofts_001.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/tissue/images/sphx_glr_plot_tofts_002.png b/docs/source/generated/examples/tissue/images/sphx_glr_plot_tofts_002.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/tissue/images/thumb/sphx_glr_plot_extended_tofts_thumb.png b/docs/source/generated/examples/tissue/images/thumb/sphx_glr_plot_extended_tofts_thumb.png
new file mode 100755
index 0000000..13e5769
Binary files /dev/null and b/docs/source/generated/examples/tissue/images/thumb/sphx_glr_plot_extended_tofts_thumb.png differ
diff --git a/docs/source/generated/examples/tissue/images/thumb/sphx_glr_plot_tofts_thumb.png b/docs/source/generated/examples/tissue/images/thumb/sphx_glr_plot_tofts_thumb.png
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/tissue/index.rst b/docs/source/generated/examples/tissue/index.rst
old mode 100644
new mode 100755
index 12f0321..b028c57
--- a/docs/source/generated/examples/tissue/index.rst
+++ b/docs/source/generated/examples/tissue/index.rst
@@ -32,6 +32,23 @@ Tissue concentrations
+.. raw:: html
+
+
+
+.. only:: html
+
+ .. image:: /generated/examples/tissue/images/thumb/sphx_glr_plot_extended_tofts_thumb.png
+ :alt:
+
+ :ref:`sphx_glr_generated_examples_tissue_plot_extended_tofts.py`
+
+.. raw:: html
+
+
The Extended Tofts model
+
+
+
.. raw:: html
@@ -41,4 +58,5 @@ Tissue concentrations
:hidden:
/generated/examples/tissue/plot_tofts
+ /generated/examples/tissue/plot_extended_tofts
diff --git a/docs/source/generated/examples/tissue/plot_extended_tofts.ipynb b/docs/source/generated/examples/tissue/plot_extended_tofts.ipynb
new file mode 100755
index 0000000..d42ad9c
--- /dev/null
+++ b/docs/source/generated/examples/tissue/plot_extended_tofts.ipynb
@@ -0,0 +1,104 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n# The Extended Tofts model\n\nSimulating tissue concentrations from extended Tofts model with different settings.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Import necessary packages\n\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\nimport matplotlib.pyplot as plt\nimport osipi"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Generate Parker AIF with default settings.\n\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# Define time points in units of seconds - in this case we use a time resolution of 1 sec and a total duration of 6 minutes.\nt = np.arange(0, 6*60, 1)\n\n# Create an AIF with default settings\nca = osipi.aif_parker(t)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Plot the tissue concentrations for an extracellular volume fraction of 0.2 and 3 different plasma volumes of 0.05, 0.2 and 0.6\n\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "Ktrans = 0.2 # in units of 1/min\nve = 0.2 # volume fraction between 0 and 1\nvp = [0.05, 0.2, 0.6] # volume fraction between 0 and 1\nct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0])\nplt.plot(t, ct, 'b-', label=f'vp = {vp[0]}')\nct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[1])\nplt.plot(t, ct, 'g-', label=f'vp = {vp[1]}')\nct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[2])\nplt.plot(t, ct, 'm-', label=f'vp = {vp[2]}')\nplt.xlabel('Time (sec)')\nplt.ylabel('Tissue concentration (mM)')\nplt.legend()\nplt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Comparing different discretization methods for an extracellular volume fraction of 0.2, Ktrans of 0.2 /min and vp of 0.05\n\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0]) # Defaults to Convolution\nplt.plot(t, ct, 'b-', label='Convolution')\nct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0], discretization_method='exp')\nplt.plot(t, ct, 'g-', label='Exponential Convolution')\nplt.title(f'Ktrans = {Ktrans} /min')\nplt.xlabel('Time (sec)')\nplt.ylabel('Tissue concentration (mM)')\nplt.legend()\nplt.show()\n\n# Choose the last image as a thumbnail for the gallery\n# sphinx_gallery_thumbnail_number = -1"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
\ No newline at end of file
diff --git a/docs/source/generated/examples/tissue/plot_extended_tofts.py b/docs/source/generated/examples/tissue/plot_extended_tofts.py
new file mode 100755
index 0000000..a4c60d3
--- /dev/null
+++ b/docs/source/generated/examples/tissue/plot_extended_tofts.py
@@ -0,0 +1,53 @@
+"""
+====================
+The Extended Tofts model
+====================
+
+Simulating tissue concentrations from extended Tofts model with different settings.
+"""
+
+# %%
+# Import necessary packages
+import numpy as np
+import matplotlib.pyplot as plt
+import osipi
+
+# %%
+# Generate Parker AIF with default settings.
+
+# Define time points in units of seconds - in this case we use a time resolution of 1 sec and a total duration of 6 minutes.
+t = np.arange(0, 6*60, 1)
+
+# Create an AIF with default settings
+ca = osipi.aif_parker(t)
+
+# %%
+# Plot the tissue concentrations for an extracellular volume fraction of 0.2 and 3 different plasma volumes of 0.05, 0.2 and 0.6
+Ktrans = 0.2 # in units of 1/min
+ve = 0.2 # volume fraction between 0 and 1
+vp = [0.05, 0.2, 0.6] # volume fraction between 0 and 1
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0])
+plt.plot(t, ct, 'b-', label=f'vp = {vp[0]}')
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[1])
+plt.plot(t, ct, 'g-', label=f'vp = {vp[1]}')
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[2])
+plt.plot(t, ct, 'm-', label=f'vp = {vp[2]}')
+plt.xlabel('Time (sec)')
+plt.ylabel('Tissue concentration (mM)')
+plt.legend()
+plt.show()
+
+# %%
+# Comparing different discretization methods for an extracellular volume fraction of 0.2, Ktrans of 0.2 /min and vp of 0.05
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0]) # Defaults to Convolution
+plt.plot(t, ct, 'b-', label='Convolution')
+ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0], discretization_method='exp')
+plt.plot(t, ct, 'g-', label='Exponential Convolution')
+plt.title(f'Ktrans = {Ktrans} /min')
+plt.xlabel('Time (sec)')
+plt.ylabel('Tissue concentration (mM)')
+plt.legend()
+plt.show()
+
+# Choose the last image as a thumbnail for the gallery
+# sphinx_gallery_thumbnail_number = -1
diff --git a/docs/source/generated/examples/tissue/plot_extended_tofts.py.md5 b/docs/source/generated/examples/tissue/plot_extended_tofts.py.md5
new file mode 100755
index 0000000..0a6c85b
--- /dev/null
+++ b/docs/source/generated/examples/tissue/plot_extended_tofts.py.md5
@@ -0,0 +1 @@
+fe125cfe0a7b9603e82149422673111f
\ No newline at end of file
diff --git a/docs/source/generated/examples/tissue/plot_extended_tofts.rst b/docs/source/generated/examples/tissue/plot_extended_tofts.rst
new file mode 100755
index 0000000..1223560
--- /dev/null
+++ b/docs/source/generated/examples/tissue/plot_extended_tofts.rst
@@ -0,0 +1,159 @@
+
+.. DO NOT EDIT.
+.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
+.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
+.. "generated/examples/tissue/plot_extended_tofts.py"
+.. LINE NUMBERS ARE GIVEN BELOW.
+
+.. only:: html
+
+ .. note::
+ :class: sphx-glr-download-link-note
+
+ :ref:`Go to the end `
+ to download the full example code
+
+.. rst-class:: sphx-glr-example-title
+
+.. _sphx_glr_generated_examples_tissue_plot_extended_tofts.py:
+
+
+====================
+The Extended Tofts model
+====================
+
+Simulating tissue concentrations from extended Tofts model with different settings.
+
+.. GENERATED FROM PYTHON SOURCE LINES 10-11
+
+Import necessary packages
+
+.. GENERATED FROM PYTHON SOURCE LINES 11-15
+
+.. code-block:: Python
+
+ import numpy as np
+ import matplotlib.pyplot as plt
+ import osipi
+
+
+
+
+
+
+
+
+.. GENERATED FROM PYTHON SOURCE LINES 16-17
+
+Generate Parker AIF with default settings.
+
+.. GENERATED FROM PYTHON SOURCE LINES 17-24
+
+.. code-block:: Python
+
+
+ # Define time points in units of seconds - in this case we use a time resolution of 1 sec and a total duration of 6 minutes.
+ t = np.arange(0, 6*60, 1)
+
+ # Create an AIF with default settings
+ ca = osipi.aif_parker(t)
+
+
+
+
+
+
+
+
+.. GENERATED FROM PYTHON SOURCE LINES 25-26
+
+Plot the tissue concentrations for an extracellular volume fraction of 0.2 and 3 different plasma volumes of 0.05, 0.2 and 0.6
+
+.. GENERATED FROM PYTHON SOURCE LINES 26-40
+
+.. code-block:: Python
+
+ Ktrans = 0.2 # in units of 1/min
+ ve = 0.2 # volume fraction between 0 and 1
+ vp = [0.05, 0.2, 0.6] # volume fraction between 0 and 1
+ ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0])
+ plt.plot(t, ct, 'b-', label=f'vp = {vp[0]}')
+ ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[1])
+ plt.plot(t, ct, 'g-', label=f'vp = {vp[1]}')
+ ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[2])
+ plt.plot(t, ct, 'm-', label=f'vp = {vp[2]}')
+ plt.xlabel('Time (sec)')
+ plt.ylabel('Tissue concentration (mM)')
+ plt.legend()
+ plt.show()
+
+
+
+
+.. image-sg:: /generated/examples/tissue/images/sphx_glr_plot_extended_tofts_001.png
+ :alt: plot extended tofts
+ :srcset: /generated/examples/tissue/images/sphx_glr_plot_extended_tofts_001.png
+ :class: sphx-glr-single-img
+
+
+
+
+
+.. GENERATED FROM PYTHON SOURCE LINES 41-42
+
+Comparing different discretization methods for an extracellular volume fraction of 0.2, Ktrans of 0.2 /min and vp of 0.05
+
+.. GENERATED FROM PYTHON SOURCE LINES 42-54
+
+.. code-block:: Python
+
+ ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0]) # Defaults to Convolution
+ plt.plot(t, ct, 'b-', label='Convolution')
+ ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp[0], discretization_method='exp')
+ plt.plot(t, ct, 'g-', label='Exponential Convolution')
+ plt.title(f'Ktrans = {Ktrans} /min')
+ plt.xlabel('Time (sec)')
+ plt.ylabel('Tissue concentration (mM)')
+ plt.legend()
+ plt.show()
+
+ # Choose the last image as a thumbnail for the gallery
+ # sphinx_gallery_thumbnail_number = -1
+
+
+
+.. image-sg:: /generated/examples/tissue/images/sphx_glr_plot_extended_tofts_002.png
+ :alt: Ktrans = 0.2 /min
+ :srcset: /generated/examples/tissue/images/sphx_glr_plot_extended_tofts_002.png
+ :class: sphx-glr-single-img
+
+
+
+
+
+
+.. rst-class:: sphx-glr-timing
+
+ **Total running time of the script:** (0 minutes 0.113 seconds)
+
+
+.. _sphx_glr_download_generated_examples_tissue_plot_extended_tofts.py:
+
+.. only:: html
+
+ .. container:: sphx-glr-footer sphx-glr-footer-example
+
+ .. container:: sphx-glr-download sphx-glr-download-jupyter
+
+ :download:`Download Jupyter notebook: plot_extended_tofts.ipynb `
+
+ .. container:: sphx-glr-download sphx-glr-download-python
+
+ :download:`Download Python source code: plot_extended_tofts.py `
+
+
+.. only:: html
+
+ .. rst-class:: sphx-glr-signature
+
+ `Gallery generated by Sphinx-Gallery `_
diff --git a/docs/source/generated/examples/tissue/plot_extended_tofts_codeobj.pickle b/docs/source/generated/examples/tissue/plot_extended_tofts_codeobj.pickle
new file mode 100755
index 0000000..b503898
Binary files /dev/null and b/docs/source/generated/examples/tissue/plot_extended_tofts_codeobj.pickle differ
diff --git a/docs/source/generated/examples/tissue/plot_tofts.ipynb b/docs/source/generated/examples/tissue/plot_tofts.ipynb
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/tissue/plot_tofts.py b/docs/source/generated/examples/tissue/plot_tofts.py
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/tissue/plot_tofts.py.md5 b/docs/source/generated/examples/tissue/plot_tofts.py.md5
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/tissue/plot_tofts.rst b/docs/source/generated/examples/tissue/plot_tofts.rst
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/tissue/plot_tofts_codeobj.pickle b/docs/source/generated/examples/tissue/plot_tofts_codeobj.pickle
old mode 100644
new mode 100755
diff --git a/docs/source/generated/examples/tissue/sg_execution_times.rst b/docs/source/generated/examples/tissue/sg_execution_times.rst
old mode 100644
new mode 100755
index 54b7203..d653090
--- a/docs/source/generated/examples/tissue/sg_execution_times.rst
+++ b/docs/source/generated/examples/tissue/sg_execution_times.rst
@@ -6,8 +6,35 @@
Computation times
=================
-**00:00.093** total execution time for **generated_examples_tissue** files:
+**00:00.113** total execution time for 2 files **from generated/examples/tissue**:
-+-----------------------------------------------------------------------------+-----------+--------+
-| :ref:`sphx_glr_generated_examples_tissue_plot_tofts.py` (``plot_tofts.py``) | 00:00.093 | 0.0 MB |
-+-----------------------------------------------------------------------------+-----------+--------+
+.. container::
+
+ .. raw:: html
+
+
+
+
+
+
+
+ .. list-table::
+ :header-rows: 1
+ :class: table table-striped sg-datatable
+
+ * - Example
+ - Time
+ - Mem (MB)
+ * - :ref:`sphx_glr_generated_examples_tissue_plot_extended_tofts.py` (``plot_extended_tofts.py``)
+ - 00:00.113
+ - 0.0
+ * - :ref:`sphx_glr_generated_examples_tissue_plot_tofts.py` (``plot_tofts.py``)
+ - 00:00.000
+ - 0.0
diff --git a/docs/source/index.rst b/docs/source/index.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/alphabetical.rst b/docs/source/reference/alphabetical.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.averaging.rst b/docs/source/reference/general.averaging.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.convolution.rst b/docs/source/reference/general.convolution.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.deconvolution.rst b/docs/source/reference/general.deconvolution.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.descriptive.rst b/docs/source/reference/general.descriptive.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.forward.rst b/docs/source/reference/general.forward.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.optimization.rst b/docs/source/reference/general.optimization.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.rst b/docs/source/reference/general.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.segmentation.rst b/docs/source/reference/general.segmentation.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/general.uncertainty.rst b/docs/source/reference/general.uncertainty.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.concentration.aif.rst b/docs/source/reference/models.concentration.aif.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.concentration.rst b/docs/source/reference/models.concentration.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.concentration.tissue.rst b/docs/source/reference/models.concentration.tissue.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.descriptive.rst b/docs/source/reference/models.descriptive.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.empproperties.rst b/docs/source/reference/models.empproperties.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.identity.rst b/docs/source/reference/models.identity.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.leakage.rst b/docs/source/reference/models.leakage.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.rst b/docs/source/reference/models.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/models.signal.rst b/docs/source/reference/models.signal.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.R1.rst b/docs/source/reference/processes.R1.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.aif.rst b/docs/source/reference/processes.aif.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.baseline.rst b/docs/source/reference/processes.baseline.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.bat.rst b/docs/source/reference/processes.bat.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.calibration.rst b/docs/source/reference/processes.calibration.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.concentration.rst b/docs/source/reference/processes.concentration.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.leakage.rst b/docs/source/reference/processes.leakage.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.parameters.rst b/docs/source/reference/processes.parameters.rst
old mode 100644
new mode 100755
diff --git a/docs/source/reference/processes.rst b/docs/source/reference/processes.rst
old mode 100644
new mode 100755
diff --git a/docs/source/sg_execution_times.rst b/docs/source/sg_execution_times.rst
new file mode 100755
index 0000000..2f4c88e
--- /dev/null
+++ b/docs/source/sg_execution_times.rst
@@ -0,0 +1,46 @@
+
+:orphan:
+
+.. _sphx_glr_sg_execution_times:
+
+
+Computation times
+=================
+**00:00.113** total execution time for 4 files **from all galleries**:
+
+.. container::
+
+ .. raw:: html
+
+
+
+
+
+
+
+ .. list-table::
+ :header-rows: 1
+ :class: table table-striped sg-datatable
+
+ * - Example
+ - Time
+ - Mem (MB)
+ * - :ref:`sphx_glr_generated_examples_tissue_plot_extended_tofts.py` (``../examples/tissue/plot_extended_tofts.py``)
+ - 00:00.113
+ - 0.0
+ * - :ref:`sphx_glr_generated_examples_aif_plot_aif_parker.py` (``../examples/aif/plot_aif_parker.py``)
+ - 00:00.000
+ - 0.0
+ * - :ref:`sphx_glr_generated_examples_aif_plot_dummy.py` (``../examples/aif/plot_dummy.py``)
+ - 00:00.000
+ - 0.0
+ * - :ref:`sphx_glr_generated_examples_tissue_plot_tofts.py` (``../examples/tissue/plot_tofts.py``)
+ - 00:00.000
+ - 0.0
diff --git a/docs/source/user_guide/forward/forward.rst b/docs/source/user_guide/forward/forward.rst
old mode 100644
new mode 100755
diff --git a/docs/source/user_guide/forward/index.rst b/docs/source/user_guide/forward/index.rst
old mode 100644
new mode 100755
diff --git a/docs/source/user_guide/index.rst b/docs/source/user_guide/index.rst
old mode 100644
new mode 100755
diff --git a/docs/source/user_guide/installation.rst b/docs/source/user_guide/installation.rst
old mode 100644
new mode 100755
diff --git a/docs/source/user_guide/inverse/index.rst b/docs/source/user_guide/inverse/index.rst
old mode 100644
new mode 100755
diff --git a/docs/source/user_guide/inverse/inverse.rst b/docs/source/user_guide/inverse/inverse.rst
old mode 100644
new mode 100755
diff --git a/manage.py b/manage.py
old mode 100644
new mode 100755
diff --git a/pyproject.toml b/pyproject.toml
old mode 100644
new mode 100755
diff --git a/requirements.txt b/requirements.txt
old mode 100644
new mode 100755
diff --git a/setup.py b/setup.py
old mode 100644
new mode 100755
diff --git a/src/.DS_Store b/src/.DS_Store
index d09ec79..7f04e6e 100644
Binary files a/src/.DS_Store and b/src/.DS_Store differ
diff --git a/src/osipi/.DS_Store b/src/osipi/.DS_Store
new file mode 100644
index 0000000..79badd4
Binary files /dev/null and b/src/osipi/.DS_Store differ
diff --git a/src/osipi/__init__.py b/src/osipi/__init__.py
old mode 100644
new mode 100755
diff --git a/src/osipi/_aif.py b/src/osipi/_aif.py
old mode 100644
new mode 100755
diff --git a/src/osipi/_convolution.py b/src/osipi/_convolution.py
old mode 100644
new mode 100755
diff --git a/src/osipi/_tissue.py b/src/osipi/_tissue.py
old mode 100644
new mode 100755
index a0f4e5b..a4643a1
--- a/src/osipi/_tissue.py
+++ b/src/osipi/_tissue.py
@@ -50,6 +50,7 @@ def tofts(t: np.ndarray, ca: np.ndarray, Ktrans: float, ve: float, Ta: float = 3
>>> ca = osipi.aif_parker(t)
Calculate tissue concentrations and plot:
+
>>> Ktrans = 0.6 # in units of 1/min
>>> ve = 0.2 # takes values from 0 to 1
>>> ct = osipi.tofts(t, ca, Ktrans, ve)
@@ -60,7 +61,7 @@ def tofts(t: np.ndarray, ca: np.ndarray, Ktrans: float, ve: float, Ta: float = 3
if Ktrans <= 0 or ve <= 0:
ct = 0 * ca
- warnings.warn('Tissue concentration will be set to zero if Ktrans or ve are less than or equal to zero.', stacklevel=2)
+
else:
# Convert units
Ktrans = Ktrans/60 # from 1/min to 1/sec
@@ -112,18 +113,16 @@ def tofts(t: np.ndarray, ca: np.ndarray, Ktrans: float, ve: float, Ta: float = 3
return ct
-def extended_tofts(t: np.ndarray, ca: np.ndarray, Ktrans: float, ve: float, Ta: float = 30.0,
+def extended_tofts(t: np.ndarray, ca: np.ndarray, Ktrans: float, ve: float, vp: float, Ta: float = 30.0,
discretization_method: str = "conv") -> np.ndarray:
- """Extended tofts model as defined by ???.
-
- Note:
- This function is not yet implemented. If you are implementing it yourself please consider submitting a code contribution to OSIPI, so nobody ever has to write this function again!
+ """Extended tofts model as defined by Tofts (1997)
Args:
t (np.ndarray): array of time points in units of sec. [OSIPI code Q.GE1.004]
ca (np.ndarray): Arterial concentrations in mM for each time point in t. [OSIPI code Q.IC1.001]
- Ktrans (float): Volume transfer constant in units of 1/sec. [OSIPI code Q.PH1.008]
+ Ktrans (float): Volume transfer constant in units of 1/min. [OSIPI code Q.PH1.008]
ve (float): Relative volume fraction of the extracellular extravascular compartment (e). [OSIPI code Q.PH1.001.[e]]
+ vp (float): Relative volyme fraction of the plasma compartment (p). [OSIPI code Q.PH1.001.[p]]
Ta (float, optional): Arterial delay time, i.e., difference in onset time between tissue curve and AIF in units of sec. Defaults to 30 seconds. [OSIPI code Q.PH1.007]
discretization_method (str, optional): Defines the discretization method. Options include
@@ -142,11 +141,11 @@ def extended_tofts(t: np.ndarray, ca: np.ndarray, Ktrans: float, ve: float, Ta:
- Lexicon url: https://osipi.github.io/OSIPI_CAPLEX/perfusionModels/#indicator-kinetic-models
- Lexicon code: M.IC1.005
- OSIPI name: Extended Tofts Model
- - Adapted from contributions by: TBC
+ - Adapted from contributions by: LEK_UoEdinburgh_UK, ST_USyd_AUS, MJT_UoEdinburgh_UK
Example:
- Create an array of time points covering 6min in steps of 1sec, calculate the Parker AIF at these time points, calculate tissue concentrations
+ Create an array of time points covering 6 min in steps of 1 sec, calculate the Parker AIF at these time points, calculate tissue concentrations
using the Extended Tofts model and plot the results.
Import packages:
@@ -160,13 +159,69 @@ def extended_tofts(t: np.ndarray, ca: np.ndarray, Ktrans: float, ve: float, Ta:
>>> ca = osipi.aif_parker(t)
Calculate tissue concentrations and plot
- >>> Ktrans = 0.6/60 # in units of 1/sec
+
+ >>> Ktrans = 0.6 # in units of 1/min
>>> ve = 0.2 # takes values from 0 to 1
- >>> ct = osipi.extended_tofts(t, ca, Ktrans, ve)
+ >>> vp = 0.3 # takes values from 0 to 1
+ >>> ct = osipi.extended_tofts(t, ca, Ktrans, ve, vp)
>>> plt.plot(t, ca, 'r', t, ct, 'b')
"""
- msg = 'This function is not yet implemented \n'
- msg += 'If you implement it yourself, please consider submitting it as an OSIPI code contribution'
- raise NotImplementedError(msg)
+ if not np.allclose(np.diff(t), np.diff(t)[0]):
+ warnings.warn('Non-uniform time spacing detected. Time array may be resampled.', stacklevel=2)
+
+ if Ktrans <= 0 or ve <= 0:
+ ct = vp * ca
+
+ else:
+ # Convert units
+ Ktrans = Ktrans/60 # from 1/min to 1/sec
+
+ if discretization_method == 'exp': # Use exponential convolution
+ # Shift the AIF by the arterial delay time (if not zero)
+ if Ta != 0:
+ f = interp1d(t, ca, kind='linear', bounds_error=False, fill_value=0)
+ ca = (t > Ta) * f(t - Ta)
+
+ Tc = ve / Ktrans
+ # expconv calculates convolution of ca and (1/Tc)exp(-t/Tc), add vp*ca term for extended model
+ ct = (vp * ca) + ve * exp_conv(Tc, t, ca)
+
+
+ else: # Use convolution by default
+ # Calculate the impulse response function
+ kep = Ktrans / ve
+ imp = Ktrans * np.exp(-1 * kep * t)
+
+ # Shift the AIF by the arterial delay time (if not zero)
+ if Ta != 0:
+ f = interp1d(t, ca, kind='linear', bounds_error=False, fill_value=0)
+ ca = (t > Ta) * f(t - Ta)
+
+ # Check if time data grid is uniformly spaced
+ if np.allclose(np.diff(t), np.diff(t)[0]):
+ # Convolve impulse response with AIF
+ convolution = np.convolve(ca, imp)
+
+ # Discard unwanted points, make sure time spacing is correct and add vp*ca term for extended model
+ ct = convolution[0:len(t)] * t[1] + (vp * ca)
+ else:
+ # Resample at the smallest spacing
+ dt = np.min(np.diff(t))
+ t_resampled = np.linspace(t[0], t[-1], int((t[-1]-t[0])/dt))
+ ca_func = interp1d(t, ca, kind='quadratic', bounds_error=False, fill_value=0)
+ imp_func = interp1d(t, imp, kind='quadratic', bounds_error=False, fill_value=0)
+ ca_resampled = ca_func(t_resampled)
+ imp_resampled = imp_func(t_resampled)
+ # Convolve impulse response with AIF
+ convolution = np.convolve(ca_resampled, imp_resampled)
+
+ # Discard unwanted points, make sure time spacing is correct and add vp*ca term for extended model
+ ct_resampled = convolution[0:len(t_resampled)] * t_resampled[1] + (vp * ca_resampled)
+
+ # Restore time grid spacing
+ ct_func = interp1d(t_resampled, ct_resampled, kind='quadratic', bounds_error=False, fill_value=0)
+ ct = ct_func(t)
+
+ return ct
diff --git a/tests/.DS_Store b/tests/.DS_Store
new file mode 100644
index 0000000..058ed8b
Binary files /dev/null and b/tests/.DS_Store differ
diff --git a/tests/requirements.txt b/tests/requirements.txt
old mode 100644
new mode 100755
diff --git a/tests/test_aif.py b/tests/test_aif.py
old mode 100644
new mode 100755
diff --git a/tests/test_tissue.py b/tests/test_tissue.py
old mode 100644
new mode 100755
index eb97a0b..06caa64
--- a/tests/test_tissue.py
+++ b/tests/test_tissue.py
@@ -55,15 +55,54 @@ def test_tissue_tofts():
def test_tissue_extended_tofts():
- # Not implemented yet so need to raise an error
- t = np.arange(0, 6 * 60, 0.1)
+# 1. Basic operation of the function - test that the peak tissue concentration is less than the peak AIF
+ t = np.linspace(0, 6 * 60, 360)
+ ca = osipi.aif_parker(t)
+ ct = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0.2, vp=0.3)
+ assert np.round(np.max(ct)) < np.round(np.max(ca))
+
+ # 2. Basic operation of the function - test with non-uniform spacing of time array
+ t = np.geomspace(1, 6*60+1, num=360)-1
+ ca = osipi.aif_parker(t)
+ ct = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0.2, vp=0.3)
+ assert np.round(np.max(ct)) < np.round(np.max(ca))
+
+ # 3. The offset option - test that the tissue concentration is shifted from the AIF by the specified offset time
+ t = np.arange(0, 6 * 60, 1)
+ ca = osipi.aif_parker(t)
+ ct = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0.2, vp=0.3, Ta=60.0)
+ assert (np.min(np.where(ct>0.0)) - np.min(np.where(ca>0.0)) - 1)*1 == 60.0
+
+ # 4. Test that the discretization options give almost the same result - time step must be very small
+ t = np.arange(0, 6 * 60, 0.01)
+ ca = osipi.aif_parker(t)
+ ct_conv = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0.2, vp=0.3)
+ ct_exp = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0.2, vp=0.3, discretization_method='exp')
+ assert np.allclose(ct_conv, ct_exp, rtol=1e-4, atol=1e-3)
+
+ # 5. Test that the ratio of the area under the ct and ca curves is approximately the extracellular volume plus the plasma volume
+ t = np.arange(0, 6 * 60, 1)
+ ca = osipi.aif_parker(t)
+ ct_conv = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0.2, vp=0.3)
+ ct_exp = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0.2, vp=0.3, discretization_method='exp')
+ assert math.isclose(np.trapz(ct_conv, t)/np.trapz(ca, t), 0.2+0.3, abs_tol=1e-1)
+ assert math.isclose(np.trapz(ct_exp, t)/np.trapz(ca, t), 0.2+0.3, abs_tol=1e-1)
+
+ # 6. Test specific use cases
+ t = np.arange(0, 6 * 60, 1)
ca = osipi.aif_parker(t)
- try:
- ct = osipi.extended_tofts(t, ca, Ktrans=0.6/60, ve=0.2)
- except:
- assert True
- else:
- assert False
+ ct_conv = osipi.extended_tofts(t, ca, Ktrans=0, ve=0.2, vp=0.3)
+ assert np.allclose(ct_conv,ca*0.3,rtol=1e-4, atol=1e-3)
+
+ ct_exp = osipi.extended_tofts(t, ca, Ktrans=0, ve=0.2, vp=0.3, discretization_method='exp')
+ assert np.allclose(ct_conv,ca*0.3,rtol=1e-4, atol=1e-3)
+
+ ct_conv = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0, vp=0.3)
+ assert np.allclose(ct_conv,ca*0.3,rtol=1e-4, atol=1e-3)
+
+ ct_exp = osipi.extended_tofts(t, ca, Ktrans=0.6, ve=0, vp=0.3, discretization_method='exp')
+ assert np.allclose(ct_conv,ca*0.3,rtol=1e-4, atol=1e-3)
+
if __name__ == "__main__":