Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions eitprocessing/datahandling/loading/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def load_eit_data(
) -> Sequence:
"""Load EIT data from path(s).

Current limitations:
- Dräger data is assumed to have a limited set of (Medibus) data. Newer additions that add data like pleural
pressure are not yet supported.

Args:
path: relative or absolute path(s) to data file.
vendor: vendor indicating the device used.
Expand Down Expand Up @@ -64,6 +68,10 @@ def load_eit_data(
Vendor.SENTEC: sentec.load_from_single_path,
}[vendor]

if vendor == Vendor.DRAEGER and not sample_frequency:
msg = """Provide a sample frequency when loading Draeger data."""
raise NotImplementedError(msg) # automatic sample frequency detection is to be implemented per #217

first_frame = _check_first_frame(first_frame)

paths = EITData.ensure_path_list(path)
Expand Down
10 changes: 6 additions & 4 deletions eitprocessing/datahandling/loading/draeger.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,12 @@
from numpy.typing import NDArray

_FRAME_SIZE_BYTES = 4358
DRAEGER_SAMPLE_FREQUENCY = 20
load_draeger_data = partial(load_eit_data, vendor=Vendor.DRAEGER)


def load_from_single_path(
path: Path,
sample_frequency: float | None = 20,
sample_frequency: float,
first_frame: int = 0,
max_frames: int | None = None,
) -> dict[str, DataCollection]:
Expand All @@ -38,7 +37,9 @@ def load_from_single_path(
if file_size % _FRAME_SIZE_BYTES:
msg = (
f"File size {file_size} of file {path!s} not divisible by {_FRAME_SIZE_BYTES}.\n"
f"Make sure this is a valid and uncorrupted Dräger data file."
"Currently this package does not support loading files containing "
"esophageal pressure or other non-standard data. "
"Make sure this is a valid and uncorrupted Dräger data file."
Comment on lines 39 to +42
Copy link
Member

@DaniBodor DaniBodor Dec 16, 2024

Choose a reason for hiding this comment

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

Is this clearer? Also is it worthwhile explicitly stating to re-save files excluding those data and trying again?

Suggested change
f"File size {file_size} of file {path!s} not divisible by {_FRAME_SIZE_BYTES}.\n"
f"Make sure this is a valid and uncorrupted Dräger data file."
"Currently this package does not support loading files containing "
"esophageal pressure or other non-standard data. "
"Make sure this is a valid and uncorrupted Dräger data file."
f"<{path!s}> cannot be loaded due to an incompatible file size.\n"
"Make sure this is a valid and uncorrupted Dräger data file.\n"
"Note that this package does not currently support loading"
"files containing esophageal pressure or other non-standard data."

)
raise OSError(msg)
total_frames = file_size // _FRAME_SIZE_BYTES
Expand Down Expand Up @@ -88,7 +89,8 @@ def load_from_single_path(
)

if not sample_frequency:
sample_frequency = DRAEGER_SAMPLE_FREQUENCY
msg = "No sample frequency provided. "
raise ValueError(msg)

eit_data = EITData(
vendor=Vendor.DRAEGER,
Expand Down
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@

@pytest.fixture(scope="session")
def draeger1():
return load_eit_data(draeger_file1, vendor="draeger", label="draeger1")
return load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20, label="draeger1")


@pytest.fixture(scope="session")
def draeger2():
return load_eit_data(draeger_file2, vendor="draeger", label="draeger2")
return load_eit_data(draeger_file2, vendor="draeger", sample_frequency=20, label="draeger2")


@pytest.fixture(scope="session")
def draeger_both():
return load_eit_data([draeger_file2, draeger_file1], vendor="draeger", label="draeger_both")
return load_eit_data([draeger_file2, draeger_file1], vendor="draeger", sample_frequency=20, label="draeger_both")


@pytest.fixture(scope="session")
Expand Down
4 changes: 2 additions & 2 deletions tests/mixins/test_eq.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@


def test_eq():
data = load_eit_data(draeger_file1, vendor="draeger")
data2 = load_eit_data(draeger_file1, vendor="draeger")
data = load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20)
data2 = load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20)

data.isequivalent(data2)

Expand Down
4 changes: 2 additions & 2 deletions tests/test_labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


def test_default_label(draeger1: Sequence):
draeger_default = load_eit_data(draeger_file1, vendor="draeger")
draeger_default = load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20)
assert isinstance(draeger_default.label, str)
assert draeger_default.label == f"Sequence_{id(draeger_default)}"

Expand All @@ -15,7 +15,7 @@ def test_default_label(draeger1: Sequence):
assert timpel_default.label == f"Sequence_{id(timpel_default)}"

# test that default label changes upon reloading identical data
draeger_reloaded = load_eit_data(draeger_file1, vendor="draeger")
draeger_reloaded = load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20)
assert draeger_default == draeger_reloaded
assert draeger_default.label != draeger_reloaded.label
assert draeger_default.label != draeger1.label
Expand Down
54 changes: 35 additions & 19 deletions tests/test_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

from eitprocessing.datahandling.eitdata import EITData, Vendor
from eitprocessing.datahandling.loading import load_eit_data
from eitprocessing.datahandling.loading.draeger import DRAEGER_SAMPLE_FREQUENCY
from eitprocessing.datahandling.sequence import Sequence
from tests.conftest import draeger_file1, draeger_file2, draeger_file3, dummy_file, timpel_file
from tests.conftest import (
draeger_file1,
draeger_file2,
draeger_file3,
dummy_file,
timpel_file,
)

# ruff: noqa: ERA001 #TODO: remove this line

Expand All @@ -20,8 +25,8 @@ def test_loading_draeger(
assert len(draeger1.eit_data["raw"]) == len(draeger1.eit_data["raw"].time)
assert len(draeger2.eit_data["raw"].time) == 20740

assert draeger1 == load_eit_data(draeger_file1, vendor="draeger", label="draeger1")
assert draeger1 == load_eit_data(draeger_file1, vendor="draeger", label="something_else")
assert draeger1 == load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20, label="draeger1")
assert draeger1 == load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20, label="something_else")
assert draeger1 != draeger2

# Load multiple
Expand Down Expand Up @@ -55,13 +60,17 @@ def test_loading_illegal():
# non existing
for vendor in ["draeger", "timpel"]:
with pytest.raises(FileNotFoundError):
_ = load_eit_data(dummy_file, vendor=vendor)
_ = load_eit_data(dummy_file, vendor=vendor, sample_frequency=20)

# incorrect vendor
with pytest.raises(OSError):
_ = load_eit_data(draeger_file1, vendor="timpel")
with pytest.raises(OSError):
_ = load_eit_data(timpel_file, vendor="draeger")
_ = load_eit_data(timpel_file, vendor="draeger", sample_frequency=20)

# no sample frequency provided
with pytest.raises(NotImplementedError):
_ = load_eit_data(timpel_file, vendor="draeger", sample_frequency=None)


def test_load_partial(
Expand All @@ -79,8 +88,8 @@ def test_load_partial(
# file for this situation.

# Timpel
timpel_part1 = load_eit_data(timpel_file, "timpel", max_frames=cutoff, label="timpel_part_1")
timpel_part2 = load_eit_data(timpel_file, "timpel", first_frame=cutoff, label="timpel_part2")
timpel_part1 = load_eit_data(timpel_file, vendor="timpel", max_frames=cutoff, label="timpel_part_1")
timpel_part2 = load_eit_data(timpel_file, vendor="timpel", first_frame=cutoff, label="timpel_part2")

assert len(timpel_part1) == cutoff
assert len(timpel_part2) == len(timpel1) - cutoff
Expand All @@ -90,8 +99,20 @@ def test_load_partial(
# assert Sequence.concatenate(timpel_part2, timpel_part1) != timpel1

# Draeger
draeger2_part1 = load_eit_data(draeger_file2, "draeger", max_frames=cutoff, label="draeger_part_1")
draeger2_part2 = load_eit_data(draeger_file2, "draeger", first_frame=cutoff, label="draeger_part_2")
draeger2_part1 = load_eit_data(
draeger_file2,
vendor="draeger",
sample_frequency=20,
max_frames=cutoff,
label="draeger_part_1",
)
draeger2_part2 = load_eit_data(
draeger_file2,
vendor="draeger",
sample_frequency=20,
first_frame=cutoff,
label="draeger_part_2",
)

assert len(draeger2_part1) == cutoff
assert len(draeger2_part2) == len(draeger2) - cutoff
Expand All @@ -108,24 +129,19 @@ def test_load_partial(
def test_illegal_first_frame():
for ff in [0.5, -1, "fdw", 1e12]:
with pytest.raises((TypeError, ValueError)):
_ = load_eit_data(draeger_file1, "draeger", first_frame=ff)
_ = load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20, first_frame=ff)

for ff2 in [0, 0.0, 1.0, None]:
_ = load_eit_data(draeger_file1, "draeger", first_frame=ff2)
_ = load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20, first_frame=ff2)


def test_max_frames_too_large():
with pytest.warns():
_ = load_eit_data(draeger_file1, "draeger", max_frames=1e12)


def test_sample_frequency_unset():
loaded_draeger = load_eit_data(draeger_file1, "draeger", sample_frequency=None)
assert loaded_draeger.eit_data["raw"].sample_frequency == DRAEGER_SAMPLE_FREQUENCY
_ = load_eit_data(draeger_file1, vendor="draeger", sample_frequency=20, max_frames=1e12)


def test_event_on_first_frame(draeger2: Sequence):
draeger3 = load_eit_data(draeger_file3, vendor="draeger")
draeger3 = load_eit_data(draeger_file3, vendor="draeger", sample_frequency=20)
draeger3_events = draeger3.sparse_data["events_(draeger)"]
assert draeger3_events == draeger2.sparse_data["events_(draeger)"]
assert draeger3_events.time[0] == draeger3.eit_data["raw"].time[0]
Loading