@@ -123,38 +123,57 @@ def run_qc(self, voltage_steps, times,
123
123
before = self .filter_capacitive_spikes (before , times , voltage_steps )
124
124
after = self .filter_capacitive_spikes (after , times , voltage_steps )
125
125
126
+ QC = {label : [(False , None )] for label in self .qc_labels }
127
+
126
128
if len (before ) == 0 or len (after ) == 0 :
127
- return False , [ False for lab in self . qc_labels ]
129
+ return QC
128
130
129
131
if (None in qc_vals_before ) or (None in qc_vals_after ):
130
- return False , False * self . no_QC
132
+ return QC
131
133
132
134
qc1_1 = self .qc1 (* qc_vals_before )
133
135
qc1_2 = self .qc1 (* qc_vals_after )
134
- qc1 = [i and j for i , j in zip (qc1_1 , qc1_2 )]
135
136
136
- qc2_1 = True
137
- qc2_2 = True
137
+ QC ['qc1.rseal' ] = [qc1_1 [0 ], qc1_2 [0 ]]
138
+ QC ['qc1.cm' ] = [qc1_1 [1 ], qc1_2 [1 ]]
139
+ QC ['qc1.rseries' ] = [qc1_1 [2 ], qc1_2 [2 ]]
140
+
141
+ QC ['qc2.raw' ] = []
142
+ QC ['qc2.subtracted' ] = []
138
143
for i in range (n_sweeps ):
139
- qc2_1 = qc2_1 and self .qc2 (before [i ])
140
- qc2_2 = qc2_2 and self .qc2 (before [i ] - after [i ])
144
+ qc2_1 = self .qc2 (before [i ])
145
+ qc2_2 = self .qc2 (before [i ] - after [i ])
146
+
147
+ QC ['qc2.raw' ].append (qc2_1 )
148
+ QC ['qc2.subtracted' ].append (qc2_2 )
141
149
142
150
qc3_1 = self .qc3 (before [0 , :], before [1 , :])
143
151
qc3_2 = self .qc3 (after [0 , :], after [1 , :])
144
152
qc3_3 = self .qc3 (before [0 , :] - after [0 , :],
145
153
before [1 , :] - after [1 , :])
146
154
155
+ QC ['qc3.raw' ] = [qc3_1 ]
156
+ QC ['qc3.E4031' ] = [qc3_2 ]
157
+ QC ['qc3.subtracted' ] = [qc3_3 ]
158
+
147
159
rseals = [qc_vals_before [0 ], qc_vals_after [0 ]]
148
160
cms = [qc_vals_before [1 ], qc_vals_after [1 ]]
149
161
rseriess = [qc_vals_before [2 ], qc_vals_after [2 ]]
150
162
qc4 = self .qc4 (rseals , cms , rseriess )
151
163
164
+ QC ['qc4.rseal' ] = [qc4 [0 ]]
165
+ QC ['qc4.cm' ] = [qc4 [1 ]]
166
+ QC ['qc4.rseries' ] = [qc4 [2 ]]
167
+
152
168
# indices where hERG peaks
153
169
qc5 = self .qc5 (before [0 , :], after [0 , :],
154
170
self .qc5_win )
155
171
156
172
qc5_1 = self .qc5_1 (before [0 , :], after [0 , :], label = '1' )
157
173
174
+ QC ['qc5.staircase' ] = [qc5 ]
175
+ QC ['qc5.1.staircase' ] = [qc5_1 ]
176
+
158
177
# Ensure thats the windows are correct by checking the voltage trace
159
178
assert np .all (
160
179
np .abs (self .voltage [self .qc6_win [0 ]: self .qc6_win [1 ]] - 40.0 ))\
@@ -166,14 +185,17 @@ def run_qc(self, voltage_steps, times,
166
185
np .abs (self .voltage [self .qc6_2_win [0 ]: self .qc6_2_win [1 ]] - 40.0 ))\
167
186
< 1e-8
168
187
169
- qc6 , qc6_1 , qc6_2 = True , True , True
188
+ QC ['qc6.subtracted' ] = []
189
+ QC ['qc6.1.subtracted' ] = []
190
+ QC ['qc6.2.subtracted' ] = []
170
191
for i in range (before .shape [0 ]):
171
- qc6 = qc6 and self .qc6 ((before [i , :] - after [i , :]),
172
- self .qc6_win , label = '0' )
173
- qc6_1 = qc6_1 and self .qc6 ((before [i , :] - after [i , :]),
174
- self .qc6_1_win , label = '1' )
175
- qc6_2 = qc6_2 and self .qc6 ((before [i , :] - after [i , :]),
176
- self .qc6_2_win , label = '2' )
192
+ qc6 = self .qc6 ((before [i , :] - after [i , :]), self .qc6_win , label = "0" )
193
+ qc6_1 = self .qc6 ((before [i , :] - after [i , :]), self .qc6_1_win , label = "1" )
194
+ qc6_2 = self .qc6 ((before [i , :] - after [i , :]), self .qc6_2_win , label = "2" )
195
+
196
+ QC ['qc6.subtracted' ].append (qc6 )
197
+ QC ['qc6.1.subtracted' ].append (qc6_1 )
198
+ QC ['qc6.2.subtracted' ].append (qc6_2 )
177
199
178
200
if self ._debug :
179
201
fig = plt .figure (figsize = (8 , 5 ))
@@ -199,37 +221,47 @@ def run_qc(self, voltage_steps, times,
199
221
fig .savefig (os .path .join (self .plot_dir , 'qc_debug.png' ))
200
222
plt .close (fig )
201
223
202
- # Make a flat list of all QC criteria (pass/fail bool)
203
- QC = np .hstack ([qc1 , [qc2_1 , qc2_2 , qc3_1 , qc3_2 , qc3_3 ],
204
- qc4 , [qc5 , qc5_1 , qc6 , qc6_1 , qc6_2 ]]).flatten ()
224
+ # Check if all QC criteria passed
225
+ passed = all ([x for qc in QC .values () for x , _ in qc ])
205
226
206
- passed = np .all (QC )
207
227
return passed , QC
208
228
209
229
def qc1 (self , rseal , cm , rseries ):
210
-
211
- if any ([x is None for x in (rseal , cm , rseries )]):
212
- return False , False , False
213
-
214
230
# Check R_seal, C_m, R_series within desired range
215
- if rseal < self .rsealc [0 ] or rseal > self .rsealc [1 ] \
216
- or not np .isfinite (rseal ):
231
+ if (
232
+ rseal is None
233
+ or rseal < self .rsealc [0 ]
234
+ or rseal > self .rsealc [1 ]
235
+ or not np .isfinite (rseal )
236
+ ):
217
237
self .logger .debug (f"rseal: { rseal } " )
218
238
qc11 = False
219
239
else :
220
240
qc11 = True
221
- if cm < self .cmc [0 ] or cm > self .cmc [1 ] or not np .isfinite (cm ):
241
+
242
+ if (
243
+ cm is None
244
+ or cm < self .cmc [0 ]
245
+ or cm > self .cmc [1 ]
246
+ or not np .isfinite (cm )
247
+ ):
222
248
self .logger .debug (f"cm: { cm } " )
223
249
qc12 = False
224
250
else :
225
251
qc12 = True
226
- if rseries < self .rseriesc [0 ] or rseries > self .rseriesc [1 ] \
227
- or not np .isfinite (rseries ):
252
+
253
+ if (
254
+ rseries is None
255
+ or rseries < self .rseriesc [0 ]
256
+ or rseries > self .rseriesc [1 ]
257
+ or not np .isfinite (rseries )
258
+ ):
228
259
self .logger .debug (f"rseries: { rseries } " )
229
260
qc13 = False
230
261
else :
231
262
qc13 = True
232
- return [qc11 , qc12 , qc13 ]
263
+
264
+ return [(qc11 , rseal ), (qc12 , cm ), (qc13 , rseries )]
233
265
234
266
def qc2 (self , recording , method = 3 ):
235
267
# Check SNR is good
@@ -245,9 +277,11 @@ def qc2(self, recording, method=3):
245
277
246
278
if snr < self .snrc or not np .isfinite (snr ):
247
279
self .logger .debug (f"snr: { snr } " )
248
- return False
280
+ result = False
281
+ else :
282
+ result = True
249
283
250
- return True
284
+ return ( result , snr )
251
285
252
286
def qc3 (self , recording1 , recording2 , method = 3 ):
253
287
# Check 2 sweeps similar
@@ -270,36 +304,51 @@ def qc3(self, recording1, recording2, method=3):
270
304
rmsd = np .sqrt (np .mean ((recording1 - recording2 ) ** 2 ))
271
305
if rmsd > rmsdc or not (np .isfinite (rmsd ) and np .isfinite (rmsdc )):
272
306
self .logger .debug (f"rmsd: { rmsd } , rmsdc: { rmsdc } " )
273
- return False
274
- return True
275
-
276
- def qc4 (self , rseals , cms , rseriess ):
307
+ result = False
308
+ else :
309
+ result = True
277
310
278
- if any ([x is None for x in list (rseals ) + list (cms ) + list (rseriess )]):
279
- return [False , False , False ]
311
+ return (result , rmsd )
280
312
313
+ def qc4 (self , rseals , cms , rseriess ):
281
314
# Check R_seal, C_m, R_series stability
282
315
# Require std/mean < x%
283
316
qc41 = True
284
317
qc42 = True
285
318
qc43 = True
286
- if np .std (rseals ) / np .mean (rseals ) > self .rsealsc or not (
287
- np .isfinite (np .mean (rseals )) and np .isfinite (np .std (rseals ))):
288
- self .logger .debug (f"d_rseal: { np .std (rseals ) / np .mean (rseals )} " )
319
+
320
+ if None in list (rseals ):
289
321
qc41 = False
322
+ d_rseal = None
323
+ else :
324
+ d_rseal = np .std (rseals ) / np .mean (rseals )
325
+ if d_rseal > self .rsealsc or not (
326
+ np .isfinite (np .mean (rseals )) and np .isfinite (np .std (rseals ))):
327
+ self .logger .debug (f"d_rseal: { d_rseal } " )
328
+ qc41 = False
290
329
291
- if np .std (cms ) / np .mean (cms ) > self .cmsc or not (
292
- np .isfinite (np .mean (cms )) and np .isfinite (np .std (cms ))):
293
- self .logger .debug (f"d_cm: { np .std (cms ) / np .mean (cms )} " )
330
+ if None in list (cms ):
294
331
qc42 = False
332
+ d_cm = None
333
+ else :
334
+ d_cm = np .std (cms ) / np .mean (cms )
335
+ if d_cm > self .cmsc or not (
336
+ np .isfinite (np .mean (cms )) and np .isfinite (np .std (cms ))):
337
+ self .logger .debug (f"d_cm: { d_cm } " )
338
+ qc42 = False
295
339
296
- if np .std (rseriess ) / np .mean (rseriess ) > self .rseriessc or not (
297
- np .isfinite (np .mean (rseriess ))
298
- and np .isfinite (np .std (rseriess ))):
299
- self .logger .debug (f"d_rseries: { np .std (rseriess ) / np .mean (rseriess )} " )
340
+ if None in list (rseriess ):
300
341
qc43 = False
342
+ d_rseries = None
343
+ else :
344
+ d_rseries = np .std (rseriess ) / np .mean (rseriess )
345
+ if d_rseries > self .rseriessc or not (
346
+ np .isfinite (np .mean (rseriess ))
347
+ and np .isfinite (np .std (rseriess ))):
348
+ self .logger .debug (f"d_rseries: { d_rseries } " )
349
+ qc43 = False
301
350
302
- return [qc41 , qc42 , qc43 ]
351
+ return [( qc41 , d_rseal ), ( qc42 , d_cm ), ( qc43 , d_rseries ) ]
303
352
304
353
def qc5 (self , recording1 , recording2 , win = None , label = '' ):
305
354
# Check pharma peak value drops after E-4031 application
@@ -325,8 +374,11 @@ def qc5(self, recording1, recording2, win=None, label=''):
325
374
if (max_diff < max_diffc ) or not (np .isfinite (max_diff )
326
375
and np .isfinite (max_diffc )):
327
376
self .logger .debug (f"max_diff: { max_diff } , max_diffc: { max_diffc } " )
328
- return False
329
- return True
377
+ result = False
378
+ else :
379
+ result = True
380
+
381
+ return (result , max_diff )
330
382
331
383
def qc5_1 (self , recording1 , recording2 , win = None , label = '' ):
332
384
# Check RMSD_0 drops after E-4031 application
@@ -355,8 +407,11 @@ def qc5_1(self, recording1, recording2, win=None, label=''):
355
407
if (rmsd0_diff < rmsd0_diffc ) or not (np .isfinite (rmsd0_diff )
356
408
and np .isfinite (rmsd0_diffc )):
357
409
self .logger .debug (f"rmsd0_diff: { rmsd0_diff } , rmsd0c: { rmsd0_diffc } " )
358
- return False
359
- return True
410
+ result = False
411
+ else :
412
+ result = True
413
+
414
+ return (result , rmsd0_diff )
360
415
361
416
def qc6 (self , recording1 , win = None , label = '' ):
362
417
# Check subtracted staircase +40mV step up is non negative
@@ -377,8 +432,11 @@ def qc6(self, recording1, win=None, label=''):
377
432
if (val < valc ) or not (np .isfinite (val )
378
433
and np .isfinite (valc )):
379
434
self .logger .debug (f"qc6_{ label } val: { val } , valc: { valc } " )
380
- return False
381
- return True
435
+ result = False
436
+ else :
437
+ result = True
438
+
439
+ return (result , val )
382
440
383
441
def filter_capacitive_spikes (self , current , times , voltage_step_times ):
384
442
"""
0 commit comments