rosetta-eclab 0.1.3__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/PKG-INFO +2 -2
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/README.md +1 -1
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/library.py +5 -1
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/mprfile.py +13 -1
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/pyproject.toml +1 -1
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/rosetta_eclab.egg-info/PKG-INFO +2 -2
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/tests/test_cli.py +40 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/LICENSE +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/__init__.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/cli.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/data/stats.json +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/data/stats_features.npy +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/debug.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/engine.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/evaluate.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/fallback.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/galvani_ref.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/golden.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/namer/misses.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/rosetta_eclab.egg-info/SOURCES.txt +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/rosetta_eclab.egg-info/dependency_links.txt +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/rosetta_eclab.egg-info/entry_points.txt +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/rosetta_eclab.egg-info/requires.txt +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/rosetta_eclab.egg-info/top_level.txt +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/setup.cfg +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/__init__.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/agent.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/api_check.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/baselines.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/corpus.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/dsl.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/elim.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/features.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/galvani_0.5.0_colmap.json +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/galvani_snapshot.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/lock.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/run.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/score.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/tasks.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/spike2/vocab.py +0 -0
- {rosetta_eclab-0.1.3 → rosetta_eclab-0.1.4}/tests/test_relations.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosetta-eclab
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Name the columns of BioLogic EC-Lab .mpr files that your parser does not know - no language model, evidence for every answer
|
|
5
5
|
Author: Nataniel Ataseven
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -139,7 +139,7 @@ The namer improved between hold-outs, so the total includes earlier versions. Th
|
|
|
139
139
|
- **Values EC-Lab computes after the fact** cannot be reconstructed reliably. For example, a capacitance is held per segment.
|
|
140
140
|
- **Noise-like DC currents** in impedance records, and **external analog inputs** with no sibling column, usually get ABSTAIN.
|
|
141
141
|
- **Two quantities with the same definition in a file** cannot be told apart from the data. In galvanostatic cycling, for example, `dQ` and `Q charge or discharge` reset at the same points. A prior over how common each name is for the technique decides between them, and the alternative is shown.
|
|
142
|
-
- **Supported formats:** EC-Lab data-module versions 2, 3, 10 and 11.
|
|
142
|
+
- **Supported formats:** EC-Lab data-module versions 0, 2, 3, 10 and 11. Version 0 (older EC-Lab) is read with galvani's offsets, because yadg does not read it. All 59 public version-0 files decode byte for byte like galvani 0.5.0, and the two with an EC-Lab text export match it. The file technique is not read from version-0 files, so the namer works without it.
|
|
143
143
|
|
|
144
144
|
## Reproduce the benchmark
|
|
145
145
|
|
|
@@ -114,7 +114,7 @@ The namer improved between hold-outs, so the total includes earlier versions. Th
|
|
|
114
114
|
- **Values EC-Lab computes after the fact** cannot be reconstructed reliably. For example, a capacitance is held per segment.
|
|
115
115
|
- **Noise-like DC currents** in impedance records, and **external analog inputs** with no sibling column, usually get ABSTAIN.
|
|
116
116
|
- **Two quantities with the same definition in a file** cannot be told apart from the data. In galvanostatic cycling, for example, `dQ` and `Q charge or discharge` reset at the same points. A prior over how common each name is for the technique decides between them, and the alternative is shown.
|
|
117
|
-
- **Supported formats:** EC-Lab data-module versions 2, 3, 10 and 11.
|
|
117
|
+
- **Supported formats:** EC-Lab data-module versions 0, 2, 3, 10 and 11. Version 0 (older EC-Lab) is read with galvani's offsets, because yadg does not read it. All 59 public version-0 files decode byte for byte like galvani 0.5.0, and the two with an EC-Lab text export match it. The file technique is not read from version-0 files, so the namer works without it.
|
|
118
118
|
|
|
119
119
|
## Reproduce the benchmark
|
|
120
120
|
|
|
@@ -561,7 +561,11 @@ def build() -> dict[str, Quantity]:
|
|
|
561
561
|
q("z cycle", shapes=[Shape("integer counter in a sequence with impedance", lambda c: 0.75 * is_counter(c) if c.col("freq") is not None else 0.0)])
|
|
562
562
|
q("Ns", shapes=[Shape("sequence index from 0 that changes with the control", lambda c: ns_shape(c))])
|
|
563
563
|
q("I Range", shapes=[Shape("instrument range code (few values, not starting at 0)", lambda c: irange_shape(c))])
|
|
564
|
-
q("Pwe", relations=[
|
|
564
|
+
q("Pwe", relations=[
|
|
565
|
+
Relation("Ewe*I", ("Ewe", CURRENT), lambda c: _e(c) * _i(c), [W_PER_V_MA]),
|
|
566
|
+
# some older EC-Lab files store the power's magnitude (galvani's bio_logic1.mpr and bio_logic3.mpr)
|
|
567
|
+
Relation("|Ewe*I|", ("Ewe", CURRENT), lambda c: np.abs(_e(c) * _i(c)), [W_PER_V_MA]),
|
|
568
|
+
])
|
|
565
569
|
q("Ewe", relations=[
|
|
566
570
|
Relation("Pwe/I", ("Pwe", ("I", "dq", "(Q-Qo)")), lambda c: c.col("Pwe") / _i(c), [1000.0]),
|
|
567
571
|
Relation("follows potential control", ("control",), lambda c: c.col("control"), [1.0]),
|
|
@@ -131,10 +131,19 @@ def read(path: str | Path, reference: str = "galvani") -> MprData:
|
|
|
131
131
|
elif version in (2, 3):
|
|
132
132
|
yids = full = np.frombuffer(data, offset=5, dtype="<u2", count=n_columns).tolist()
|
|
133
133
|
offset = 0x195 if version == 2 else 0x196
|
|
134
|
+
elif version == 0: # older EC-Lab files; offsets as in galvani (yadg 7.0.1 does not read version 0)
|
|
135
|
+
if data[5]: # one byte per column ID; all public version-0 files use this layout
|
|
136
|
+
yids = full = list(data[5:5 + n_columns])
|
|
137
|
+
offset = 100
|
|
138
|
+
else: # galvani: EC-Lab 11.50+ writes [0 1 0 3 0 174 ...]; no public file to test against
|
|
139
|
+
yids = full = list(data[6:5 + 2 * n_columns:2])
|
|
140
|
+
offset = 1007
|
|
134
141
|
else:
|
|
135
142
|
raise NotImplementedError(f"data module version {version} is not supported yet")
|
|
143
|
+
if n_points == 0:
|
|
144
|
+
raise ValueError("the file has no data points")
|
|
136
145
|
region = len(data) - offset
|
|
137
|
-
if
|
|
146
|
+
if region % n_points:
|
|
138
147
|
raise ValueError(f"record size is not a whole number of bytes ({region} / {n_points})")
|
|
139
148
|
rec = region // n_points
|
|
140
149
|
|
|
@@ -142,6 +151,9 @@ def read(path: str | Path, reference: str = "galvani") -> MprData:
|
|
|
142
151
|
gref = galvani_ref.reference() if reference == "galvani" else None
|
|
143
152
|
gmap = gref.colmap if gref else {}
|
|
144
153
|
notes = _galvani_notes(full, gref, version in (10, 11)) if gref else []
|
|
154
|
+
if version == 0 and reference == "yadg":
|
|
155
|
+
notes.append("yadg 7.0.1 cannot read this file at all (data module version 0); "
|
|
156
|
+
"'known' here means listed in yadg's column map")
|
|
145
157
|
layout = [] # record layout in file order: (raw_id or None for the flags byte, ...)
|
|
146
158
|
for yid, fid in zip(yids, full):
|
|
147
159
|
if yid in FLAG_IDS: # all flag IDs share one byte, at the position of the first one
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rosetta-eclab"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.4"
|
|
8
8
|
description = "Name the columns of BioLogic EC-Lab .mpr files that your parser does not know - no language model, evidence for every answer"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "GPL-3.0-or-later"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosetta-eclab
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Name the columns of BioLogic EC-Lab .mpr files that your parser does not know - no language model, evidence for every answer
|
|
5
5
|
Author: Nataniel Ataseven
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -139,7 +139,7 @@ The namer improved between hold-outs, so the total includes earlier versions. Th
|
|
|
139
139
|
- **Values EC-Lab computes after the fact** cannot be reconstructed reliably. For example, a capacitance is held per segment.
|
|
140
140
|
- **Noise-like DC currents** in impedance records, and **external analog inputs** with no sibling column, usually get ABSTAIN.
|
|
141
141
|
- **Two quantities with the same definition in a file** cannot be told apart from the data. In galvanostatic cycling, for example, `dQ` and `Q charge or discharge` reset at the same points. A prior over how common each name is for the technique decides between them, and the alternative is shown.
|
|
142
|
-
- **Supported formats:** EC-Lab data-module versions 2, 3, 10 and 11.
|
|
142
|
+
- **Supported formats:** EC-Lab data-module versions 0, 2, 3, 10 and 11. Version 0 (older EC-Lab) is read with galvani's offsets, because yadg does not read it. All 59 public version-0 files decode byte for byte like galvani 0.5.0, and the two with an EC-Lab text export match it. The file technique is not read from version-0 files, so the namer works without it.
|
|
143
143
|
|
|
144
144
|
## Reproduce the benchmark
|
|
145
145
|
|
|
@@ -45,6 +45,46 @@ def test_reader_matches_reference_decoder():
|
|
|
45
45
|
assert a == b, name
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
def _mpt(path: Path) -> dict[str, np.ndarray]:
|
|
49
|
+
lines = path.read_bytes().decode("latin-1").splitlines()
|
|
50
|
+
n_header = int(lines[1].split(":")[1])
|
|
51
|
+
head = lines[n_header - 1].rstrip("\t").split("\t")
|
|
52
|
+
rows = [line.rstrip("\t").split("\t") for line in lines[n_header:] if line.strip()]
|
|
53
|
+
return {h: np.array([float(r[i].replace(",", ".")) for r in rows]) for i, h in enumerate(head)}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_version_0_files_match_the_vendor_export():
|
|
57
|
+
"""Data module version 0 (older EC-Lab): yadg cannot read it; the values must match EC-Lab's own .mpt."""
|
|
58
|
+
m = mprfile.read(EXT / "bio_logic1.mpr", reference="galvani")
|
|
59
|
+
mpt = _mpt(EXT / "bio_logic1.mpt")
|
|
60
|
+
cols = {c.name: c.values.astype("f8") for c in m.columns}
|
|
61
|
+
assert m.n_points == len(mpt["time/s"]) == 3119 and not m.unknown
|
|
62
|
+
for name, ref in (("time", "time/s"), ("Ewe", "Ewe/V"), ("dq", "dq/mA.h"), ("Pwe", "P/W")):
|
|
63
|
+
np.testing.assert_allclose(cols[name], mpt[ref], rtol=1e-6, atol=1e-9, err_msg=name)
|
|
64
|
+
assert any("yadg 7.0.1 cannot read" in n for n in mprfile.read(EXT / "bio_logic1.mpr", reference="yadg").notes)
|
|
65
|
+
assert not any("yadg" in n for n in m.notes)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_empty_file_is_reported_plainly():
|
|
69
|
+
with pytest.raises(ValueError, match="no data points"):
|
|
70
|
+
mprfile.read(EXT / "wait.mpr")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_power_magnitude_in_version_0_file_is_named(tmp_path):
|
|
74
|
+
"""Version-0 files store |Ewe*I| as the power; hidden, it must come back as Pwe (it was named Ece)."""
|
|
75
|
+
raw = bytearray((EXT / "bio_logic1.mpr").read_bytes())
|
|
76
|
+
mdata = next(md for name, _v, md in mprfile._modules(bytes(raw)) if name == "VMP data")
|
|
77
|
+
start = bytes(raw).index(mdata)
|
|
78
|
+
ids = list(raw[start + 5: start + 5 + raw[start + 4]])
|
|
79
|
+
raw[start + 5 + ids.index(70)] = 255 # one-byte column IDs in version 0
|
|
80
|
+
f = tmp_path / "old_drift.mpr"
|
|
81
|
+
f.write_bytes(bytes(raw))
|
|
82
|
+
m = mprfile.read(f, reference="galvani")
|
|
83
|
+
assert [c.raw_id for c in m.unknown] == [255]
|
|
84
|
+
res = cli.name_unknown(m)
|
|
85
|
+
assert res[0]["verdict"] == "NAME" and res[0]["name"] == "Pwe", res[0]
|
|
86
|
+
|
|
87
|
+
|
|
48
88
|
def test_real_drift_duplicates_are_reported():
|
|
49
89
|
m = mprfile.read(EXT / "gcpl.issue_230.mpr", reference="galvani")
|
|
50
90
|
assert [c.raw_id for c in m.unknown] == [883, 884]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|