From 834455fcdd4f14946e7d914060ea2ead28c10cce Mon Sep 17 00:00:00 2001 From: Michael Clerx Date: Mon, 5 Oct 2026 17:26:16 +0100 Subject: [PATCH 1/3] Added support for reading patchliner e data (different chip layout) --- syncropatch_export/trace.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/syncropatch_export/trace.py b/syncropatch_export/trace.py index 2737fb5..9a491b9 100644 --- a/syncropatch_export/trace.py +++ b/syncropatch_export/trace.py @@ -1,6 +1,5 @@ import json import os -import string import numpy as np @@ -53,20 +52,27 @@ def __init__(self, filepath, json_file: str): self.MeasurementLayout = TraceHeader['MeasurementLayout'] self.FileInformation = TraceHeader['FileInformation'] - # Create (hardcoded) list-of-list of well names: + # Create list-of-list of well names: # [['A01', 'B01', ..., 'P01'], # ['A02', 'B02', ..., 'P02'], # ... # ['A24', 'B24', ..., 'P24']] # So a list of 24 lists with 16 entries each - # + self.WP_nRows = TraceHeader['Chiplayout']['WP_nRows'] + self.WP_nCols = TraceHeader['Chiplayout']['WP_nCols'] + if self.WP_nCols > 26: + raise NotImplementedError( # pragma: no cover + 'Unsupported chip layout (more than 26 columns)') + if self.WP_nRows > 100: + raise NotImplementedError( # pragma: no cover + 'Unsupported chip layout (more than 100 rows)') + abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' self.WELL_ID = np.array([ - [lab + str(i).zfill(2) for lab in string.ascii_uppercase[:16]] - for i in range(1, 25)]) + [f'{abc[i]}{j:>02}' for j in range(self.WP_nRows)] + for i in range(self.WP_nCols) + ]) self.NofSweeps = self.MeasurementLayout['NofSweeps'] - self.WP_nRows = TraceHeader['Chiplayout']['WP_nRows'] - self.WP_nCols = TraceHeader['Chiplayout']['WP_nCols'] self.nCols = self.MeasurementLayout['nCols'] self.NofSamples = self.MeasurementLayout['NofSamples'] self.Leakdata = self.MeasurementLayout['Leakdata'] From 8af2f63f739571126453cb9efa0b38403efba982 Mon Sep 17 00:00:00 2001 From: Michael Clerx Date: Thu, 8 Oct 2026 10:50:50 +0100 Subject: [PATCH 2/3] Apply batched suggestions from code review Co-authored-by: Kwabena Amponsah --- syncropatch_export/trace.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/syncropatch_export/trace.py b/syncropatch_export/trace.py index 9a491b9..b3e5787 100644 --- a/syncropatch_export/trace.py +++ b/syncropatch_export/trace.py @@ -52,7 +52,7 @@ def __init__(self, filepath, json_file: str): self.MeasurementLayout = TraceHeader['MeasurementLayout'] self.FileInformation = TraceHeader['FileInformation'] - # Create list-of-list of well names: + # Create list-of-list of well names, e.g. for SyncroPatch: # [['A01', 'B01', ..., 'P01'], # ['A02', 'B02', ..., 'P02'], # ... @@ -60,16 +60,16 @@ def __init__(self, filepath, json_file: str): # So a list of 24 lists with 16 entries each self.WP_nRows = TraceHeader['Chiplayout']['WP_nRows'] self.WP_nCols = TraceHeader['Chiplayout']['WP_nCols'] - if self.WP_nCols > 26: + if self.WP_nCols > 99: raise NotImplementedError( # pragma: no cover - 'Unsupported chip layout (more than 26 columns)') - if self.WP_nRows > 100: + 'Unsupported chip layout (more than 99 columns)') + if self.WP_nRows > 26: raise NotImplementedError( # pragma: no cover - 'Unsupported chip layout (more than 100 rows)') + 'Unsupported chip layout (more than 26 rows)') abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' self.WELL_ID = np.array([ - [f'{abc[i]}{j:>02}' for j in range(self.WP_nRows)] - for i in range(self.WP_nCols) + [f'{abc[i]}{j:>02}' for i in range(self.WP_nRows)] + for j in range(1, self.WP_nCols + 1) ]) self.NofSweeps = self.MeasurementLayout['NofSweeps'] From 25ef7641b35af083535ad3f1a89bfc1b5f4ae516 Mon Sep 17 00:00:00 2001 From: Michael Clerx Date: Thu, 8 Oct 2026 10:53:11 +0100 Subject: [PATCH 3/3] Added tests for row/column order of well names --- syncropatch_export/trace.py | 7 ++++--- tests/test_trace_class.py | 15 +++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/syncropatch_export/trace.py b/syncropatch_export/trace.py index b3e5787..edd70d9 100644 --- a/syncropatch_export/trace.py +++ b/syncropatch_export/trace.py @@ -58,14 +58,15 @@ def __init__(self, filepath, json_file: str): # ... # ['A24', 'B24', ..., 'P24']] # So a list of 24 lists with 16 entries each + # "rows" here is columns in the above matrix! self.WP_nRows = TraceHeader['Chiplayout']['WP_nRows'] self.WP_nCols = TraceHeader['Chiplayout']['WP_nCols'] - if self.WP_nCols > 99: - raise NotImplementedError( # pragma: no cover - 'Unsupported chip layout (more than 99 columns)') if self.WP_nRows > 26: raise NotImplementedError( # pragma: no cover 'Unsupported chip layout (more than 26 rows)') + if self.WP_nCols > 99: + raise NotImplementedError( # pragma: no cover + 'Unsupported chip layout (more than 99 columns)') abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' self.WELL_ID = np.array([ [f'{abc[i]}{j:>02}' for i in range(self.WP_nRows)] diff --git a/tests/test_trace_class.py b/tests/test_trace_class.py index 1d2de6c..b29190d 100755 --- a/tests/test_trace_class.py +++ b/tests/test_trace_class.py @@ -90,17 +90,24 @@ def test_get_QC(self): self.assertGreater(len(QC_values), 0) def test_get_traces(self): + + # Check well ids + self.assertEqual(self.trace.WELL_ID[3, 2], 'C04') + self.assertEqual(len(self.trace.WELL_ID), 24) + self.assertEqual(len(self.trace.WELL_ID[0]), 16) + + # Check voltage and time v = self.trace.get_voltage() ts = self.trace.get_times() - all_traces = self.trace.get_all_traces(leakcorrect=True) - all_traces = self.trace.get_all_traces() - # TODO: Check the output, numerically, by comparing a few points - self.assertTrue(np.all(np.isfinite(v))) self.assertTrue(np.all(np.isfinite(ts))) + # Check traces + all_traces = self.trace.get_all_traces(leakcorrect=True) + all_traces = self.trace.get_all_traces() for well, trace in all_traces.items(): self.assertTrue(np.all(np.isfinite(trace))) + # TODO: Check the output, numerically, by comparing a few points # Test complex sweep selection a = self.trace.get_trace_sweeps([-1, -2])