-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1f586f8
commit cf69511
Showing
28 changed files
with
663 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,5 @@ junit | |
docs/build | ||
docs/source/generated | ||
docs/source/sg_execution_times.rst | ||
docs-mk/site | ||
docs-mk/docs/generated |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# About | ||
|
||
osipi is developed by the **Open Source Initiative for Perfusion Imaging (OSIPI)**, an initiative of the perfusion study group of the **International Society for Magnetic Resonance in Medicine (ISMRM)**. | ||
|
||
The osipi package structure and logic follow the lexicon defined by OSIPI, and wrap around selected implementations collected in the code contributions of OSIPI. | ||
|
||
## Scope | ||
|
||
osipi currently only includes methods for the dynamic contrast (DC) approach to perfusion MRI (DC-MRI, a unifying term for the separate fields DCE-MRI and DSC-MRI). In particular, arterial spin labelling (ASL) solutions are not currently included, but this may change in the future. | ||
|
||
!!! note "Future Updates" | ||
The inclusion of arterial spin labelling (ASL) solutions may change in the future. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Developer Guide | ||
|
||
There are multiple ways to contribute to `osipi` and we welcome them all. `osipi` is a tool developed by the research community for the research community, and we are all responsible for ensuring it is as good as it can be. So, if you feel some part of it is not, fix it! | ||
|
||
The way to do this is by making a pull request on GitHub. If you are not familiar with GitHub pull requests, it is not as scary as it sounds. The simplest way is to find the file that you want to edit on GitHub in your browser, edit it manually and follow the prompts to create a fork and pull request. | ||
|
||
## How to Contribute Examples | ||
|
||
One way to contribute is by providing examples of how you used `osipi` for a specific task. These are usually real-world examples with a relevant aim, perhaps to derive some results that you have published. To package these up as an example, follow these steps: | ||
|
||
1. Code up your example in a single Python file in a narrative style, similar to a notebook. Have a look at the current examples to see how these need to be formatted, especially their docstrings, to make sure they show up properly on the website. | ||
2. When you save your file, make sure the filename starts with *plot_*. | ||
3. Then drop your file in the examples folder `osipi-docs-examples` in the appropriate subfolder. | ||
|
||
When the documentation is generated, your example will automatically appear in the examples gallery and also in the documentation of any function you are using in the example. | ||
|
||
## How to Contribute Documentation | ||
|
||
`osipi` is a user interface and for that reason good, clear and well-structured documentation is equally important as the quality of the functionality itself. We especially welcome suggestions for improving the documentation from end-users who are not necessarily contributing new code. You know best what works, and what doesn't. | ||
|
||
If you are a user of `osipi`, and some part of the documentation is not as clear as it can be, then submit your suggestions for improvement and make sure that the next person will not have to face the same issues. | ||
|
||
If you want to edit the documentation of a specific function, then you need to find the function in the osipi source code `osipi-src`. Find the function and edit the documentation string immediately below its definition. If you want to edit any other part of the documentation, find the appropriate file in the documentation source code `osipi-docs-source` and edit it there. | ||
|
||
## How to Contribute Tests | ||
|
||
Beyond documentation and functionality, solid testing is equally critical for ensuring long-term stability of a package. `osipi` uses a continuous integration model where all tests are run before each push to the central repository. This is important because often changes at one part of the code, even if tested well locally, can have unintended consequences at other parts. The testing prevents that these errors propagate and destabilize parts of the package. | ||
|
||
If you find a bug in any part of the code, this obviously points to a flaw in the code, but it also reveals a gap in the testing. It is critical when this happens that both the code AND the tests are reviewed to ensure that in future a scenario of this type is picked up during testing. | ||
|
||
The tests are defined in the folder `osipi-tests`. | ||
|
||
## How to Contribute Functionality | ||
|
||
OSIPI is always happy to receive new functionality for inclusion in the `osipi` package. This can be code that addresses a gap in the current functionality, or it can be code that improves the performance of a current implementation. Improvements can consist of extending the functionality (e.g. with new optional arguments), user friendliness or consistency, improvement of the accuracy or precision in the results, computation time, or platform independence, or improved documentation or code structure. | ||
|
||
Contribution of functionality generally proceeds in two steps. In the first step you submit your code to the primary *contributions* repository as explained in its [wiki](https://github.com/OSIPI/DCE-DSC-MRI_CodeCollection/wiki/How-to-contribute-code). The task force will catalogue your code in the contributions repository and test it as explained in the [guidance](https://github.com/OSIPI/DCE-DSC-MRI_CodeCollection/wiki/The-testing-approach). Afterwards, if it is found to address a gap in `osipi` and/or improve existing functionality, you will be invited to submit a pull request to `osipi` containing your contribution formatted as required by the package. | ||
|
||
While this is the general process, we accept there may be situations where a new submission to the contributions repository is overkill, for instance if your improvement concerns documentation only, or improvements in code structure or style. In that case a direct pull request to `osipi` may be acceptable - when in doubt please contact the OSIPI repository lead in the first instance to avoid unnecessary work. | ||
|
||
See the section on design principles below for general requirements from `osipi` code snippets. | ||
|
||
## How to Contribute Issues | ||
|
||
If you have a constructive suggestion for how `osipi` can be improved, but you are not able to address it yourself for some reason, it is still extremely helpful if you write this up as an issue so it can be picked up by others at a later stage. To write up an issue, go to the `osipi` repository on GitHub, select `issues` and write a new one. Make sure to provide sufficient detail so that others can understand and address the issue. | ||
|
||
## Design Principles | ||
|
||
### Style Guide | ||
|
||
`osipi` follows the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html). This means especially also that we expect proper attention to error handling. Consider for instance what happens if a user calls your snippet using arguments of incorrect type or length. Will they get an appropriate error message that will help them identify and fix the error? | ||
|
||
### Package Structure | ||
|
||
The `osipi` documentation follows the structure of the OSIPI Lexicon exactly - see [here](https://osipi.github.io/OSIPI_CAPLEX/) for a detailed description of the Lexicon. | ||
|
||
From a user perspective, the package structure is a flat list of functions that can all be accessed as `osipi.some_function`. They are listed in the __init__ file of the package, directly under the folder `src\osipi`. For clarity, the code itself is organized into modules, but these may evolve over time and should not be accessed directly. Module names all start with an underscore `_module.py` to emphasize their private and transient nature. Equally, subfolders may be added in the future as the package grows. | ||
|
||
|
||
|
||
### Code Snippets | ||
|
||
`osipi` is a collection of *simple* code snippets following a *simple* functional programming paradigm (did you see how we said *simple* twice there?). Each code snippet is a Python function that takes OSIPI variables as arguments and returns other OSIPI variables as results. At this stage, we are *not* planning to include an object-oriented interface or internal logic as this reduces the modularity of the code snippets, reduces compatibility with other packages, and increases the overhead of learning how to use `osipi`. Therefore, all code contributions will essentially consist of a new function or an improvement of an existing function. | ||
|
||
Beyond the general requirements of the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html), `osipi` requires that each new function is accompanied by an appropriate test in the tests folder, and that each function fully conforms to the Lexicon. In particular: | ||
|
||
1. Each function must be defined in the lexicon, and the docstring must include a reference section containing the following four items: | ||
- Lexicon URL: webpage in the Lexicon where the function is defined. | ||
- Lexicon code: machine-readable code identifying the entry in the Lexicon. | ||
- OSIPI name: human-readable name for the function as defined in the Lexicon. | ||
- Adapted from contribution: module.py in the original snippet in the code contribution repository | ||
2. Each argument to the function as well as each return value *must* be defined in the Lexicon. The docstring of the function must provide the following data on each argument and return value: | ||
- Python data type (include type hint in the function definition) | ||
- Lexicon code: machine-readable code identifying the corresponding quantity in the Lexicon. | ||
- OSIPI name: human-readable name for the quantity as defined in the Lexicon. | ||
3. All arguments and return values must be provided in OSIPI units as defined in the Lexicon. | ||
4. Arguments should be provided using OSIPI notation as defined in the Lexicon. | ||
5. The docstring of the function must contain a self-contained code example that runs the function and illustrates the output. | ||
|
||
!!!note | ||
If your function addresses entirely novel functionality or uses new variables that are not yet described in the Lexicon, then you should first contact the Lexicon maintainers and request that it is added as an entry to the Lexicon. Only afterwards can it be considered as a contribution to the `osipi` package. | ||
|
||
!!!note | ||
The original [library for code contributions](https://github.com/OSIPI/DCE-DSC-MRI_CodeCollection/wiki/How-to-contribute-code) is less stringent as to code structure and documentation or testing requirements. However, it is nevertheless advisable to adhere to the same guidelines when submitting code to the original contributions repository as this will make it easier for testers to understand and run your code, and it will reduce the overhead on your part in rewriting the code |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
|
||
# Examples | ||
|
||
|
||
### Illustrating common use cases of osipi. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
************************ | ||
Arterial Input Functions | ||
************************ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
""" | ||
====================================== | ||
The Parker AIF - a play with variables | ||
====================================== | ||
Simulating a Parker AIF with different settings. | ||
""" | ||
|
||
import matplotlib.pyplot as plt | ||
|
||
# %% | ||
# Import necessary packages | ||
import numpy as np | ||
import osipi | ||
|
||
# %% | ||
# Generate synthetic AIF with default settings and plot the result. | ||
|
||
# Define time points in units of seconds - in this case we use a time | ||
# resolution of 0.5 sec and a total duration of 6 minutes. | ||
t = np.arange(0, 6 * 60, 0.5) | ||
|
||
# Create an AIF with default settings | ||
ca = osipi.aif_parker(t) | ||
|
||
# Plot the AIF over the full range | ||
plt.plot(t, ca, "r-") | ||
plt.plot(t, 0 * t, "k-") | ||
plt.xlabel("Time (sec)") | ||
plt.ylabel("Plasma concentration (mM)") | ||
plt.show() | ||
|
||
# %% | ||
# The bolus arrival time (BAT) defaults to 0s. What happens if we | ||
# change it? Let's try, by changing it in steps of 30s: | ||
|
||
ca = osipi.aif_parker(t, BAT=0) | ||
plt.plot(t, ca, "b-", label="BAT = 0s") | ||
ca = osipi.aif_parker(t, BAT=30) | ||
plt.plot(t, ca, "r-", label="BAT = 30s") | ||
ca = osipi.aif_parker(t, BAT=60) | ||
plt.plot(t, ca, "g-", label="BAT = 60s") | ||
ca = osipi.aif_parker(t, BAT=90) | ||
plt.plot(t, ca, "m-", label="BAT = 90s") | ||
plt.xlabel("Time (sec)") | ||
plt.ylabel("Plasma concentration (mM)") | ||
plt.legend() | ||
plt.show() | ||
|
||
# Choose the last image as a thumbnail for the gallery | ||
# sphinx_gallery_thumbnail_number = -1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
""" | ||
============== | ||
A dummy script | ||
============== | ||
Dummy script to illustrate structure of examples folder | ||
""" | ||
|
||
import matplotlib.pyplot as plt | ||
|
||
# %% | ||
# Import necessary packages | ||
import numpy as np | ||
import osipi | ||
|
||
# %% | ||
# Generate synthetic AIF with default settings and plot the result. | ||
|
||
# Define time points in units of seconds - in this case we use a time | ||
# resolution of 0.5 sec and a total duration of 6 minutes. | ||
t = np.arange(0, 6 * 60, 0.5) | ||
|
||
# Create an AIF with default settings | ||
ca = osipi.aif_parker(t) | ||
|
||
# Plot the AIF over the full range | ||
plt.plot(t, ca, "r-") | ||
plt.plot(t, 0 * t, "k-") | ||
plt.xlabel("Time (sec)") | ||
plt.ylabel("Plasma concentration (mM)") | ||
plt.show() | ||
|
||
# %% | ||
# The bolus arrival time (BAT) defaults to 30s. What happens if we | ||
# change it? Let's try, by changing it in steps of 30s: | ||
|
||
ca = osipi.aif_parker(t, BAT=0) | ||
plt.plot(t, ca, "b-", label="BAT = 0s") | ||
ca = osipi.aif_parker(t, BAT=30) | ||
plt.plot(t, ca, "r-", label="BAT = 30s") | ||
ca = osipi.aif_parker(t, BAT=60) | ||
plt.plot(t, ca, "g-", label="BAT = 60s") | ||
ca = osipi.aif_parker(t, BAT=90) | ||
plt.plot(t, ca, "m-", label="BAT = 90s") | ||
plt.xlabel("Time (sec)") | ||
plt.ylabel("Plasma concentration (mM)") | ||
plt.legend() | ||
plt.show() | ||
|
||
# Choose the last image as a thumbnail for the gallery | ||
# sphinx_gallery_thumbnail_number = -1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
********************* | ||
Tissue concentrations | ||
********************* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
""" | ||
==================== | ||
The Extended Tofts model | ||
==================== | ||
Simulating tissue concentrations from extended Tofts model with different settings. | ||
""" | ||
|
||
import matplotlib.pyplot as plt | ||
|
||
# %% | ||
# Import necessary packages | ||
import numpy as np | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
""" | ||
==================== | ||
The Tofts model | ||
==================== | ||
Simulating tissue concentrations from Tofts model with different settings. | ||
""" | ||
|
||
import matplotlib.pyplot as plt | ||
|
||
# %% | ||
# Import necessary packages | ||
import numpy as np | ||
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 transfer rate constants of 0.05, 0.2 and 0.6 | ||
# /min | ||
Ktrans = [0.05, 0.2, 0.6] # in units of 1/min | ||
ve = 0.2 # volume fraction between 0 and 1 | ||
ct = osipi.tofts(t, ca, Ktrans=Ktrans[0], ve=ve) | ||
plt.plot(t, ct, "b-", label=f"Ktrans = {Ktrans[0]} /min") | ||
ct = osipi.tofts(t, ca, Ktrans[1], ve) | ||
plt.plot(t, ct, "g-", label=f"Ktrans = {Ktrans[1]} /min") | ||
ct = osipi.tofts(t, ca, Ktrans[2], ve) | ||
plt.plot(t, ct, "m-", label=f"Ktrans = {Ktrans[2]} /min") | ||
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 and Ktrans of 0.2 /min | ||
ct = osipi.tofts(t, ca, Ktrans=Ktrans[1], ve=ve) # Defaults to Convolution | ||
plt.plot(t, ct, "b-", label="Convolution") | ||
ct = osipi.tofts(t, ca, Ktrans=Ktrans[1], ve=ve, discretization_method="exp") | ||
plt.plot(t, ct, "g-", label="Exponential Convolution") | ||
plt.title(f"Ktrans = {Ktrans[1]} /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 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Osipi Documentation | ||
|
||
Welcome to the Osipi documentation! This guide is intended to help you get started with Osipi and provide the information you need to maximize its potential. | ||
|
||
## Warning | ||
|
||
!!! warning | ||
`osipi` is developed in public but is a work in progress. This version contains mostly temporary placeholder functionality. | ||
|
||
## About Osipi | ||
|
||
`osipi` is the authoritative Python package for perfusion MRI. It is developed by the Open Source Initiative for Perfusion Imaging (OSIPI), which is a study group initiative of the International Society for Magnetic Resonance in Medicine (ISMRM). | ||
|
||
## Purpose | ||
|
||
The purpose of `osipi` is to standardize and streamline the use of perfusion MRI, ensuring consistency and reliability across different implementations and studies. The package follows the lexicon defined by OSIPI and integrates selected implementations from the original code contributions made by the OSIPI community. | ||
|
||
|
||
Explore the documentation to learn more about how to use `osipi` and leverage its full capabilities for your perfusion MRI projects. | ||
|
||
## Sections | ||
|
||
- [User Guide](user-guide/index.md) | ||
- [Contribution Guidelines](contribution/index.md) | ||
- [References](references/index.md) | ||
- [About](about/index.md) | ||
- [Examples](examples/index.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Reference | ||
|
||
This reference manual details all functions included in `osipi`, describing what they are and what they do. Documentation of individual functions contains self-contained example code that demonstrates basic usage of the function. | ||
|
||
The `osipi` package currently only includes methods for the dynamic contrast (DC) approach to perfusion MRI (DC-MRI, a unifying term for the separate fields DCE-MRI and DSC-MRI). In particular arterial spin labelling (ASL) solutions are not currently included, but may be added in the future. | ||
|
||
This reference guide, like the `osipi` package itself, adheres closely to the structure and language of the [OSIPI Lexicon](https://osipi.github.io/OSIPI_CAPLEX/). | ||
|
||
!!!warning | ||
`osipi` is in development and this reference guide currently contains mainly empty placeholder entries. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# osipi.aif_georgiou | ||
|
||
::: osipi.aif_georgiou |
Oops, something went wrong.