rosetta-eclab 0.1.1__tar.gz → 0.1.2__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.
Files changed (38) hide show
  1. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/PKG-INFO +24 -2
  2. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/README.md +23 -1
  3. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/cli.py +3 -2
  4. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/mprfile.py +18 -1
  5. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/pyproject.toml +1 -1
  6. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/rosetta_eclab.egg-info/PKG-INFO +24 -2
  7. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/tests/test_cli.py +9 -0
  8. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/LICENSE +0 -0
  9. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/__init__.py +0 -0
  10. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/data/stats.json +0 -0
  11. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/data/stats_features.npy +0 -0
  12. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/debug.py +0 -0
  13. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/engine.py +0 -0
  14. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/evaluate.py +0 -0
  15. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/fallback.py +0 -0
  16. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/golden.py +0 -0
  17. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/library.py +0 -0
  18. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/namer/misses.py +0 -0
  19. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/rosetta_eclab.egg-info/SOURCES.txt +0 -0
  20. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/rosetta_eclab.egg-info/dependency_links.txt +0 -0
  21. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/rosetta_eclab.egg-info/entry_points.txt +0 -0
  22. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/rosetta_eclab.egg-info/requires.txt +0 -0
  23. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/rosetta_eclab.egg-info/top_level.txt +0 -0
  24. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/setup.cfg +0 -0
  25. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/__init__.py +0 -0
  26. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/agent.py +0 -0
  27. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/api_check.py +0 -0
  28. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/baselines.py +0 -0
  29. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/corpus.py +0 -0
  30. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/dsl.py +0 -0
  31. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/elim.py +0 -0
  32. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/features.py +0 -0
  33. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/lock.py +0 -0
  34. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/run.py +0 -0
  35. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/score.py +0 -0
  36. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/tasks.py +0 -0
  37. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/spike2/vocab.py +0 -0
  38. {rosetta_eclab-0.1.1 → rosetta_eclab-0.1.2}/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.1
3
+ Version: 0.1.2
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
@@ -39,7 +39,7 @@ drift.mpr
39
39
  evidence: relation: I*dt summed within half cycle: r2 1.0000, scale 0.0002778
40
40
  also considered: dQ, step time
41
41
 
42
- self-check: hid each of 11 known columns in turn; named 11, 11 correctly, 0 wrong, the rest abstained
42
+ self-check: hid each of 11 known columns in turn; named 11, 11 correctly, 0 wrong, 0 abstained
43
43
  ```
44
44
 
45
45
  *`drift.mpr` is `gcpl.mpr` from the yadg test suite, with one column ID changed to 950, an ID no parser knows (see `tests/test_cli.py`).*
@@ -76,6 +76,28 @@ Each unknown column gets one of three answers:
76
76
 
77
77
  `--self-check` shows how well Rosetta knows *your* kind of file. It hides each known column in turn and tries to name it.
78
78
 
79
+ ## If galvani stops with "Column ID … is unknown"
80
+
81
+ In files from EC-Lab 11.50 and later, galvani 0.5.0 reads only the low byte of each column ID. IDs of 256 and above therefore turn into other IDs:
82
+
83
+ | Real ID | Column | galvani 0.5.0 sees |
84
+ |---|---|---|
85
+ | 471 | `<Ece>/V` | 215 |
86
+ | 438 | `step time/s` | 182 |
87
+ | 431–433 | `\|Zwe-ce\|`, `Re(Zwe-ce)`, `-Im(Zwe-ce)` | 175–177 |
88
+
89
+ The column is often one that galvani already knows. Rosetta reads the full IDs and says so:
90
+
91
+ ```
92
+ $ rosetta peis.issue_225.with_ece.mpr
93
+ peis.issue_225.with_ece.mpr
94
+ technique PEIS, 32 rows, 112 bytes per record
95
+ galvani 0.5.0 reads only the low byte of each column ID in this file layout, so it misreads 471 as 215, 430 as 174, 431 as 175, 432 as 176, 433 as 177
96
+ every column ID is in galvani's column map; nothing to name
97
+ ```
98
+
99
+ The fix was released in datalab-org-galvani 0.6.0 ([galvani-mirror#11](https://github.com/datalab-org/galvani-mirror/issues/11)). IDs that are missing from the map altogether, such as 880 or 883 and 884, are what Rosetta names.
100
+
79
101
  ## How it works
80
102
 
81
103
  1. **Read the file** (`namer/mprfile.py`). Columns the reference parser knows are typed from its column map. For unknown IDs the byte width is solved from the record size, and the storage type is chosen by plausibility.
@@ -14,7 +14,7 @@ drift.mpr
14
14
  evidence: relation: I*dt summed within half cycle: r2 1.0000, scale 0.0002778
15
15
  also considered: dQ, step time
16
16
 
17
- self-check: hid each of 11 known columns in turn; named 11, 11 correctly, 0 wrong, the rest abstained
17
+ self-check: hid each of 11 known columns in turn; named 11, 11 correctly, 0 wrong, 0 abstained
18
18
  ```
19
19
 
20
20
  *`drift.mpr` is `gcpl.mpr` from the yadg test suite, with one column ID changed to 950, an ID no parser knows (see `tests/test_cli.py`).*
@@ -51,6 +51,28 @@ Each unknown column gets one of three answers:
51
51
 
52
52
  `--self-check` shows how well Rosetta knows *your* kind of file. It hides each known column in turn and tries to name it.
53
53
 
54
+ ## If galvani stops with "Column ID … is unknown"
55
+
56
+ In files from EC-Lab 11.50 and later, galvani 0.5.0 reads only the low byte of each column ID. IDs of 256 and above therefore turn into other IDs:
57
+
58
+ | Real ID | Column | galvani 0.5.0 sees |
59
+ |---|---|---|
60
+ | 471 | `<Ece>/V` | 215 |
61
+ | 438 | `step time/s` | 182 |
62
+ | 431–433 | `\|Zwe-ce\|`, `Re(Zwe-ce)`, `-Im(Zwe-ce)` | 175–177 |
63
+
64
+ The column is often one that galvani already knows. Rosetta reads the full IDs and says so:
65
+
66
+ ```
67
+ $ rosetta peis.issue_225.with_ece.mpr
68
+ peis.issue_225.with_ece.mpr
69
+ technique PEIS, 32 rows, 112 bytes per record
70
+ galvani 0.5.0 reads only the low byte of each column ID in this file layout, so it misreads 471 as 215, 430 as 174, 431 as 175, 432 as 176, 433 as 177
71
+ every column ID is in galvani's column map; nothing to name
72
+ ```
73
+
74
+ The fix was released in datalab-org-galvani 0.6.0 ([galvani-mirror#11](https://github.com/datalab-org/galvani-mirror/issues/11)). IDs that are missing from the map altogether, such as 880 or 883 and 884, are what Rosetta names.
75
+
54
76
  ## How it works
55
77
 
56
78
  1. **Read the file** (`namer/mprfile.py`). Columns the reference parser knows are typed from its column map. For unknown IDs the byte width is solved from the record size, and the storage type is chosen by plausibility.
@@ -88,7 +88,7 @@ def main(argv: list[str] | None = None) -> int:
88
88
  for n in m.notes:
89
89
  print(f" {n}")
90
90
  if not result["unknown_columns"]:
91
- print(f" every column is known to {a.reference}; nothing to name")
91
+ print(f" every column ID is in {a.reference}'s column map; nothing to name")
92
92
  for u in result["unknown_columns"]:
93
93
  if u["verdict"] == "NAME":
94
94
  head = f"{u['name']} [{u['unit'] or 'no unit'}] (confidence {u['confidence']})"
@@ -103,7 +103,8 @@ def main(argv: list[str] | None = None) -> int:
103
103
  if a.self_check:
104
104
  s = result["self_check"]
105
105
  print(f"\n self-check: hid each of {s['hidden_one_at_a_time']} known columns in turn; named {s['named']}, "
106
- f"{s['named_correctly']} correctly, {len(s['wrong'])} wrong, the rest abstained")
106
+ f"{s['named_correctly']} correctly, {len(s['wrong'])} wrong, "
107
+ f"{s['hidden_one_at_a_time'] - s['named']} abstained")
107
108
  for w in s["wrong"]:
108
109
  print(f" wrong: {w['column']} -> {w['answer']}")
109
110
  return 0
@@ -79,6 +79,23 @@ def _plausibility(v: np.ndarray, dtype: str) -> float:
79
79
  return 0.9 if span < 2 ** (8 * width - 4) else 0.2
80
80
 
81
81
 
82
+ def _galvani_low_byte_note(full_ids: list[int], gmap: dict) -> list[str]:
83
+ """galvani 0.5.0 reads only the low byte of each column ID in the 11.50+ layout.
84
+
85
+ IDs above 255 then become other IDs (471 -> 215), which galvani either does not
86
+ know (it stops) or knows as a different column. Its map repeats a few entries at
87
+ the low-byte ID (211 = 467), so only IDs whose low-byte entry differs are listed.
88
+ """
89
+ misread = [x for x in full_ids if x > 255 and gmap.get(x & 0xFF) != gmap.get(x)]
90
+ if not misread:
91
+ return []
92
+ from importlib.metadata import version
93
+
94
+ pairs = ", ".join(f"{x} as {x & 0xFF}" for x in misread)
95
+ return [f"galvani {version('galvani')} reads only the low byte of each column ID in this file layout, "
96
+ f"so it misreads {pairs}"]
97
+
98
+
82
99
  def read(path: str | Path, reference: str = "galvani") -> MprData:
83
100
  from galvani import BioLogic
84
101
  from yadg.extractors.eclab.mpr import parse_columns, process_settings
@@ -117,6 +134,7 @@ def read(path: str | Path, reference: str = "galvani") -> MprData:
117
134
 
118
135
  names, dtypes, units, _ = parse_columns(yids, technique) # yadg's map: names for known columns
119
136
  gmap = {int(k): v for k, v in BioLogic.VMPdata_colID_dtype_map.items()}
137
+ notes = _galvani_low_byte_note(full, gmap) if version in (10, 11) and reference == "galvani" else []
120
138
  layout = [] # record layout in file order: (raw_id or None for the flags byte, ...)
121
139
  for yid, fid in zip(yids, full):
122
140
  if yid in FLAG_IDS: # all flag IDs share one byte, at the position of the first one
@@ -146,7 +164,6 @@ def read(path: str | Path, reference: str = "galvani") -> MprData:
146
164
  known_width = sum(np.dtype(d).itemsize for _, _, _, d, kn in filled if kn)
147
165
  unknown_idx = [i for i, e in enumerate(filled) if not e[4]]
148
166
  rest = rec - known_width
149
- notes = []
150
167
  best = None
151
168
  if unknown_idx:
152
169
  combos = [c for c in itertools.product((1, 2, 4, 8), repeat=len(unknown_idx)) if sum(c) == rest]
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rosetta-eclab"
7
- version = "0.1.1"
7
+ version = "0.1.2"
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.1
3
+ Version: 0.1.2
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
@@ -39,7 +39,7 @@ drift.mpr
39
39
  evidence: relation: I*dt summed within half cycle: r2 1.0000, scale 0.0002778
40
40
  also considered: dQ, step time
41
41
 
42
- self-check: hid each of 11 known columns in turn; named 11, 11 correctly, 0 wrong, the rest abstained
42
+ self-check: hid each of 11 known columns in turn; named 11, 11 correctly, 0 wrong, 0 abstained
43
43
  ```
44
44
 
45
45
  *`drift.mpr` is `gcpl.mpr` from the yadg test suite, with one column ID changed to 950, an ID no parser knows (see `tests/test_cli.py`).*
@@ -76,6 +76,28 @@ Each unknown column gets one of three answers:
76
76
 
77
77
  `--self-check` shows how well Rosetta knows *your* kind of file. It hides each known column in turn and tries to name it.
78
78
 
79
+ ## If galvani stops with "Column ID … is unknown"
80
+
81
+ In files from EC-Lab 11.50 and later, galvani 0.5.0 reads only the low byte of each column ID. IDs of 256 and above therefore turn into other IDs:
82
+
83
+ | Real ID | Column | galvani 0.5.0 sees |
84
+ |---|---|---|
85
+ | 471 | `<Ece>/V` | 215 |
86
+ | 438 | `step time/s` | 182 |
87
+ | 431–433 | `\|Zwe-ce\|`, `Re(Zwe-ce)`, `-Im(Zwe-ce)` | 175–177 |
88
+
89
+ The column is often one that galvani already knows. Rosetta reads the full IDs and says so:
90
+
91
+ ```
92
+ $ rosetta peis.issue_225.with_ece.mpr
93
+ peis.issue_225.with_ece.mpr
94
+ technique PEIS, 32 rows, 112 bytes per record
95
+ galvani 0.5.0 reads only the low byte of each column ID in this file layout, so it misreads 471 as 215, 430 as 174, 431 as 175, 432 as 176, 433 as 177
96
+ every column ID is in galvani's column map; nothing to name
97
+ ```
98
+
99
+ The fix was released in datalab-org-galvani 0.6.0 ([galvani-mirror#11](https://github.com/datalab-org/galvani-mirror/issues/11)). IDs that are missing from the map altogether, such as 880 or 883 and 884, are what Rosetta names.
100
+
79
101
  ## How it works
80
102
 
81
103
  1. **Read the file** (`namer/mprfile.py`). Columns the reference parser knows are typed from its column map. For unknown IDs the byte width is solved from the record size, and the storage type is chosen by plausibility.
@@ -51,6 +51,15 @@ def test_real_drift_duplicates_are_reported():
51
51
  assert [r["verdict"] for r in res] == ["DUPLICATE", "DUPLICATE"]
52
52
 
53
53
 
54
+ def test_galvani_low_byte_misreads_are_reported():
55
+ """galvani 0.5.0 stops on this file only because it reads 471 (<Ece>/V) as 215; nothing is unknown."""
56
+ m = mprfile.read(EXT / "peis.issue_225.with_ece.mpr", reference="galvani")
57
+ assert m.unknown == []
58
+ assert any("471 as 215" in n for n in m.notes), m.notes
59
+ assert not any("low byte" in n for n in mprfile.read(EXT / "gcpl.mpr", reference="galvani").notes)
60
+ assert not any("low byte" in n for n in mprfile.read(EXT / "peis.issue_225.with_ece.mpr", reference="yadg").notes)
61
+
62
+
54
63
  @pytest.mark.parametrize("old_id,expected", [(467, "Q charge or discharge"), (7, "dq"), (4, "time")])
55
64
  def test_simulated_drift_is_named(tmp_path, old_id, expected):
56
65
  f = tmp_path / "drift.mpr"
File without changes
File without changes