Skip to content

Commit deba9a4

Browse files
committed
Refactor Neuropixels 2.0 probes in preparation for single-shank probes
- Add Neuropixels V2 probe info interfaces and implementations - Moved all probe-specific logic from the dialog to the info class in the Design library - Update all methods/classes to handle the abstract class, with easy scalability to add single-shank probes in the future - Add clone method for NeuropixelsV2eProbeGroup to ensure that dialogs can be exited without affecting settings - Update how the ChannelMap is accessed and utilized
1 parent 8e0f8cd commit deba9a4

20 files changed

+958
-962
lines changed

OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,21 @@ public partial class ChannelConfigurationDialog : Form
1919
internal event EventHandler OnResizeZedGraph;
2020
internal event EventHandler OnDrawProbeGroup;
2121

22-
internal ProbeGroup ProbeGroup;
22+
ProbeGroup probeGroup;
23+
24+
internal ProbeGroup ProbeGroup
25+
{
26+
get => probeGroup;
27+
set
28+
{
29+
probeGroup = value;
30+
SelectedContacts = new bool[probeGroup.NumberOfContacts];
31+
}
32+
}
2333

2434
internal readonly List<int> ReferenceContacts = new();
2535

26-
internal readonly bool[] SelectedContacts = null;
36+
internal bool[] SelectedContacts { get; private set; } = null;
2737

2838
[Obsolete("Designer only.", true)]
2939
ChannelConfigurationDialog()
@@ -49,8 +59,6 @@ public ChannelConfigurationDialog(ProbeGroup probeGroup)
4959
ProbeGroup = probeGroup;
5060
}
5161

52-
SelectedContacts = new bool[ProbeGroup.NumberOfContacts];
53-
5462
ReferenceContacts = new List<int>();
5563

5664
zedGraphChannels.MouseDownEvent += MouseDownEvent;
@@ -278,6 +286,17 @@ internal virtual bool OpenFile<T>() where T : ProbeGroup
278286
{
279287
var newConfiguration = OpenAndParseConfigurationFile<T>();
280288

289+
if (ValidateProbeGroup(newConfiguration))
290+
{
291+
ProbeGroup = newConfiguration;
292+
return true;
293+
}
294+
295+
return false;
296+
}
297+
298+
internal bool ValidateProbeGroup(ProbeGroup newConfiguration)
299+
{
281300
if (newConfiguration == null)
282301
{
283302
return false;
@@ -287,10 +306,6 @@ internal virtual bool OpenFile<T>() where T : ProbeGroup
287306
{
288307
newConfiguration.Validate();
289308

290-
ProbeGroup = newConfiguration;
291-
DrawProbeGroup();
292-
RefreshZedGraph();
293-
294309
return true;
295310
}
296311
else
@@ -1013,6 +1028,8 @@ private void MenuItemOpenFile(object sender, EventArgs e)
10131028
if (OpenFile<ProbeGroup>())
10141029
{
10151030
DrawProbeGroup();
1031+
ResetZoom();
1032+
UpdateFontSize();
10161033
RefreshZedGraph();
10171034
}
10181035
}
@@ -1021,6 +1038,7 @@ private void MenuItemLoadDefaultConfig(object sender, EventArgs e)
10211038
{
10221039
LoadDefaultChannelLayout();
10231040
DrawProbeGroup();
1041+
ResetZoom();
10241042
UpdateFontSize();
10251043
RefreshZedGraph();
10261044
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace OpenEphys.Onix1.Design
4+
{
5+
interface INeuropixelsV2ProbeInfo
6+
{
7+
Array GetReferenceEnumValues();
8+
9+
Array GetComboBoxChannelPresets();
10+
11+
Enum CheckForExistingChannelPreset(NeuropixelsV2Electrode[] channelMap);
12+
13+
NeuropixelsV2Electrode[] GetChannelPreset(Enum channelPreset);
14+
}
15+
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Linq;
5+
6+
namespace OpenEphys.Onix1.Design
7+
{
8+
internal class NeuropixelsV2QuadShankInfo : INeuropixelsV2ProbeInfo
9+
{
10+
const int BankDStartIndex = 896;
11+
12+
enum QuadShankChannelPreset
13+
{
14+
Shank0BankA,
15+
Shank0BankB,
16+
Shank0BankC,
17+
Shank0BankD,
18+
Shank1BankA,
19+
Shank1BankB,
20+
Shank1BankC,
21+
Shank1BankD,
22+
Shank2BankA,
23+
Shank2BankB,
24+
Shank2BankC,
25+
Shank2BankD,
26+
Shank3BankA,
27+
Shank3BankB,
28+
Shank3BankC,
29+
Shank3BankD,
30+
AllShanks0_95,
31+
AllShanks96_191,
32+
AllShanks192_287,
33+
AllShanks288_383,
34+
AllShanks384_479,
35+
AllShanks480_575,
36+
AllShanks576_671,
37+
AllShanks672_767,
38+
AllShanks768_863,
39+
AllShanks864_959,
40+
AllShanks960_1055,
41+
AllShanks1056_1151,
42+
AllShanks1152_1247,
43+
None
44+
}
45+
46+
IEnumerable<NeuropixelsV2Electrode> Electrodes { get; init; }
47+
48+
public NeuropixelsV2QuadShankInfo(NeuropixelsV2QuadShankProbeConfiguration probeConfiguration)
49+
{
50+
Electrodes = probeConfiguration.ProbeGroup.ToElectrodes();
51+
}
52+
53+
public Array GetReferenceEnumValues()
54+
{
55+
return Enum.GetValues(typeof(NeuropixelsV2QuadShankReference));
56+
}
57+
58+
public Array GetComboBoxChannelPresets()
59+
{
60+
return Enum.GetValues(typeof(QuadShankChannelPreset));
61+
}
62+
63+
public Enum CheckForExistingChannelPreset(NeuropixelsV2Electrode[] channelMap)
64+
{
65+
static bool CheckShankBank(NeuropixelsV2Electrode[] channelMap, int shank, NeuropixelsV2Bank bank, out QuadShankChannelPreset preset)
66+
{
67+
preset = (shank, bank) switch
68+
{
69+
(0, NeuropixelsV2Bank.A) => QuadShankChannelPreset.Shank0BankA,
70+
(0, NeuropixelsV2Bank.B) => QuadShankChannelPreset.Shank0BankB,
71+
(0, NeuropixelsV2Bank.C) => QuadShankChannelPreset.Shank0BankC,
72+
(1, NeuropixelsV2Bank.A) => QuadShankChannelPreset.Shank1BankA,
73+
(1, NeuropixelsV2Bank.B) => QuadShankChannelPreset.Shank1BankB,
74+
(1, NeuropixelsV2Bank.C) => QuadShankChannelPreset.Shank1BankC,
75+
(2, NeuropixelsV2Bank.A) => QuadShankChannelPreset.Shank2BankA,
76+
(2, NeuropixelsV2Bank.B) => QuadShankChannelPreset.Shank2BankB,
77+
(2, NeuropixelsV2Bank.C) => QuadShankChannelPreset.Shank2BankC,
78+
(3, NeuropixelsV2Bank.A) => QuadShankChannelPreset.Shank3BankA,
79+
(3, NeuropixelsV2Bank.B) => QuadShankChannelPreset.Shank3BankB,
80+
(3, NeuropixelsV2Bank.C) => QuadShankChannelPreset.Shank3BankC,
81+
_ => QuadShankChannelPreset.None
82+
};
83+
84+
return channelMap.All(e => e.Bank == bank && e.Shank == shank);
85+
}
86+
87+
static bool CheckShankBankD(NeuropixelsV2Electrode[] channelMap, int shank, out QuadShankChannelPreset preset)
88+
{
89+
preset = shank switch
90+
{
91+
0 => QuadShankChannelPreset.Shank0BankD,
92+
1 => QuadShankChannelPreset.Shank1BankD,
93+
2 => QuadShankChannelPreset.Shank2BankD,
94+
3 => QuadShankChannelPreset.Shank3BankD,
95+
_ => QuadShankChannelPreset.None
96+
};
97+
98+
return channelMap.All(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.IntraShankElectrodeIndex >= BankDStartIndex)) && e.Shank == shank);
99+
}
100+
101+
for (int shank = 0; shank <= 3; shank++)
102+
{
103+
if (CheckShankBank(channelMap, shank, NeuropixelsV2Bank.A, out var preset))
104+
return preset;
105+
106+
if (CheckShankBank(channelMap, shank, NeuropixelsV2Bank.B, out preset))
107+
return preset;
108+
109+
if (CheckShankBank(channelMap, shank, NeuropixelsV2Bank.C, out preset))
110+
return preset;
111+
112+
if (CheckShankBankD(channelMap, shank, out preset))
113+
return preset;
114+
}
115+
116+
var ranges = new[]
117+
{
118+
(0, 95, QuadShankChannelPreset.AllShanks0_95),
119+
(192, 287, QuadShankChannelPreset.AllShanks192_287),
120+
(288, 383, QuadShankChannelPreset.AllShanks288_383),
121+
(394, 479, QuadShankChannelPreset.AllShanks384_479),
122+
(480, 575, QuadShankChannelPreset.AllShanks480_575),
123+
(576, 671, QuadShankChannelPreset.AllShanks576_671),
124+
(672, 767, QuadShankChannelPreset.AllShanks672_767),
125+
(768, 863, QuadShankChannelPreset.AllShanks768_863),
126+
(864, 959, QuadShankChannelPreset.AllShanks864_959),
127+
(960, 1055, QuadShankChannelPreset.AllShanks960_1055),
128+
(1056, 1151, QuadShankChannelPreset.AllShanks1056_1151),
129+
(1152, 1247, QuadShankChannelPreset.AllShanks1152_1247)
130+
};
131+
132+
static bool CheckAllShanksRange(NeuropixelsV2Electrode[] channelMap, int start, int end)
133+
{
134+
return channelMap.All(e => e.Shank >= 0 && e.Shank <= 3 &&
135+
e.IntraShankElectrodeIndex >= start &&
136+
e.IntraShankElectrodeIndex <= end);
137+
}
138+
139+
foreach (var (start, end, presetValue) in ranges)
140+
{
141+
if (CheckAllShanksRange(channelMap, start, end))
142+
return presetValue;
143+
}
144+
145+
return QuadShankChannelPreset.None;
146+
}
147+
148+
public NeuropixelsV2Electrode[] GetChannelPreset(Enum channelPreset)
149+
{
150+
var preset = (QuadShankChannelPreset)channelPreset;
151+
152+
static NeuropixelsV2Electrode[] GetAllShanks(IEnumerable<NeuropixelsV2Electrode> electrodes, int startIndex, int endIndex)
153+
{
154+
return electrodes.Where(e => (e.Shank == 0 && e.IntraShankElectrodeIndex >= startIndex && e.IntraShankElectrodeIndex <= endIndex)
155+
|| (e.Shank == 1 && e.IntraShankElectrodeIndex >= startIndex && e.IntraShankElectrodeIndex <= endIndex)
156+
|| (e.Shank == 2 && e.IntraShankElectrodeIndex >= startIndex && e.IntraShankElectrodeIndex <= endIndex)
157+
|| (e.Shank == 3 && e.IntraShankElectrodeIndex >= startIndex && e.IntraShankElectrodeIndex <= endIndex)).ToArray();
158+
};
159+
160+
return preset switch
161+
{
162+
QuadShankChannelPreset.Shank0BankA => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 0).ToArray(),
163+
QuadShankChannelPreset.Shank0BankB => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 0).ToArray(),
164+
QuadShankChannelPreset.Shank0BankC => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 0).ToArray(),
165+
QuadShankChannelPreset.Shank0BankD => Electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 0).ToArray(),
166+
QuadShankChannelPreset.Shank1BankA => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 1).ToArray(),
167+
QuadShankChannelPreset.Shank1BankB => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 1).ToArray(),
168+
QuadShankChannelPreset.Shank1BankC => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 1).ToArray(),
169+
QuadShankChannelPreset.Shank1BankD => Electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 1).ToArray(),
170+
QuadShankChannelPreset.Shank2BankA => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 2).ToArray(),
171+
QuadShankChannelPreset.Shank2BankB => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 2).ToArray(),
172+
QuadShankChannelPreset.Shank2BankC => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 2).ToArray(),
173+
QuadShankChannelPreset.Shank2BankD => Electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 2).ToArray(),
174+
QuadShankChannelPreset.Shank3BankA => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.A && e.Shank == 3).ToArray(),
175+
QuadShankChannelPreset.Shank3BankB => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.B && e.Shank == 3).ToArray(),
176+
QuadShankChannelPreset.Shank3BankC => Electrodes.Where(e => e.Bank == NeuropixelsV2Bank.C && e.Shank == 3).ToArray(),
177+
QuadShankChannelPreset.Shank3BankD => Electrodes.Where(e => (e.Bank == NeuropixelsV2Bank.D || (e.Bank == NeuropixelsV2Bank.C && e.Index >= BankDStartIndex)) && e.Shank == 3).ToArray(),
178+
QuadShankChannelPreset.AllShanks0_95 => GetAllShanks(Electrodes, 0, 95),
179+
QuadShankChannelPreset.AllShanks96_191 => GetAllShanks(Electrodes, 96, 191),
180+
QuadShankChannelPreset.AllShanks192_287 => GetAllShanks(Electrodes, 192, 287),
181+
QuadShankChannelPreset.AllShanks288_383 => GetAllShanks(Electrodes, 288, 383),
182+
QuadShankChannelPreset.AllShanks384_479 => GetAllShanks(Electrodes, 384, 479),
183+
QuadShankChannelPreset.AllShanks480_575 => GetAllShanks(Electrodes, 480, 575),
184+
QuadShankChannelPreset.AllShanks576_671 => GetAllShanks(Electrodes, 576, 671),
185+
QuadShankChannelPreset.AllShanks672_767 => GetAllShanks(Electrodes, 672, 767),
186+
QuadShankChannelPreset.AllShanks768_863 => GetAllShanks(Electrodes, 768, 863),
187+
QuadShankChannelPreset.AllShanks864_959 => GetAllShanks(Electrodes, 864, 959),
188+
QuadShankChannelPreset.AllShanks960_1055 => GetAllShanks(Electrodes, 960, 1055),
189+
QuadShankChannelPreset.AllShanks1056_1151 => GetAllShanks(Electrodes, 1056, 1151),
190+
QuadShankChannelPreset.AllShanks1152_1247 => GetAllShanks(Electrodes, 1152, 1247),
191+
QuadShankChannelPreset.None => Array.Empty<NeuropixelsV2Electrode>(),
192+
_ => throw new InvalidEnumArgumentException($"Unknown value of {nameof(QuadShankChannelPreset)}: {channelPreset}")
193+
};
194+
}
195+
}
196+
}

0 commit comments

Comments
 (0)