Skip to content

Commit 865b10e

Browse files
committed
Analysis function dashboard: Fix the failure messages and make them more verbose
The analysis function dashboard displays the analysis function result for each stimulus set cycle ID (SCI). But we want to have the failure result of each single sweep. This was not implemented instead e.g. AD_GetBaselineFailMsg look at the whole SCI. And this triggered an assertion with Chat-IRES-Cre-neo;Ai14-582721.05.04.01.nwb as from three sweeps the middle one was failing but the last one passed. Investigating this assertion revealed that this approach is fundamentally broken as we need to query each sweep failure mode and then, depending on the analysis function, other things as well for the whole SCI. The new AD_GetPerSweepFailMessage does that.
1 parent e4f7e4b commit 865b10e

File tree

1 file changed

+166
-79
lines changed

1 file changed

+166
-79
lines changed

Packages/MIES/MIES_AnalysisFunctions_Dashboard.ipf

Lines changed: 166 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,6 @@ static Function/S AD_GetResultMessage(variable anaFuncType, variable passed, WAV
8484
return "Pass"
8585
endif
8686

87-
// PSQ_DA, PSQ_RB, PSQ_RA, PSQ_SP, PSQ_CR
88-
// PSQ_FMT_LBN_BL_QC_PASS
89-
9087
// MSQ_DA
9188
// - always passes
9289

@@ -101,16 +98,21 @@ static Function/S AD_GetResultMessage(variable anaFuncType, variable passed, WAV
10198
// - Not enough sweeps
10299

103100
// PSQ_CR
101+
// - baseline QC
104102
// - needs at least PSQ_CR_NUM_SWEEPS_PASS passing sweeps with the same to-full-pA rounded DAScale
103+
// - spike found while none expected (optional)
105104

106105
// PSQ_DA
106+
// - baseline QC
107107
// - needs at least $NUM_DA_SCALES passing sweeps
108108
// and for supra mode if the FinalSlopePercent parameter is present this has to be reached as well
109109

110110
// PSQ_RA
111+
// - baseline QC
111112
// - needs at least PSQ_RA_NUM_SWEEPS_PASS passing sweeps
112113

113114
// PSQ_RB
115+
// - baseline QC
114116
// - Difference to initial DAScale larger than 60pA?
115117
// - Not enough sweeps
116118

@@ -124,13 +126,13 @@ static Function/S AD_GetResultMessage(variable anaFuncType, variable passed, WAV
124126
case MSQ_FAST_RHEO_EST:
125127
return AD_GetFastRheoEstFailMsg(numericalValues, sweepNo, headstage)
126128
case PSQ_CHIRP:
127-
return AD_GetChirpFailMsg(numericalValues, sweepNo, headstage)
129+
return AD_GetChirpFailMsg(numericalValues, textualValues, sweepNo, headstage)
128130
case PSQ_DA_SCALE:
129131
return AD_GetDaScaleFailMsg(numericalValues, textualValues, sweepNo, headstage)
130132
case PSQ_RAMP:
131-
return AD_GetRampFailMsg(numericalValues, sweepNo, headstage)
133+
return AD_GetRampFailMsg(numericalValues, textualValues, sweepNo, headstage)
132134
case PSQ_RHEOBASE:
133-
return AD_GetRheobaseFailMsg(numericalValues, sweepNo, headstage)
135+
return AD_GetRheobaseFailMsg(numericalValues, textualValues, sweepNo, headstage)
134136
case PSQ_SQUARE_PULSE:
135137
return AD_GetSquarePulseFailMsg(numericalValues, sweepNo, headstage)
136138
case SC_SPIKE_CONTROL:
@@ -390,8 +392,8 @@ static Function/S AD_GetDAScaleFailMsg(numericalValues, textualValues, sweepNo,
390392
ASSERT(WaveExists(DASCales), "analysis function parameters don't have a DAScales entry")
391393
numRequiredPasses = DimSize(DAScales, ROWS)
392394

393-
if(numPasses < numRequiredPasses)
394-
sprintf msg, "Failure as we ran out of sweeps (%d passed but we needed %d)", numPasses, numRequiredPasses
395+
msg = AD_GetPerSweepFailMessage(PSQ_DA_SCALE, numericalValues, textualValues, sweepNo, headstage, numRequiredPasses = numRequiredPasses)
396+
if(!IsEmpty(msg))
395397
return msg
396398
endif
397399

@@ -417,70 +419,28 @@ End
417419
/// @brief Return an appropriate error message for why #PSQ_RAMP failed
418420
///
419421
/// @param numericalValues Numerical labnotebook
422+
/// @param textualValues Textual labnotebook
420423
/// @param sweepNo Sweep number
421424
/// @param headstage Headstage
422-
static Function/S AD_GetRampFailMsg(numericalValues, sweepNo, headstage)
423-
variable sweepNo
424-
WAVE numericalValues
425-
variable headstage
426-
427-
string msg
428-
variable numPasses
429-
430-
msg = AD_GetBaselineFailMsg(PSQ_RAMP, numericalValues, sweepNo, headstage)
431-
432-
if(!IsEmpty(msg))
433-
return msg
434-
endif
435-
436-
numPasses = PSQ_NumPassesInSet(numericalValues, PSQ_RAMP, sweepNo, headstage)
437-
if(numPasses < PSQ_RA_NUM_SWEEPS_PASS)
438-
sprintf msg, "Failure as we ran out of sweeps (%d passed but we needed %d)", numPasses, PSQ_RA_NUM_SWEEPS_PASS
439-
return msg
440-
endif
441-
442-
BUG("Unknown reason for failure")
443-
return "Failure"
425+
static Function/S AD_GetRampFailMsg(WAVE numericalValues, WAVE/T textualValues, variable sweepNo, variable headstage)
426+
return AD_GetPerSweepFailMessage(PSQ_RAMP, numericalValues, textualValues, sweepNo, headstage, numRequiredPasses = PSQ_RA_NUM_SWEEPS_PASS)
444427
End
445428

446429
/// @brief Return an appropriate error message for why #PSQ_RHEOBASE failed
447430
///
448431
/// @param numericalValues Numerical labnotebook
432+
/// @param textualValues Textual labnotebook
449433
/// @param sweepNo Sweep number
450434
/// @param headstage Headstage
451-
static Function/S AD_GetRheobaseFailMsg(numericalValues, sweepNo, headstage)
452-
variable sweepNo
453-
WAVE numericalValues
454-
variable headstage
455-
456-
string key, msg
457-
458-
msg = AD_GetBaselineFailMsg(PSQ_RHEOBASE, numericalValues, sweepNo, headstage)
459-
460-
if(!IsEmpty(msg))
461-
return msg
462-
endif
435+
static Function/S AD_GetRheobaseFailMsg(WAVE numericalValues, WAVE/T textualValues, variable sweepNo, variable headstage)
436+
string key, prefix, msg
463437

464-
key = CreateAnaFuncLBNKey(PSQ_RHEOBASE, PSQ_FMT_LBN_RB_DASCALE_EXC, query = 1)
465-
WAVE/Z daScaleExc = GetLastSettingEachSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE)
466-
ASSERT(WaveExists(daScaleExc), "Missing DAScale exceeded LBN entry")
467-
468-
if(AD_LabnotebookEntryExistsAndIsTrue(daScaleExc))
469-
return "Max DA scale exceeded failure"
470-
endif
471-
472-
key = CreateAnaFuncLBNKey(PSQ_RHEOBASE, PSQ_FMT_LBN_RB_LIMITED_RES, query = 1)
473-
WAVE/Z limitedResolution = GetLastSettingEachSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE)
474-
ASSERT(WaveExists(limitedResolution), "Missing limited resolution labnotebook entry")
475-
476-
if(AD_LabnotebookEntryExistsAndIsTrue(limitedResolution))
477-
return "Failure due to limited resolution"
478-
endif
438+
prefix = AD_GetPerSweepFailMessage(PSQ_RHEOBASE, numericalValues, textualValues, sweepNo, headstage)
479439

480440
key = CreateAnaFuncLBNKey(PSQ_RHEOBASE, PSQ_FMT_LBN_SPIKE_DETECT, query = 1)
481441
WAVE/Z spikeDetect = GetLastSettingEachSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE)
482442

483-
sprintf msg, "Failure as we were not able to find the correct on/off spike pattern (%s)", RemoveEnding(NumericWaveToList(spikeDetect, ", ", format="%g"), ", ")
443+
sprintf msg, "%s\rWe were not able to find the correct on/off spike pattern (%s)", prefix, RemoveEnding(NumericWaveToList(spikeDetect, ", ", format="%g"), ", ")
484444
return msg
485445
End
486446

@@ -515,42 +475,33 @@ End
515475
/// @brief Return an appropriate error message for why #PSQ_CHIRP failed
516476
///
517477
/// @param numericalValues Numerical labnotebook
478+
/// @param textualValues Textual labnotebook
518479
/// @param sweepNo Sweep number
519480
/// @param headstage Headstage
520-
static Function/S AD_GetChirpFailMsg(numericalValues, sweepNo, headstage)
521-
WAVE numericalValues
522-
variable sweepNo
523-
variable headstage
524-
481+
static Function/S AD_GetChirpFailMsg(WAVE numericalValues,WAVE/T textualValues, variable sweepNo, variable headstage)
525482
string key, msg, str
526483
string text = ""
527-
variable numPasses, i, numEntries, setPassed, maxOccurences
484+
variable i, numSweeps, setPassed, maxOccurences
528485

529-
msg = AD_GetBaselineFailMsg(PSQ_CHIRP, numericalValues, sweepNo, headstage)
486+
msg = AD_GetPerSweepFailMessage(PSQ_CHIRP, numericalValues, textualValues, sweepNo, headstage, numRequiredPasses = PSQ_CR_NUM_SWEEPS_PASS)
530487

531488
if(!IsEmpty(msg))
532489
return msg
533490
endif
534491

535-
numPasses = PSQ_NumPassesInSet(numericalValues, PSQ_CHIRP, sweepNo, headstage)
536-
if(numPasses < PSQ_CR_NUM_SWEEPS_PASS)
537-
sprintf msg, "Failure as we ran out of sweeps (%d passed but we needed %d)", numPasses, PSQ_CR_NUM_SWEEPS_PASS
538-
return msg
539-
endif
540-
492+
// all sweeps passed, but the set did not pass
541493
[setPassed, maxOccurences] = PSQ_CR_SetHasPassed(numericalValues, sweepNo, headstage)
542494

543495
if(!setPassed)
544-
545496
key = CreateAnaFuncLBNKey(PSQ_CHIRP, PSQ_FMT_LBN_SWEEP_PASS, query = 1)
546497
WAVE sweepPass = GetLastSettingIndepEachSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE)
547498

548499
WAVE DAScales = GetLastSettingEachSCI(numericalValues, sweepNo, STIMSET_SCALE_FACTOR_KEY, headstage, DATA_ACQUISITION_MODE)
549500
ASSERT(DimSize(sweepPass, ROWS) == DimSize(DAScales, ROWS), "Unexpected sizes")
550501

551-
numEntries = DimSize(sweepPass, ROWS)
552-
for(i = 0; i < numEntries; i += 1)
553-
sprintf str, "%g:%d, ", DAScales[i], sweepPass[i]
502+
numSweeps = DimSize(sweepPass, ROWS)
503+
for(i = 0; i < numSweeps; i += 1)
504+
sprintf str, "%g:%s, ", DAScales[i], ToPassFail(sweepPass[i])
554505

555506
text += str
556507
endfor
@@ -565,7 +516,7 @@ static Function/S AD_GetChirpFailMsg(numericalValues, sweepNo, headstage)
565516
return "Failure"
566517
End
567518

568-
/// @brief Return an appropriate error message if the baseline QC failed, or an empty string otherwise
519+
/// @brief Return an appropriate error message if the baseline QC failed for the given sweep, or an empty string otherwise
569520
///
570521
/// @param anaFuncType One of @ref PatchSeqAnalysisFunctionTypes
571522
/// @param numericalValues Numerical labnotebook
@@ -585,7 +536,7 @@ static Function/S AD_GetBaselineFailMsg(anaFuncType, numericalValues, sweepNo, h
585536
case PSQ_RAMP:
586537
case PSQ_CHIRP:
587538
key = CreateAnaFuncLBNKey(anaFuncType, PSQ_FMT_LBN_BL_QC_PASS, query = 1)
588-
WAVE/Z baselineQC = GetLastSettingSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE)
539+
WAVE/Z baselineQC = GetLastSetting(numericalValues, sweepNo, key, UNKNOWN_MODE)
589540

590541
if(anaFuncType == PSQ_CHIRP && !WaveExists(baselineQC))
591542
// we did not evaluate the baseline completely but aborted earlier
@@ -597,15 +548,15 @@ static Function/S AD_GetBaselineFailMsg(anaFuncType, numericalValues, sweepNo, h
597548
if(!baselineQC[headstage])
598549
for(i = 0; ;i += 1)
599550
key = CreateAnaFuncLBNKey(anaFuncType, PSQ_FMT_LBN_CHUNK_PASS, query = 1, chunk = i)
600-
chunkQC = GetLastSettingIndepSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE)
551+
chunkQC = GetLastSettingIndep(numericalValues, sweepNo, key, UNKNOWN_MODE)
601552

602553
if(IsNaN(chunkQC))
603554
// no more chunks
604555
break
605556
endif
606557

607558
if(!chunkQC)
608-
sprintf msg, "Failed due to Baseline QC failure in chunk %d", i
559+
sprintf msg, "Baseline QC failure in chunk %d", i
609560
return msg
610561
endif
611562
endfor
@@ -618,6 +569,142 @@ static Function/S AD_GetBaselineFailMsg(anaFuncType, numericalValues, sweepNo, h
618569
return ""
619570
End
620571

572+
/// @brief Gather per sweep failure information for some analysis function types
573+
///
574+
/// @param anaFuncType analysis function type
575+
/// @param numericalValues numerical labnotebook
576+
/// @param textualValues textual labnotebook
577+
/// @param refSweepNo reference sweep number
578+
/// @param headstage headstage
579+
/// @param numRequiredPasses [optional, defaults to off] allows to determine the set failure state by not having reached enough passing sets
580+
///
581+
/// @sa AD_GetResultMessage()
582+
static Function/S AD_GetPerSweepFailMessage(variable anaFuncType, WAVE numericalValues, WAVE/T textualValues, variable refSweepNo, variable headstage, [variable numRequiredPasses])
583+
string key, msg, str
584+
string text = ""
585+
variable numPasses, i, numSweeps, sweepNo, boundsAction, spikeCheck
586+
string perSweepFailedMessage = ""
587+
588+
if(!ParamIsDefault(numRequiredPasses))
589+
numPasses = PSQ_NumPassesInSet(numericalValues, anaFuncType, refSweepNo, headstage)
590+
591+
if(numPasses >= numRequiredPasses)
592+
return ""
593+
endif
594+
endif
595+
596+
key = CreateAnaFuncLBNKey(anaFuncType, PSQ_FMT_LBN_SWEEP_PASS, query = 1)
597+
WAVE/Z sweepPass = GetLastSettingIndepEachSCI(numericalValues, refSweepNo, key, headstage, UNKNOWN_MODE)
598+
599+
WAVE sweeps = AFH_GetSweepsFromSameSCI(numericalValues, refSweepNo, headstage)
600+
numSweeps = DimSize(sweeps, ROWS)
601+
602+
for(i = 0; i < numSweeps; i += 1)
603+
sweepNo = sweeps[i]
604+
text = ""
605+
606+
if(WaveExists(sweepPass) && sweepPass[i])
607+
sprintf text, "Sweep %d passed", sweeps[i]
608+
perSweepFailedMessage += text + "\r"
609+
continue
610+
endif
611+
612+
switch(anaFuncType)
613+
case PSQ_CHIRP:
614+
msg = AD_GetBaselineFailMsg(PSQ_CHIRP, numericalValues, sweepNo, headstage)
615+
616+
if(!IsEmpty(msg))
617+
sprintf text, "Sweep %d failed: %s", sweepNo, msg
618+
break
619+
endif
620+
621+
key = CreateAnaFuncLBNKey(PSQ_CHIRP, PSQ_FMT_LBN_CR_BOUNDS_ACTION, query = 1)
622+
boundsAction = GetLastSettingIndep(numericalValues, sweepNo, key, UNKNOWN_MODE)
623+
624+
if(IsFinite(boundsAction) && boundsAction != PSQ_CR_PASS)
625+
sprintf text, "Sweep %d failed: bounds action %s", sweepNo, PSQ_CR_BoundsActionToString(boundsAction)
626+
break
627+
endif
628+
629+
key = CreateAnaFuncLBNKey(PSQ_CHIRP, PSQ_FMT_LBN_CR_SPIKE_CHECK, query = 1)
630+
spikeCheck = GetLastSettingIndepSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE)
631+
632+
if(spikeCheck)
633+
key = CreateAnaFuncLBNKey(PSQ_CHIRP, PSQ_FMT_LBN_CR_SPIKE_PASS, query = 1)
634+
WAVE/Z spikePass = GetLastSetting(numericalValues, sweepNo, key, UNKNOWN_MODE)
635+
ASSERT(WaveExists(spikePass), "Spike pass wave is missing")
636+
637+
if(!spikePass[headstage])
638+
sprintf text, "Sweep %d failed: found spikes", sweepNo
639+
break
640+
endif
641+
endif
642+
break
643+
case PSQ_DA_SCALE:
644+
msg = AD_GetBaselineFailMsg(anaFuncType, numericalValues, sweepNo, headstage)
645+
646+
if(!IsEmpty(msg))
647+
sprintf text, "Sweep %d failed: %s", sweepNo, msg
648+
break
649+
endif
650+
651+
key = CreateAnaFuncLBNKey(anaFuncType, PSQ_FMT_LBN_RB_DASCALE_EXC, query = 1)
652+
WAVE/Z daScaleExc = GetLastSetting(numericalValues, sweepNo, key, UNKNOWN_MODE)
653+
654+
if(WaveExists(daScaleExc) && daScaleExc[headstage])
655+
sprintf text, "Sweep %d failed: Max DA scale exceeded failure", sweepNo
656+
break
657+
endif
658+
659+
key = CreateAnaFuncLBNKey(anaFuncType, PSQ_FMT_LBN_RB_LIMITED_RES, query = 1)
660+
WAVE/Z limitedResolution = GetLastSetting(numericalValues, sweepNo, key, UNKNOWN_MODE)
661+
662+
if(WaveExists(limitedResolution) && limitedResolution[headstage])
663+
sprintf text, "Sweep %d failed: Limited resolution", sweepNo
664+
break
665+
endif
666+
break
667+
case PSQ_RAMP:
668+
msg = AD_GetBaselineFailMsg(anaFuncType, numericalValues, sweepNo, headstage)
669+
670+
if(!IsEmpty(msg))
671+
sprintf text, "Sweep %d failed: %s", sweepNo, msg
672+
break
673+
endif
674+
break
675+
case PSQ_RHEOBASE:
676+
msg = AD_GetBaselineFailMsg(anaFuncType, numericalValues, sweepNo, headstage)
677+
678+
if(!IsEmpty(msg))
679+
sprintf text, "Sweep %d failed: %s", sweepNo, msg
680+
break
681+
endif
682+
683+
// Speciality: Rheobase does not have a Sweep QC entry and only
684+
// baseline QC determines a passing sweep
685+
sprintf text, "Sweep %d passed", sweeps[i]
686+
break
687+
default:
688+
ASSERT(0, "Unsupported analysis function")
689+
endswitch
690+
691+
if(IsEmpty(text))
692+
BUG("Unknown reason for failure")
693+
sprintf text, "Sweep %d failed: Unknown reasons", sweepNo
694+
endif
695+
696+
perSweepFailedMessage += text + "\r"
697+
endfor
698+
699+
if(!ParamIsDefault(numRequiredPasses))
700+
sprintf msg, "Failure as we ran out of sweeps (%d passed but we needed %d).\r%s", numPasses, numRequiredPasses, perSweepFailedMessage
701+
else
702+
sprintf msg, "Failure as we ran out of sweeps.\r%s", perSweepFailedMessage
703+
endif
704+
705+
return RemoveEnding(msg, "\r")
706+
End
707+
621708
/// @brief Show the sweeps of the given `index` entry into the listbox
622709
static Function AD_SelectResult(win, [index])
623710
string win

0 commit comments

Comments
 (0)