Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9e6de79
api: bring functional wrappers up to Simulator
mcencini Oct 5, 2026
6a473f8
api: bring functional wrappers up to Simulator
mcencini Oct 5, 2026
95521ee
api: bring functional wrappers up to Simulator
mcencini Oct 5, 2026
ca7aec3
api: bring functional wrappers up to Simulator
mcencini Oct 5, 2026
cc51fe5
api: bring functional wrappers up to Simulator
mcencini Oct 5, 2026
0cb901f
api: bring functional wrappers up to Simulator
mcencini Oct 5, 2026
432d594
api: bring functional wrappers up to Simulator
mcencini Oct 5, 2026
1730a25
api: correct FSE wrapper documentation
mcencini Oct 5, 2026
dfe9208
api: correct prepared-GRE wrapper documentation
mcencini Oct 5, 2026
669ff13
api: correct prepared-GRE wrapper documentation
mcencini Oct 5, 2026
477b514
api: fix functional wrapper docstrings
mcencini Oct 5, 2026
c36e256
api: fix functional wrapper docstrings
mcencini Oct 5, 2026
0f622f7
test: cover functional wrapper protocol parity
mcencini Oct 5, 2026
62e87a6
test: cover functional wrapper physics parity
mcencini Oct 5, 2026
587de42
api: clarify functional pass-through scope
mcencini Oct 5, 2026
c93dd21
api: clarify functional pass-through scope
mcencini Oct 5, 2026
2e0a9db
api: clarify functional pass-through scope
mcencini Oct 5, 2026
440267c
api: clarify functional pass-through scope
mcencini Oct 5, 2026
7f66477
api: clarify functional pass-through scope
mcencini Oct 5, 2026
41e3118
api: clarify functional pass-through scope
mcencini Oct 5, 2026
f1c135c
api: clarify functional pass-through scope
mcencini Oct 5, 2026
5397923
test: keep wrapper parity to call-time settings
mcencini Oct 5, 2026
502263c
style: apply pre-commit formatting
mcencini Oct 5, 2026
aed068f
style: apply pre-commit formatting
mcencini Oct 5, 2026
5f71f35
fix: keep MP2RAGE wrapper to supported closed-form arguments
mcencini Oct 5, 2026
ce348a8
Merge branch 'main' into api/functional-wrapper-parity
mcencini Oct 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/torchsim/_functional/_bssfp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

__all__ = ["bssfp_sim"]

from typing import Any

import numpy.typing as npt
import torch

Expand All @@ -15,15 +17,16 @@ def bssfp_sim(
TR: float,
T1: float | npt.ArrayLike,
T2: float | npt.ArrayLike,
diff: str | tuple[str] = None,
diff: str | tuple[str, ...] | None = None,
phase_inc: float = 180.0,
B0: float | npt.ArrayLike = 0.0,
chemshift: float | npt.ArrayLike = 0.0,
M0: float | npt.ArrayLike = 1.0,
device: str | torch.device = None,
device: str | torch.device | None = None,
**values: Any,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
"""
SPoiled Gradient Recalled echo simulator wrapper.
Balanced steady-state free-precession simulator wrapper.

Parameters
----------
Expand All @@ -45,10 +48,14 @@ def bssfp_sim(
The default is ``180.0``
B0 : float | npt.ArrayLike, optional
Frequency offset map in Hz, default is ``0.0.``
chemshift : float | npt.ArrayLik, optional
chemshift : float | npt.ArrayLike, optional
Chemical shift in Hz, default is ``0.0``.
M0 : float or array-like, optional
Proton density scaling factor, default is ``1.0``.
**values : optional
Additional call-time tissue, protocol or run settings accepted by
``Simulator.simulate``. Settings fixed only at simulator construction
remain class-interface features.
device : str | torch.device, optional
Computational device for simulation.
The default is ``None`` (infer from input).
Expand Down Expand Up @@ -76,4 +83,5 @@ def bssfp_sim(
TR=TR,
TE=TE,
phase_inc=phase_inc,
**values,
)
21 changes: 12 additions & 9 deletions src/torchsim/_functional/_fse.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

__all__ = ["fse_sim"]

from typing import Any

import numpy.typing as npt
import torch

Expand All @@ -18,11 +20,12 @@ def fse_sim(
TR: float | npt.ArrayLike = 1e6,
exc_flip: float = 90.0,
exc_phase: float = 90.0,
diff: str | tuple[str] = None,
diff: str | tuple[str, ...] | None = None,
B1: float | npt.ArrayLike = 1.0,
M0: float | npt.ArrayLike = 1.0,
states: int = 10,
device: str | torch.device = None,
device: str | torch.device | None = None,
**values: Any,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
"""
Fast Spin Echo simulator wrapper.
Expand All @@ -35,7 +38,7 @@ def fse_sim(
Echo spacing in milliseconds.
phases : float | npt.ArrayLike, optional
Refocusing flip angle phases in degrees.
The default is ``90.0``.
The default is ``0.0``.
TR : float | npt.ArrayLike, optional
Repetition time in milliseconds.
The default is ``1e6``.
Expand All @@ -44,7 +47,7 @@ def fse_sim(
The default is ``90.0``.
exc_phase : float, optional
Excitation flip angle phase in degrees.
The default is ``0.0``.
The default is ``90.0``.
T1 : float | npt.ArrayLike
Longitudinal relaxation time in milliseconds.
T2 : float | npt.ArrayLike
Expand All @@ -54,16 +57,15 @@ def fse_sim(
The default is ``None`` (no differentation).
B1 : float | npt.ArrayLike, optional
Flip angle scaling map, default is ``1.0``.
inv_efficiency : float | npt.ArrayLike, optional
Inversion efficiency map, default is ``1.0``.
M0 : float or array-like, optional
Proton density scaling factor, default is ``1.0``.
TI : float | npt.ArrayLike, optional
Inversion time in milliseconds.
The default is ``0.0``.
states : int, optional
Number of EPG states to be retained.
The default is ``10``.
**values : optional
Additional call-time tissue, protocol or run settings accepted by
``Simulator.simulate``. Settings fixed only at simulator construction
remain class-interface features.
device : str | torch.device, optional
Computational device for simulation.
The default is ``None`` (infer from input).
Expand Down Expand Up @@ -93,4 +95,5 @@ def fse_sim(
exc_flip=exc_flip,
exc_phase=exc_phase,
states=states,
**values,
)
15 changes: 10 additions & 5 deletions src/torchsim/_functional/_mp2rage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

__all__ = ["mp2rage_sim"]

from typing import Any

import numpy.typing as npt
import torch

Expand All @@ -16,10 +18,11 @@ def mp2rage_sim(
TRmp2rage: float,
nshots: int | npt.ArrayLike,
T1: float | npt.ArrayLike,
diff: str | tuple[str] = None,
diff: str | tuple[str, ...] | None = None,
inv_efficiency: float | npt.ArrayLike = 1.0,
M0: float | npt.ArrayLike = 1.0,
device: str | torch.device = None,
device: str | torch.device | None = None,
**values: Any,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
"""
MP2RAGE simulator wrapper.
Expand Down Expand Up @@ -49,9 +52,10 @@ def mp2rage_sim(
Inversion efficiency map, default is ``1.0``.
M0 : float or array-like, optional
Proton density scaling factor, default is ``1.0``.
TI : float | npt.ArrayLike, optional
Inversion time in milliseconds.
The default is ``0.0``.
**values : optional
Additional call-time tissue, protocol or run settings accepted by
``Simulator.simulate``. Settings fixed only at simulator construction
remain class-interface features.
device : str | torch.device, optional
Computational device for simulation.
The default is ``None`` (infer from input).
Expand All @@ -78,4 +82,5 @@ def mp2rage_sim(
TRspgr=TRspgr,
TRmp2rage=TRmp2rage,
nshots=nshots,
**values,
)
16 changes: 14 additions & 2 deletions src/torchsim/_functional/_mpnrage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

__all__ = ["mpnrage_sim"]

from typing import Any

import numpy.typing as npt
import torch

Expand All @@ -14,12 +16,14 @@ def mpnrage_sim(
flip: npt.ArrayLike,
TR: float | npt.ArrayLike,
T1: float | npt.ArrayLike,
diff: str | tuple[str] = None,
diff: str | tuple[str, ...] | None = None,
B1: float | npt.ArrayLike = 1.0,
inv_efficiency: float | npt.ArrayLike = 1.0,
M0: float | npt.ArrayLike = 1.0,
TI: float = 0.0,
device: str | torch.device = None,
phases: float | npt.ArrayLike = 0.0,
device: str | torch.device | None = None,
**values: Any,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
"""
MPnRAGE simulator wrapper.
Expand All @@ -46,6 +50,12 @@ def mpnrage_sim(
TI : float | npt.ArrayLike, optional
Inversion time in milliseconds.
The default is ``0.0``.
phases : float or array-like, optional
Sequence phase schedule in degrees. The default is ``0.0``.
**values : optional
Additional call-time tissue, protocol or run settings accepted by
``Simulator.simulate``. Settings fixed only at simulator construction
remain class-interface features.
device : str | torch.device, optional
Computational device for simulation.
The default is ``None`` (infer from input).
Expand All @@ -72,4 +82,6 @@ def mpnrage_sim(
flip=flip,
TR=TR,
TI=TI,
phases=phases,
**values,
)
19 changes: 14 additions & 5 deletions src/torchsim/_functional/_mprage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

__all__ = ["mprage_sim"]

from typing import Any

import numpy.typing as npt
import torch

Expand All @@ -15,10 +17,12 @@ def mprage_sim(
TRspgr: float,
nshots: int | npt.ArrayLike,
T1: float | npt.ArrayLike,
diff: str | tuple[str] = None,
diff: str | tuple[str, ...] | None = None,
inv_efficiency: float | npt.ArrayLike = 1.0,
M0: float | npt.ArrayLike = 1.0,
device: str | torch.device = None,
phases: float | npt.ArrayLike = 0.0,
device: str | torch.device | None = None,
**values: Any,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
"""
MPRAGE simulator wrapper.
Expand Down Expand Up @@ -46,9 +50,12 @@ def mprage_sim(
Inversion efficiency map, default is ``1.0``.
M0 : float or array-like, optional
Proton density scaling factor, default is ``1.0``.
TI : float | npt.ArrayLike, optional
Inversion time in milliseconds.
The default is ``0.0``.
phases : float or array-like, optional
Sequence phase schedule in degrees. The default is ``0.0``.
**values : optional
Additional call-time tissue, protocol or run settings accepted by
``Simulator.simulate``. Settings fixed only at simulator construction
remain class-interface features.
device : str | torch.device, optional
Computational device for simulation.
The default is ``None`` (infer from input).
Expand All @@ -74,4 +81,6 @@ def mprage_sim(
flip=flip,
TRspgr=TRspgr,
nshots=nshots,
phases=phases,
**values,
)
17 changes: 14 additions & 3 deletions src/torchsim/_functional/_mrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

__all__ = ["mrf_sim"]

from typing import Any

import numpy.typing as npt
import torch

Expand All @@ -14,14 +16,16 @@ def mrf_sim(
TR: float | npt.ArrayLike,
T1: float | npt.ArrayLike,
T2: float | npt.ArrayLike,
diff: str | tuple[str] = None,
diff: str | tuple[str, ...] | None = None,
B1: float | npt.ArrayLike = 1.0,
inv_efficiency: float | npt.ArrayLike = 1.0,
M0: float | npt.ArrayLike = 1.0,
TI: float = 0.0,
phases: float | npt.ArrayLike = 0.0,
states: int = 10,
nreps: int = 1,
device: str | torch.device = None,
device: str | torch.device | None = None,
**values: Any,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
"""
SSFP MR Fingerprinting simulator wrapper.
Expand Down Expand Up @@ -54,6 +58,12 @@ def mrf_sim(
nreps : int, optional
Number of simulation repetitions.
The default is ``1``.
phases : float or array-like, optional
Sequence phase schedule in degrees. The default is ``0.0``.
**values : optional
Additional call-time tissue, protocol or run settings accepted by
``Simulator.simulate``. Settings fixed only at simulator construction
remain class-interface features.
device : str | torch.device, optional
Computational device for simulation.
The default is ``None`` (infer from input).
Expand All @@ -80,6 +90,7 @@ def mrf_sim(
flip=flip,
TR=TR,
TI=TI,
phases=phases,
states=states,
repetitions=nreps,
**{"repetitions": nreps, **values},
)
14 changes: 11 additions & 3 deletions src/torchsim/_functional/_spgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

__all__ = ["spgr_sim"]

from typing import Any

import numpy.typing as npt
import torch

Expand All @@ -15,11 +17,12 @@ def spgr_sim(
TR: float,
T1: float | npt.ArrayLike,
T2star: float | npt.ArrayLike,
diff: str | tuple[str] = None,
diff: str | tuple[str, ...] | None = None,
B0: float | npt.ArrayLike = 0.0,
chemshift: float | npt.ArrayLike = 0.0,
M0: float | npt.ArrayLike = 1.0,
device: str | torch.device = None,
device: str | torch.device | None = None,
**values: Any,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
"""
SPoiled Gradient Recalled echo simulator wrapper.
Expand All @@ -41,10 +44,14 @@ def spgr_sim(
The default is ``None`` (no differentation).
B0 : float | npt.ArrayLike, optional
Frequency offset map in Hz, default is ``0.0.``
chemshift : float | npt.ArrayLik, optional
chemshift : float | npt.ArrayLike, optional
Chemical shift in Hz, default is ``0.0``.
M0 : float or array-like, optional
Proton density scaling factor, default is ``1.0``.
**values : optional
Additional call-time tissue, protocol or run settings accepted by
``Simulator.simulate``. Settings fixed only at simulator construction
remain class-interface features.
device : str | torch.device, optional
Computational device for simulation.
The default is ``None`` (infer from input).
Expand All @@ -71,4 +78,5 @@ def spgr_sim(
flip=flip,
TR=TR,
TE=TE,
**values,
)
18 changes: 18 additions & 0 deletions tests/functionals/test_fse_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,21 @@ def test_scalar_gradient(flip):
def test_multiple_gradient(flip):
_, grad = fse_sim(flip, ESP=1.0, T1=(200, 500, 1000.0), T2=100.0, diff=("T1", "T2"))
assert grad.shape == (3, 2, 100)


def test_current_simulator_physics_passes_through(flip):
"""The convenience call does not hide physics the Simulator accepts."""
from torchsim.simulators import FSESimulator

got = fse_sim(
flip,
ESP=5.0,
T1=1000.0,
T2=100.0,
B0=17.0,
)
expected = FSESimulator(
flip=flip,
ESP=5.0,
).simulate(T1=1000.0, T2=100.0, B0=17.0)
np.testing.assert_allclose(got, expected)
19 changes: 19 additions & 0 deletions tests/functionals/test_mrf_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,22 @@ def test_scalar_gradient(flip):
def test_multiple_gradient(flip):
_, grad = mrf_sim(flip, TR=10.0, T1=(200, 500, 1000.0), T2=100.0, diff=("T1", "T2"))
assert grad.shape == (3, 2, 100)


def test_current_simulator_protocol_arguments_pass_through(flip):
"""The convenience call accepts protocol fields added to MRFSimulator."""
from torchsim.simulators import MRFSimulator

phases = np.linspace(0.0, 117.0, flip.size, dtype=np.float32)
got = mrf_sim(
flip,
TR=10.0,
T1=1000.0,
T2=100.0,
phases=phases,
B0=23.0,
)
expected = MRFSimulator(flip=flip, TR=10.0, phases=phases).simulate(
T1=1000.0, T2=100.0, B0=23.0
)
np.testing.assert_allclose(got, expected)
Loading