Skip to content

Commit

Permalink
Add tests for autodiff of operators (#405)
Browse files Browse the repository at this point in the history
Co-authored-by: Felix F Zimmermann <[email protected]>
  • Loading branch information
ckolbPTB and fzimmermann89 authored Nov 14, 2024
1 parent e42f666 commit 41ad113
Show file tree
Hide file tree
Showing 34 changed files with 176 additions and 60 deletions.
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from ._RandomGenerator import RandomGenerator
from .helper import relative_image_difference, dotproduct_adjointness_test, operator_isometry_test, linear_operator_unitary_test, autodiff_test
2 changes: 1 addition & 1 deletion tests/algorithms/csm/test_inati.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import torch
from mrpro.algorithms.csm import inati
from mrpro.data import SpatialDimension
from tests import relative_image_difference
from tests.algorithms.csm.conftest import multi_coil_image
from tests.helper import relative_image_difference


def test_inati(ellipse_phantom, random_kheader):
Expand Down
2 changes: 1 addition & 1 deletion tests/algorithms/csm/test_walsh.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import torch
from mrpro.algorithms.csm import walsh
from mrpro.data import SpatialDimension
from tests import relative_image_difference
from tests.algorithms.csm.conftest import multi_coil_image
from tests.helper import relative_image_difference


def test_walsh(ellipse_phantom, random_kheader):
Expand Down
2 changes: 1 addition & 1 deletion tests/data/test_csm_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import torch
from mrpro.data import CsmData, SpatialDimension

from tests import relative_image_difference
from tests.algorithms.csm.test_walsh import multi_coil_image
from tests.helper import relative_image_difference


def test_CsmData_is_frozen_dataclass(random_test_data, random_kheader):
Expand Down
2 changes: 1 addition & 1 deletion tests/data/test_kdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
from mrpro.operators import FastFourierOp
from mrpro.utils import split_idx

from tests import relative_image_difference
from tests.conftest import RandomGenerator, generate_random_data
from tests.data import IsmrmrdRawTestData
from tests.helper import relative_image_difference
from tests.phantoms import EllipsePhantomTestData


Expand Down
61 changes: 51 additions & 10 deletions tests/helper.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Helper/Utilities for test functions."""

import torch
from mrpro.operators import Operator
from mrpro.operators import LinearOperator, Operator
from typing_extensions import TypeVarTuple, Unpack


def relative_image_difference(img1: torch.Tensor, img2: torch.Tensor) -> torch.Tensor:
Expand All @@ -26,9 +27,13 @@ def relative_image_difference(img1: torch.Tensor, img2: torch.Tensor) -> torch.T


def dotproduct_adjointness_test(
operator: Operator, u: torch.Tensor, v: torch.Tensor, relative_tolerance: float = 1e-3, absolute_tolerance=1e-5
operator: LinearOperator,
u: torch.Tensor,
v: torch.Tensor,
relative_tolerance: float = 1e-3,
absolute_tolerance=1e-5,
):
"""Test the adjointness of operator and operator.H.
"""Test the adjointness of linear operator and operator.H.
Test if
<Operator(u),v> == <u, Operator^H(v)>
Expand All @@ -42,7 +47,7 @@ def dotproduct_adjointness_test(
Parameters
----------
operator
operator
linear operator
u
element of the domain of the operator
v
Expand Down Expand Up @@ -74,9 +79,12 @@ def dotproduct_adjointness_test(


def operator_isometry_test(
operator: Operator, u: torch.Tensor, relative_tolerance: float = 1e-3, absolute_tolerance=1e-5
operator: Operator[torch.Tensor, tuple[torch.Tensor]],
u: torch.Tensor,
relative_tolerance: float = 1e-3,
absolute_tolerance=1e-5,
):
"""Test the isometry of an operator.
"""Test the isometry of a operator.
Test if
||Operator(u)|| == ||u||
Expand All @@ -103,10 +111,10 @@ def operator_isometry_test(
)


def operator_unitary_test(
operator: Operator, u: torch.Tensor, relative_tolerance: float = 1e-3, absolute_tolerance=1e-5
def linear_operator_unitary_test(
operator: LinearOperator, u: torch.Tensor, relative_tolerance: float = 1e-3, absolute_tolerance=1e-5
):
"""Test if an operator is unitary.
"""Test if a linear operator is unitary.
Test if
Operator.adjoint(Operator(u)) == u
Expand All @@ -115,7 +123,7 @@ def operator_unitary_test(
Parameters
----------
operator
operator
linear operator
u
element of the domain of the operator
relative_tolerance
Expand All @@ -129,3 +137,36 @@ def operator_unitary_test(
if the adjointness property does not hold
"""
torch.testing.assert_close(u, operator.adjoint(operator(u)[0])[0], rtol=relative_tolerance, atol=absolute_tolerance)


Tin = TypeVarTuple('Tin')


def autodiff_test(
operator: Operator[Unpack[Tin], tuple[torch.Tensor, ...]],
*u: Unpack[Tin],
):
"""Test if autodiff of an operator is working.
This test does not check that the gradient is correct but simply that it can be calculated using both torch.func.jvp
and torch.func.vjp.
Parameters
----------
operator
operator
u
element(s) of the domain of the operator
Raises
------
AssertionError
if autodiff fails
"""
# Forward-mode autodiff using jvp
with torch.autograd.detect_anomaly():
v_range, _ = torch.func.jvp(operator.forward, u, u)

# Backward-mode autodiff using vjp
with torch.autograd.detect_anomaly():
(_, vjpfunc) = torch.func.vjp(operator.forward, *u)
vjpfunc(v_range)
8 changes: 8 additions & 0 deletions tests/operators/models/test_inversion_recovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
import torch
from mrpro.operators.models import InversionRecovery
from tests import autodiff_test
from tests.operators.models.conftest import SHAPE_VARIATIONS_SIGNAL_MODELS, create_parameter_tensor_tuples


Expand Down Expand Up @@ -39,3 +40,10 @@ def test_inversion_recovery_shape(parameter_shape, contrast_dim_shape, signal_sh
m0, t1 = create_parameter_tensor_tuples(parameter_shape, number_of_tensors=2)
(signal,) = model_op(m0, t1)
assert signal.shape == signal_shape


def test_autodiff_inversion_recovery():
"""Test autodiff works for inversion_recovery model."""
model = InversionRecovery(ti=10)
m0, t1 = create_parameter_tensor_tuples(parameter_shape=(2, 5, 10, 10, 10), number_of_tensors=2)
autodiff_test(model, m0, t1)
9 changes: 8 additions & 1 deletion tests/operators/models/test_molli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest
import torch
from mrpro.operators.models import MOLLI
from tests import RandomGenerator
from tests import RandomGenerator, autodiff_test
from tests.operators.models.conftest import SHAPE_VARIATIONS_SIGNAL_MODELS, create_parameter_tensor_tuples


Expand Down Expand Up @@ -45,3 +45,10 @@ def test_molli_shape(parameter_shape, contrast_dim_shape, signal_shape):
a, c, t1 = create_parameter_tensor_tuples(parameter_shape, number_of_tensors=3)
(signal,) = model_op(a, c, t1)
assert signal.shape == signal_shape


def test_autodiff_molli():
"""Test autodiff works for molli model."""
model = MOLLI(ti=10)
a, b, t1 = create_parameter_tensor_tuples((2, 5, 10, 10, 10), number_of_tensors=3)
autodiff_test(model, a, b, t1)
8 changes: 8 additions & 0 deletions tests/operators/models/test_mono_exponential_decay.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
import torch
from mrpro.operators.models import MonoExponentialDecay
from tests import autodiff_test
from tests.operators.models.conftest import SHAPE_VARIATIONS_SIGNAL_MODELS, create_parameter_tensor_tuples


Expand Down Expand Up @@ -41,3 +42,10 @@ def test_mono_exponential_decay_shape(parameter_shape, contrast_dim_shape, signa
m0, decay_constant = create_parameter_tensor_tuples(parameter_shape, number_of_tensors=2)
(signal,) = model_op(m0, decay_constant)
assert signal.shape == signal_shape


def test_autodiff_exponential_decay():
"""Test autodiff works for mono-exponential decay model."""
model = MonoExponentialDecay(decay_time=20)
m0, decay_constant = create_parameter_tensor_tuples(parameter_shape=(2, 5, 10, 10, 10), number_of_tensors=2)
autodiff_test(model, m0, decay_constant)
8 changes: 8 additions & 0 deletions tests/operators/models/test_saturation_recovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
import torch
from mrpro.operators.models import SaturationRecovery
from tests import autodiff_test
from tests.operators.models.conftest import SHAPE_VARIATIONS_SIGNAL_MODELS, create_parameter_tensor_tuples


Expand Down Expand Up @@ -41,3 +42,10 @@ def test_saturation_recovery_shape(parameter_shape, contrast_dim_shape, signal_s
m0, t1 = create_parameter_tensor_tuples(parameter_shape, number_of_tensors=2)
(signal,) = model_op(m0, t1)
assert signal.shape == signal_shape


def test_autodiff_aturation_recovery():
"""Test autodiff works for aturation recovery model."""
model = SaturationRecovery(ti=10)
m0, t1 = create_parameter_tensor_tuples((2, 5, 10, 10, 10), number_of_tensors=2)
autodiff_test(model, m0, t1)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import torch
from einops import repeat
from mrpro.operators.models import TransientSteadyStateWithPreparation
from tests import autodiff_test
from tests.operators.models.conftest import SHAPE_VARIATIONS_SIGNAL_MODELS, create_parameter_tensor_tuples


Expand Down Expand Up @@ -79,3 +80,17 @@ def test_transient_steady_state_shape(parameter_shape, contrast_dim_shape, signa
m0, t1, flip_angle = create_parameter_tensor_tuples(parameter_shape, number_of_tensors=3)
(signal,) = model_op(m0, t1, flip_angle)
assert signal.shape == signal_shape


def test_autodiff_transient_steady_state():
"""Test autodiff works for transient steady state model."""
contrast_dim_shape = (6,)
(sampling_time,) = create_parameter_tensor_tuples(contrast_dim_shape, number_of_tensors=1)
repetition_time, m0_scaling_preparation, delay_after_preparation = create_parameter_tensor_tuples(
contrast_dim_shape[1:], number_of_tensors=3
)
model = TransientSteadyStateWithPreparation(
sampling_time, repetition_time, m0_scaling_preparation, delay_after_preparation
)
m0, t1, flip_angle = create_parameter_tensor_tuples(parameter_shape=(2, 5, 10, 10, 10), number_of_tensors=3)
autodiff_test(model, m0, t1, flip_angle)
8 changes: 8 additions & 0 deletions tests/operators/models/test_wasabi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import torch
from mrpro.operators.models import WASABI
from tests import autodiff_test
from tests.operators.models.conftest import SHAPE_VARIATIONS_SIGNAL_MODELS, create_parameter_tensor_tuples


Expand Down Expand Up @@ -45,3 +46,10 @@ def test_WASABI_shape(parameter_shape, contrast_dim_shape, signal_shape):
b0_shift, rb1, c, d = create_parameter_tensor_tuples(parameter_shape, number_of_tensors=4)
(signal,) = model_op(b0_shift, rb1, c, d)
assert signal.shape == signal_shape


def test_autodiff_WASABI():
"""Test autodiff works for WASABI model."""
offset, b0_shift, rb1, c, d = create_data(offset_max=300, n_offsets=2)
wasabi_model = WASABI(offsets=offset)
autodiff_test(wasabi_model, b0_shift, rb1, c, d)
9 changes: 9 additions & 0 deletions tests/operators/models/test_wasabiti.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
import torch
from mrpro.operators.models import WASABITI
from tests import autodiff_test
from tests.operators.models.conftest import SHAPE_VARIATIONS_SIGNAL_MODELS, create_parameter_tensor_tuples


Expand Down Expand Up @@ -76,3 +77,11 @@ def test_WASABITI_shape(parameter_shape, contrast_dim_shape, signal_shape):
b0_shift, rb1, t1 = create_parameter_tensor_tuples(parameter_shape, number_of_tensors=3)
(signal,) = model_op(b0_shift, rb1, t1)
assert signal.shape == signal_shape


def test_autodiff_WASABITI():
"""Test autodiff works for WASABITI model."""
offset, b0_shift, rb1, t1 = create_data(offset_max=300, n_offsets=2)
trec = torch.ones_like(offset) * t1
wasabiti_model = WASABITI(offsets=offset, trec=trec)
autodiff_test(wasabiti_model, b0_shift, rb1, t1)
3 changes: 1 addition & 2 deletions tests/operators/test_autograd_linop.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
from mrpro.operators import LinearOperator
from torch.autograd.gradcheck import GradcheckError

from tests import RandomGenerator
from tests.helper import dotproduct_adjointness_test
from tests import RandomGenerator, dotproduct_adjointness_test


class NonDifferentiableOperator(LinearOperator, adjoint_as_backward=False):
Expand Down
3 changes: 1 addition & 2 deletions tests/operators/test_cartesian_sampling_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
from mrpro.data import KTrajectory, SpatialDimension
from mrpro.operators import CartesianSamplingOp

from tests import RandomGenerator
from tests import RandomGenerator, dotproduct_adjointness_test
from tests.conftest import create_traj
from tests.helper import dotproduct_adjointness_test


def test_cart_sampling_op_data_match():
Expand Down
14 changes: 13 additions & 1 deletion tests/operators/test_constraints_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import torch
from mrpro.operators import ConstraintsOp

from tests import RandomGenerator
from tests import RandomGenerator, autodiff_test


@pytest.mark.parametrize(
Expand Down Expand Up @@ -141,3 +141,15 @@ def test_constraints_operator_multiple_inputs(bounds):
def test_constraints_operator_illegal_bounds(bounds):
with pytest.raises(ValueError, match='invalid'):
ConstraintsOp(bounds)


def test_autodiff_constraints_operator():
"""Test autodiff works for constraints operator."""
# random tensors with arbitrary values
random_generator = RandomGenerator(seed=0)
x1 = random_generator.float32_tensor(size=(36, 72), low=-1, high=1)
x2 = random_generator.float32_tensor(size=(36, 72), low=-1, high=1)
x3 = random_generator.float32_tensor(size=(36, 72), low=-1, high=1)

constraints_op = ConstraintsOp(bounds=((None, None), (1.0, None), (None, 1.0)))
autodiff_test(constraints_op, x1, x2, x3)
3 changes: 1 addition & 2 deletions tests/operators/test_density_compensation_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
from mrpro.data import DcfData
from mrpro.operators import DensityCompensationOp

from tests import RandomGenerator
from tests.helper import dotproduct_adjointness_test
from tests import RandomGenerator, dotproduct_adjointness_test


def test_density_compensation_op_adjointness():
Expand Down
3 changes: 1 addition & 2 deletions tests/operators/test_einsum_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import torch
from mrpro.operators.EinsumOp import EinsumOp

from tests import RandomGenerator
from tests.helper import dotproduct_adjointness_test
from tests import RandomGenerator, dotproduct_adjointness_test


@pytest.mark.parametrize('dtype', ['float32', 'complex128'])
Expand Down
3 changes: 1 addition & 2 deletions tests/operators/test_fast_fourier_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from mrpro.data import SpatialDimension
from mrpro.operators import FastFourierOp

from tests import RandomGenerator
from tests.helper import dotproduct_adjointness_test
from tests import RandomGenerator, dotproduct_adjointness_test


@pytest.mark.parametrize(('npoints', 'a'), [(100, 20), (300, 20)])
Expand Down
3 changes: 1 addition & 2 deletions tests/operators/test_finite_difference_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
from einops import repeat
from mrpro.operators import FiniteDifferenceOp

from tests import RandomGenerator
from tests.helper import dotproduct_adjointness_test
from tests import RandomGenerator, dotproduct_adjointness_test


@pytest.mark.parametrize('mode', ['central', 'forward', 'backward'])
Expand Down
3 changes: 1 addition & 2 deletions tests/operators/test_fourier_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
from mrpro.data.traj_calculators import KTrajectoryCartesian
from mrpro.operators import FourierOp

from tests import RandomGenerator
from tests import RandomGenerator, dotproduct_adjointness_test
from tests.conftest import COMMON_MR_TRAJECTORIES, create_traj
from tests.helper import dotproduct_adjointness_test


def create_data(im_shape, k_shape, nkx, nky, nkz, type_kx, type_ky, type_kz):
Expand Down
Loading

3 comments on commit 41ad113

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/mrpro/algorithms/csm
   inati.py24196%44
   walsh.py16194%34
src/mrpro/algorithms/dcf
   dcf_voronoi.py53492%15, 48–49, 76
src/mrpro/algorithms/optimizers
   adam.py20195%69
src/mrpro/algorithms/reconstruction
   DirectReconstruction.py281643%51–71, 85
   IterativeSENSEReconstruction.py13192%76
   Reconstruction.py502256%42, 54–56, 80–87, 104–113
   RegularizedIterativeSENSEReconstruction.py411759%96–100, 114–139
src/mrpro/data
   AcqInfo.py128398%26, 169, 207
   CsmData.py29390%15, 82–84
   DcfData.py45882%18, 66, 78–83
   IData.py67987%119, 125, 129, 159–167
   IHeader.py75791%75, 109, 127–131
   KHeader.py1531789%25, 119–123, 150, 199, 210, 217–218, 221, 228, 260–271
   KNoise.py311552%39–52, 56–61
   KTrajectory.py69593%178–182
   MoveDataMixin.py1371887%15, 113, 129, 143–145, 207, 305–307, 320, 399, 419–420, 422, 437–438, 440
   QData.py39782%42, 65–73
   Rotation.py6743595%100, 198, 335, 433, 477, 495, 581, 583, 592, 626, 628, 691, 768, 773, 776, 791, 808, 813, 889, 1077, 1082, 1085, 1109, 1113, 1240, 1242, 1250–1251, 1315, 1397, 1690, 1846, 1881, 1885, 1996
   SpatialDimension.py2302191%33, 103, 128, 135, 141, 261–263, 276–278, 312, 330, 343, 356, 369, 382, 391–392, 407, 416
   acq_filters.py12192%47
src/mrpro/data/_kdata
   KData.py1341887%109–110, 125, 132, 142, 150, 204–205, 243, 248–249, 268–279
   KDataRemoveOsMixin.py29293%44, 46
   KDataSelectMixin.py19289%48, 63
   KDataSplitMixin.py48394%53, 84, 93
src/mrpro/data/traj_calculators
   KTrajectoryCalculator.py25292%23, 45
   KTrajectoryIsmrmrd.py13285%41, 50
   KTrajectoryPulseq.py29197%54
src/mrpro/operators
   CartesianSamplingOp.py72297%118, 157
   ConstraintsOp.py60297%46, 48
   EndomorphOperator.py65297%228, 234
   FiniteDifferenceOp.py27293%40, 105
   Functional.py71593%20–22, 117, 119
   GridSamplingOp.py136993%72–73, 82–83, 90–91, 94, 96, 98
   LinearOperator.py1711293%55, 91, 190, 220, 261, 270, 278, 287, 295, 320, 418, 423
   LinearOperatorMatrix.py1581690%82, 119, 152, 161, 166, 175–178, 191–194, 203, 215, 304, 331, 359
   MultiIdentityOp.py13285%43, 48
   Operator.py78297%25, 74
   ProximableFunctionalSeparableSum.py39392%50, 103, 110
   SliceProjectionOp.py173895%44, 61, 63, 69, 206, 227, 260, 300
   WaveletOp.py120596%152, 170, 205, 210, 233
   ZeroPadOp.py16194%30
src/mrpro/utils
   filters.py62297%44, 49
   slice_profiles.py46687%20, 36, 113–116, 149
   sliding_window.py34197%34
   split_idx.py10280%43, 47
   summarize_tensorvalues.py11918%20–29
   typing.py181139%8–23
   zero_pad_or_crop.py31681%26, 30, 54, 57, 60, 63
TOTAL477535093% 

Tests Skipped Failures Errors Time
1989 0 💤 0 ❌ 0 🔥 1m 44s ⏱️

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/mrpro/algorithms/csm
   inati.py24196%44
   walsh.py16194%34
src/mrpro/algorithms/dcf
   dcf_voronoi.py53492%15, 48–49, 76
src/mrpro/algorithms/optimizers
   adam.py20195%69
src/mrpro/algorithms/reconstruction
   DirectReconstruction.py281643%51–71, 85
   IterativeSENSEReconstruction.py13192%76
   Reconstruction.py502256%42, 54–56, 80–87, 104–113
   RegularizedIterativeSENSEReconstruction.py411759%96–100, 114–139
src/mrpro/data
   AcqInfo.py128398%26, 169, 207
   CsmData.py29390%15, 82–84
   DcfData.py45882%18, 66, 78–83
   IData.py67987%119, 125, 129, 159–167
   IHeader.py75791%75, 109, 127–131
   KHeader.py1531789%25, 119–123, 150, 199, 210, 217–218, 221, 228, 260–271
   KNoise.py311552%39–52, 56–61
   KTrajectory.py69593%178–182
   MoveDataMixin.py1371887%15, 113, 129, 143–145, 207, 305–307, 320, 399, 419–420, 422, 437–438, 440
   QData.py39782%42, 65–73
   Rotation.py6743595%100, 198, 335, 433, 477, 495, 581, 583, 592, 626, 628, 691, 768, 773, 776, 791, 808, 813, 889, 1077, 1082, 1085, 1109, 1113, 1240, 1242, 1250–1251, 1315, 1397, 1690, 1846, 1881, 1885, 1996
   SpatialDimension.py2302191%33, 103, 128, 135, 141, 261–263, 276–278, 312, 330, 343, 356, 369, 382, 391–392, 407, 416
   acq_filters.py12192%47
src/mrpro/data/_kdata
   KData.py1341887%109–110, 125, 132, 142, 150, 204–205, 243, 248–249, 268–279
   KDataRemoveOsMixin.py29293%44, 46
   KDataSelectMixin.py19289%48, 63
   KDataSplitMixin.py48394%53, 84, 93
src/mrpro/data/traj_calculators
   KTrajectoryCalculator.py25292%23, 45
   KTrajectoryIsmrmrd.py13285%41, 50
   KTrajectoryPulseq.py29197%54
src/mrpro/operators
   CartesianSamplingOp.py72297%118, 157
   ConstraintsOp.py60297%46, 48
   EndomorphOperator.py65297%228, 234
   FiniteDifferenceOp.py27293%40, 105
   Functional.py71593%20–22, 117, 119
   GridSamplingOp.py136993%72–73, 82–83, 90–91, 94, 96, 98
   LinearOperator.py1711293%55, 91, 190, 220, 261, 270, 278, 287, 295, 320, 418, 423
   LinearOperatorMatrix.py1581690%82, 119, 152, 161, 166, 175–178, 191–194, 203, 215, 304, 331, 359
   MultiIdentityOp.py13285%43, 48
   Operator.py78297%25, 74
   ProximableFunctionalSeparableSum.py39392%50, 103, 110
   SliceProjectionOp.py173895%44, 61, 63, 69, 206, 227, 260, 300
   WaveletOp.py120596%152, 170, 205, 210, 233
   ZeroPadOp.py16194%30
src/mrpro/utils
   filters.py62297%44, 49
   slice_profiles.py46687%20, 36, 113–116, 149
   sliding_window.py34197%34
   split_idx.py10280%43, 47
   summarize_tensorvalues.py11918%20–29
   typing.py181139%8–23
   zero_pad_or_crop.py31681%26, 30, 54, 57, 60, 63
TOTAL477535093% 

Tests Skipped Failures Errors Time
1989 0 💤 0 ❌ 0 🔥 1m 41s ⏱️

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/mrpro/algorithms/csm
   inati.py24196%44
   walsh.py16194%34
src/mrpro/algorithms/dcf
   dcf_voronoi.py53492%15, 48–49, 76
src/mrpro/algorithms/optimizers
   adam.py20195%69
src/mrpro/algorithms/reconstruction
   DirectReconstruction.py281643%51–71, 85
   IterativeSENSEReconstruction.py13192%76
   Reconstruction.py502256%42, 54–56, 80–87, 104–113
   RegularizedIterativeSENSEReconstruction.py411759%96–100, 114–139
src/mrpro/data
   AcqInfo.py128398%26, 169, 207
   CsmData.py29390%15, 82–84
   DcfData.py45882%18, 66, 78–83
   IData.py67987%119, 125, 129, 159–167
   IHeader.py75791%75, 109, 127–131
   KHeader.py1531789%25, 119–123, 150, 199, 210, 217–218, 221, 228, 260–271
   KNoise.py311552%39–52, 56–61
   KTrajectory.py69593%178–182
   MoveDataMixin.py1371887%15, 113, 129, 143–145, 207, 305–307, 320, 399, 419–420, 422, 437–438, 440
   QData.py39782%42, 65–73
   Rotation.py6743595%100, 198, 335, 433, 477, 495, 581, 583, 592, 626, 628, 691, 768, 773, 776, 791, 808, 813, 889, 1077, 1082, 1085, 1109, 1113, 1240, 1242, 1250–1251, 1315, 1397, 1690, 1846, 1881, 1885, 1996
   SpatialDimension.py2302191%33, 103, 128, 135, 141, 261–263, 276–278, 312, 330, 343, 356, 369, 382, 391–392, 407, 416
   acq_filters.py12192%47
src/mrpro/data/_kdata
   KData.py1341887%109–110, 125, 132, 142, 150, 204–205, 243, 248–249, 268–279
   KDataRemoveOsMixin.py29293%44, 46
   KDataSelectMixin.py19289%48, 63
   KDataSplitMixin.py48394%53, 84, 93
src/mrpro/data/traj_calculators
   KTrajectoryCalculator.py25292%23, 45
   KTrajectoryIsmrmrd.py13285%41, 50
   KTrajectoryPulseq.py29197%54
src/mrpro/operators
   CartesianSamplingOp.py72297%118, 157
   ConstraintsOp.py60297%46, 48
   EndomorphOperator.py65297%228, 234
   FiniteDifferenceOp.py27293%40, 105
   Functional.py71593%20–22, 117, 119
   GridSamplingOp.py136993%72–73, 82–83, 90–91, 94, 96, 98
   LinearOperator.py1711293%55, 91, 190, 220, 261, 270, 278, 287, 295, 320, 418, 423
   LinearOperatorMatrix.py1581690%82, 119, 152, 161, 166, 175–178, 191–194, 203, 215, 304, 331, 359
   MultiIdentityOp.py13285%43, 48
   Operator.py78297%25, 74
   ProximableFunctionalSeparableSum.py39392%50, 103, 110
   SliceProjectionOp.py173895%44, 61, 63, 69, 206, 227, 260, 300
   WaveletOp.py120596%152, 170, 205, 210, 233
   ZeroPadOp.py16194%30
src/mrpro/utils
   filters.py62297%44, 49
   slice_profiles.py46687%20, 36, 113–116, 149
   sliding_window.py34197%34
   split_idx.py10280%43, 47
   summarize_tensorvalues.py11918%20–29
   typing.py181139%8–23
   zero_pad_or_crop.py31681%26, 30, 54, 57, 60, 63
TOTAL477535093% 

Tests Skipped Failures Errors Time
1989 0 💤 0 ❌ 0 🔥 1m 54s ⏱️

Please sign in to comment.