1717 _spike_channel_dtype ,
1818 _event_channel_dtype ,
1919)
20+ from neo .core import NeoReadWriteError
2021
2122
2223class BiocamRawIO (BaseRawIO ):
@@ -122,15 +123,53 @@ def _get_analogsignal_chunk(self, block_index, seg_index, i_start, i_stop, strea
122123 i_start = 0
123124 if i_stop is None :
124125 i_stop = self ._num_frames
125- if channel_indexes is None :
126- channel_indexes = slice ( None )
126+
127+ # read functions are different based on the version of biocam
127128 data = self ._read_function (self ._filehandle , i_start , i_stop , self ._num_channels )
128- return data [:, channel_indexes ]
129129
130+ # older style data returns array of (n_samples, n_channels), should be a view
131+ # but if memory issues come up we should doublecheck out how the file is being stored
132+ if data .ndim > 1 :
133+ if channel_indexes is None :
134+ channel_indexes = slice (None )
135+ sig_chunk = data [:, channel_indexes ]
136+
137+ # newer style data returns an initial flat array (n_samples * n_channels)
138+ # we iterate through channels rather than slicing
139+ # Due to the fact that Neo and SpikeInterface tend to prefer slices we need to add
140+ # some careful checks around slicing of None in the case we need to iterate through
141+ # channels. First check if None. Then check if slice and only if slice check that it is slice(None)
142+ else :
143+ if channel_indexes is None :
144+ channel_indexes = [ch for ch in range (self ._num_channels )]
145+ elif isinstance (channel_indexes , slice ):
146+ start = channel_indexes .start or 0
147+ stop = channel_indexes .stop or self ._num_channels
148+ step = channel_indexes .step or 1
149+ channel_indexes = [ch for ch in range (start , stop , step )]
150+
151+ sig_chunk = np .zeros ((i_stop - i_start , len (channel_indexes )), dtype = data .dtype )
152+ # iterate through channels to prevent loading all channels into memory which can cause
153+ # memory exhaustion. See https://github.com/SpikeInterface/spikeinterface/issues/3303
154+ for index , channel_index in enumerate (channel_indexes ):
155+ sig_chunk [:, index ] = data [channel_index :: self ._num_channels ]
156+
157+ return sig_chunk
130158
131- def open_biocam_file_header (filename ):
159+
160+ def open_biocam_file_header (filename ) -> dict :
132161 """Open a Biocam hdf5 file, read and return the recording info, pick the correct method to access raw data,
133- and return this to the caller."""
162+ and return this to the caller
163+
164+ Parameters
165+ ----------
166+ filename: str
167+ The file to be parsed
168+
169+ Returns
170+ -------
171+ dict
172+ The information necessary to read a biocam file (gain, n_samples, n_channels, etc)."""
134173 import h5py
135174
136175 rf = h5py .File (filename , "r" )
@@ -154,9 +193,9 @@ def open_biocam_file_header(filename):
154193 elif file_format in (101 , 102 ) or file_format is None :
155194 num_channels = int (rf ["3BData/Raw" ].shape [0 ] / num_frames )
156195 else :
157- raise Exception ("Unknown data file format." )
196+ raise NeoReadWriteError ("Unknown data file format." )
158197
159- # # get channels
198+ # get channels
160199 channels = rf ["3BRecInfo/3BMeaStreams/Raw/Chs" ][:]
161200
162201 # determine correct function to read data
@@ -166,14 +205,14 @@ def open_biocam_file_header(filename):
166205 elif signal_inv == - 1 :
167206 read_function = readHDF5t_100_i
168207 else :
169- raise Exception ("Unknown signal inversion" )
208+ raise NeoReadWriteError ("Unknown signal inversion" )
170209 else :
171210 if signal_inv == 1 :
172211 read_function = readHDF5t_101
173212 elif signal_inv == - 1 :
174213 read_function = readHDF5t_101_i
175214 else :
176- raise Exception ("Unknown signal inversion" )
215+ raise NeoReadWriteError ("Unknown signal inversion" )
177216
178217 gain = (max_uv - min_uv ) / (2 ** bit_depth )
179218 offset = min_uv
@@ -200,19 +239,22 @@ def open_biocam_file_header(filename):
200239 scale_factor = experiment_settings ["ValueConverter" ]["ScaleFactor" ]
201240 sampling_rate = experiment_settings ["TimeConverter" ]["FrameRate" ]
202241
242+ num_channels = None
203243 for key in rf :
204244 if key [:5 ] == "Well_" :
205245 num_channels = len (rf [key ]["StoredChIdxs" ])
206246 if len (rf [key ]["Raw" ]) % num_channels :
207- raise RuntimeError (f"Length of raw data array is not multiple of channel number in { key } " )
247+ raise NeoReadWriteError (f"Length of raw data array is not multiple of channel number in { key } " )
208248 num_frames = len (rf [key ]["Raw" ]) // num_channels
209249 break
210- try :
250+
251+ if num_channels is not None :
211252 num_channels_x = num_channels_y = int (np .sqrt (num_channels ))
212- except NameError :
213- raise RuntimeError ("No Well found in the file" )
253+ else :
254+ raise NeoReadWriteError ("No Well found in the file" )
255+
214256 if num_channels_x * num_channels_y != num_channels :
215- raise RuntimeError (f"Cannot determine structure of the MEA plate with { num_channels } channels" )
257+ raise NeoReadWriteError (f"Cannot determine structure of the MEA plate with { num_channels } channels" )
216258 channels = 1 + np .concatenate (np .transpose (np .meshgrid (range (num_channels_x ), range (num_channels_y ))))
217259
218260 gain = scale_factor * (max_uv - min_uv ) / (max_digital - min_digital )
@@ -231,6 +273,11 @@ def open_biocam_file_header(filename):
231273 )
232274
233275
276+ ######################################################################
277+ # Helper functions to obtain the raw data split by Biocam version.
278+
279+
280+ # return the full array for the old datasets
234281def readHDF5t_100 (rf , t0 , t1 , nch ):
235282 return rf ["3BData/Raw" ][t0 :t1 ]
236283
@@ -239,15 +286,16 @@ def readHDF5t_100_i(rf, t0, t1, nch):
239286 return 4096 - rf ["3BData/Raw" ][t0 :t1 ]
240287
241288
289+ # return flat array that we will iterate through
242290def readHDF5t_101 (rf , t0 , t1 , nch ):
243- return rf ["3BData/Raw" ][nch * t0 : nch * t1 ]. reshape (( t1 - t0 , nch ), order = "C" )
291+ return rf ["3BData/Raw" ][nch * t0 : nch * t1 ]
244292
245293
246294def readHDF5t_101_i (rf , t0 , t1 , nch ):
247- return 4096 - rf ["3BData/Raw" ][nch * t0 : nch * t1 ]. reshape (( t1 - t0 , nch ), order = "C" )
295+ return 4096 - rf ["3BData/Raw" ][nch * t0 : nch * t1 ]
248296
249297
250298def readHDF5t_brw4 (rf , t0 , t1 , nch ):
251299 for key in rf :
252300 if key [:5 ] == "Well_" :
253- return rf [key ]["Raw" ][nch * t0 : nch * t1 ]. reshape (( t1 - t0 , nch ), order = "C" )
301+ return rf [key ]["Raw" ][nch * t0 : nch * t1 ]
0 commit comments