diff --git a/Packages/MIES/MIES_AnalysisBrowser.ipf b/Packages/MIES/MIES_AnalysisBrowser.ipf index d2310ce1e6..38e861c603 100644 --- a/Packages/MIES/MIES_AnalysisBrowser.ipf +++ b/Packages/MIES/MIES_AnalysisBrowser.ipf @@ -3497,6 +3497,9 @@ End Function AB_WindowHook(STRUCT WMWinHookStruct &s) switch(s.eventCode) + case EVENT_WINDOW_HOOK_KILLVOTE: + AB_SaveSourceListInSettings() + break case EVENT_WINDOW_HOOK_KILL: AB_MemoryFreeMappedDF() diff --git a/Packages/MIES/MIES_BrowserSettingsPanel.ipf b/Packages/MIES/MIES_BrowserSettingsPanel.ipf index 96c0e5b641..b17d020ec3 100644 --- a/Packages/MIES/MIES_BrowserSettingsPanel.ipf +++ b/Packages/MIES/MIES_BrowserSettingsPanel.ipf @@ -1927,7 +1927,7 @@ static Function BSP_MemoryFreeMappedDF(string win) variable dim, index - DFREF sweepBrowserDFR = BSP_GetFolder(win, MIES_BSP_PANEL_FOLDER) + DFREF sweepBrowserDFR = BSP_GetFolder(win, MIES_BSP_PANEL_FOLDER, versionCheck = 0) WAVE/T map = GetSweepBrowserMap(sweepBrowserDFR) dim = FindDimLabel(map, COLS, "DataFolder") Duplicate/FREE/RMD=[][dim] map, dfList diff --git a/Packages/MIES/MIES_Cache.ipf b/Packages/MIES/MIES_Cache.ipf index 4e54e79c87..a8b72d5295 100644 --- a/Packages/MIES/MIES_Cache.ipf +++ b/Packages/MIES/MIES_Cache.ipf @@ -209,6 +209,13 @@ Function/S CA_AveragingWaveModKey(WAVE wv) return num2istr(CA_RecursiveWavemodCRC(wv)) + "Version 1" End +/// @brief Cache key generator for the tau range calculation +/// of psx events +Function/S CA_PSXEventGoodTauRange(WAVE wv) + + return num2istr(CA_RecursiveWavemodCRC(wv)) + "Version 1" +End + /// @brief Calculated a CRC from non wave reference waves using modification data, wave modification count and wave location. /// If the given wave is a wave reference wave, then the CRC is calculated recursively from /// all non wave reference waves and null wave references found. @@ -415,7 +422,7 @@ Function/S CA_PSXKernelOperationKey(variable riseTau, variable decayTau, variabl crc = StringCRC(crc, num2strHighPrec(dt, precision = MAX_DOUBLE_PRECISION)) crc = WaveCRC(crc, range) - return num2istr(crc) + "PSX Kernel Version 1" + return num2istr(crc) + "PSX Kernel Version 2" End static Function/S CA_PSXBaseKey(string comboKey, string psxParameters) @@ -433,22 +440,17 @@ End /// @param psxParameters JSON dump of the psx/psxKernel operation parameters Function/S CA_PSXEventsKey(string comboKey, string psxParameters) - return CA_PSXBaseKey(comboKey, psxParameters) + " Events " + ":Version 1" + return CA_PSXBaseKey(comboKey, psxParameters) + " Events " + ":Version 2" End Function/S CA_PSXOperationKey(string comboKey, string psxParameters) - return CA_PSXBaseKey(comboKey, psxParameters) + " Operation " + ":Version 1" -End - -Function/S CA_PSXRiseTimeKey(string comboKey, string psxParameters) - - return CA_PSXBaseKey(comboKey, psxParameters) + " PSX Rise time " + ":Version 1" + return CA_PSXBaseKey(comboKey, psxParameters) + " Operation " + ":Version 3" End Function/S CA_PSXAnalyzePeaks(string comboKey, string psxParameters) - return CA_PSXBaseKey(comboKey, psxParameters) + " Analyze Peaks " + ":Version 1" + return CA_PSXBaseKey(comboKey, psxParameters) + " Analyze Peaks " + ":Version 2" End /// @brief Return the key for the igor info entries diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index 74eb6a2f9a..63d9ab4e95 100644 --- a/Packages/MIES/MIES_Constants.ipf +++ b/Packages/MIES/MIES_Constants.ipf @@ -22,6 +22,7 @@ Constant DA_EPHYS_PANEL_VERSION = 64 Constant DATA_SWEEP_BROWSER_PANEL_VERSION = 51 Constant WAVEBUILDER_PANEL_VERSION = 14 Constant ANALYSISBROWSER_PANEL_VERSION = 5 +Constant PSX_PLOT_PANEL_VERSION = 1 /// Version of the stimset wave note Constant STIMSET_NOTE_VERSION = 11 @@ -2032,6 +2033,7 @@ StrConstant CO_EMPTY_DAC_LIST = "emptyDACList" StrConstant CO_SF_TOO_MANY_TRACES = "SF_tooManyTraces" StrConstant CO_PSX_CLIPPED_STATS = "psx_clippedStats" StrConstant CO_ARCHIVE_ONCE = "ArchiveLogs" +StrConstant CO_PSX_UPGRADE_EVENT = "psx_updateEvent" ///@} /// @name Constants for SweepFormula Meta data in JSON format @@ -2347,11 +2349,14 @@ StrConstant PSX_STATS_LABELS = "Average;Median;Average Deviation;Standard deviat ///@{ Constant PSX_HORIZ_OFFSET_ONSET = 0 Constant PSX_HORIZ_OFFSET_PEAK = 1 +Constant PSX_HORIZ_OFFSET_SLEW = 2 ///@} -Constant PSX_DECONV_FILTER_DEF_LOW = 0.002 -Constant PSX_DECONV_FILTER_DEF_HIGH = 0.004 -Constant PSX_DECONV_FILTER_DEF_ORDER = 101 +Constant PSX_DECONV_FILTER_DEF_LOW = 500 +Constant PSX_DECONV_FILTER_DEF_HIGH = 50 +Constant PSX_DECONV_FILTER_DEF_ORDER = 7 + +StrConstant PSX_JWN_COMBO_KEYS_NAME = "ComboKeys" StrConstant SF_OP_MERGE = "merge" StrConstant SF_OP_FIT = "fit" diff --git a/Packages/MIES/MIES_SweepFormula.ipf b/Packages/MIES/MIES_SweepFormula.ipf index d13da2d04e..bf9477d2de 100644 --- a/Packages/MIES/MIES_SweepFormula.ipf +++ b/Packages/MIES/MIES_SweepFormula.ipf @@ -1516,7 +1516,7 @@ Function [STRUCT RGBColor s] SF_GetTraceColor(string graph, string opStack, WAVE return [s] endif - WAVE numericalValues = SFH_GetLabNoteBookForSweep(graph, sweepNo, mapIndex, LBN_NUMERICAL_VALUES) + WAVE/Z numericalValues = SFH_GetLabNoteBookForSweep(graph, sweepNo, mapIndex, LBN_NUMERICAL_VALUES) if(!WaveExists(numericalValues)) return [s] endif @@ -1670,6 +1670,8 @@ static Function [WAVE/T plotGraphs, WAVE/WAVE infos] SF_PreparePlotter(string wi win = winNameTemplate if(WindowExists(win)) + TUD_Clear(win, recursive = 1) + WAVE/T allWindows = ListToTextWave(GetAllWindows(win), ";") for(subWindow : allWindows) @@ -1679,6 +1681,9 @@ static Function [WAVE/T plotGraphs, WAVE/WAVE infos] SF_PreparePlotter(string wi KillWindow/Z $subWindow endif endfor + + RemoveAllControls(win) + RemoveAllDrawLayers(win) else NewPanel/N=$win/K=1/W=(150, 400, 1000, 700) win = S_name @@ -3678,7 +3683,7 @@ static Function/WAVE SF_OperationEpochsImpl(string graph, WAVE/T epochPatterns, WAVE/T epNames = SFH_GetEpochNamesFromInfo(epochInfo) WAVE/Z epIndices = SFH_GetEpochIndicesByWildcardPatterns(epNames, epochPatterns) if(!WaveExists(epIndices)) - break + continue endif numEntries = DimSize(epIndices, ROWS) diff --git a/Packages/MIES/MIES_SweepFormula_Helpers.ipf b/Packages/MIES/MIES_SweepFormula_Helpers.ipf index d2c4a9b636..4baa56d9d7 100644 --- a/Packages/MIES/MIES_SweepFormula_Helpers.ipf +++ b/Packages/MIES/MIES_SweepFormula_Helpers.ipf @@ -128,7 +128,7 @@ End Function/S SFH_GetArgumentAsText(variable jsonId, string jsonPath, string graph, string opShort, variable argNum, [string defValue, WAVE/Z/T allowedValues, FUNCREF SFH_StringChecker_Prototype checkFunc, variable checkDefault]) string msg, result, sep, allowedValuesAsStr - variable checkExist, numArgs, idx, ret + variable checkExist, numArgs, idx, ret, matchIndex if(ParamIsDefault(checkDefault)) checkDefault = 1 @@ -178,22 +178,30 @@ Function/S SFH_GetArgumentAsText(variable jsonId, string jsonPath, string graph, if(!ParamIsDefault(allowedValues)) ASSERT(WaveExists(allowedValues) && IsTextWave(allowedValues), "allowedValues must be a text wave") - // search are allowed entries and try to match a unique abbreviation - WAVE/Z/T matches = GrepTextWave(allowedValues, "(?i)^\\Q" + result + "\\E.*$") - if(!WaveExists(matches)) - sep = ", " - allowedValuesAsStr = TextWaveToList(allowedValues, sep, trailSep = 0) - sprintf msg, "Argument #%d of operation %s: The text argument \"%s\" is not one of the allowed values (%s)", argNum, opShort, result, allowedValuesAsStr - SFH_ASSERT(0, msg) - elseif(DimSize(matches, ROWS) > 1) - sep = ", " - allowedValuesAsStr = TextWaveToList(matches, sep, trailSep = 0) - sprintf msg, "Argument #%d of operation %s: The abbreviated text argument \"%s\" is not unique and could be (%s)", argNum, opShort, result, allowedValuesAsStr - SFH_ASSERT(0, msg) - else - ASSERT(DimSize(matches, ROWS) == 1, "Unexpected match") - // replace possibly abbreviated argument with its full name - result = matches[0] + // result can be either an exact match or a unique abbreviation + // need to check the exact match first as otherwise we find two + // abbreviations when given `a` with allowedValues `a`, `aXXX` + + matchIndex = GetRowIndex(allowedValues, str = result) + + if(IsNaN(matchIndex)) + // no exact match, search allowed entries and try to match a unique abbreviation + WAVE/Z/T matches = GrepTextWave(allowedValues, "(?i)^\\Q" + result + "\\E.*$") + if(!WaveExists(matches)) + sep = ", " + allowedValuesAsStr = TextWaveToList(allowedValues, sep, trailSep = 0) + sprintf msg, "Argument #%d of operation %s: The text argument \"%s\" is not one of the allowed values (%s)", argNum, opShort, result, allowedValuesAsStr + SFH_ASSERT(0, msg) + elseif(DimSize(matches, ROWS) > 1) + sep = ", " + allowedValuesAsStr = TextWaveToList(matches, sep, trailSep = 0) + sprintf msg, "Argument #%d of operation %s: The abbreviated text argument \"%s\" is not unique and could be (%s)", argNum, opShort, result, allowedValuesAsStr + SFH_ASSERT(0, msg) + else + ASSERT(DimSize(matches, ROWS) == 1, "Unexpected match") + // replace possibly abbreviated argument with its full name + result = matches[0] + endif endif endif @@ -362,9 +370,13 @@ Function/WAVE SFH_AsDataSet(WAVE data) End /// @brief Formula "cursors(A,B)" can return NaNs if no cursor(s) are set. -static Function SFH_ExtendIncompleteRanges(WAVE ranges) +static Function SFH_ExtendIncompleteRanges(WAVE/WAVE ranges) + + for(WAVE/Z wv : ranges) + if(!WaveExists(wv)) + continue + endif - for(WAVE wv : ranges) if(IsNumericWave(wv)) SFH_ASSERT(DimSize(wv, ROWS) == 2, "Numerical range must have two rows in the form [start, end].") wv[0][] = IsNaN(wv[0][q]) ? -Inf : wv[0][q] diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index aa1e3ae9a4..061415e4c8 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -59,6 +59,15 @@ static Constant PSX_KEYBOARD_DIR_LR = 1 static Constant PSX_NUMBER_OF_SDS_DEFAULT = 2.5 +static Constant PSX_TAU_CALC_FACTOR = 2.5 +static Constant PSX_BASELINE_RANGE_FACTOR = 10 +static Constant PSX_FIT_RANGE_FACTOR = 10 +static Constant PSX_FIT_RANGE_PERC = 0.9 +static Constant PSX_BASELINE_NUM_POINTS_AVERAGE = 5 +static Constant PSX_PEAK_RANGE_FACTOR_LEFT = 5 +static Constant PSX_PEAK_RANGE_FACTOR_RIGHT = 0.33 +static Constant PSX_PEAK_NUM_HIST_BINS = 20 + static Constant PSX_NUM_PEAKS_MAX = 2000 static Constant PSX_PLOT_DEFAULT_X_RANGE = 200 @@ -72,7 +81,7 @@ static StrConstant PSX_USER_DATA_WORKING_FOLDER = "psxFolder" static StrConstant PSX_X_DATA_UNIT = "X_DATA_UNIT" static StrConstant PSX_Y_DATA_UNIT = "Y_DATA_UNIT" -static StrConstant PSX_EVENT_DIMENSION_LABELS = "sweepData;sweepDataFiltOff;sweepDataFiltOffDeconv;peakX;peakY;psxEvent;eventFit" +static StrConstant PSX_EVENT_DIMENSION_LABELS = "sweepData;sweepDataOffFilt;sweepDataOffFiltDeconv;peakX;peakY;psxEvent;eventFit" static Constant PSX_KERNEL_OUTPUTWAVES_PER_ENTRY = 3 static Constant PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY = 7 @@ -86,7 +95,6 @@ static StrConstant PSX_CURSOR_TRACE = "peakY" static StrConstant PSX_USER_DATA_TYPE = "type" static StrConstant PSX_USER_DATA_PSX = "PSX" -static StrConstant PSX_JWN_COMBO_KEYS_NAME = "ComboKeys" static StrConstant PSX_JWN_PARAMETERS = "Parameters" static StrConstant PSX_JWN_STATS_POST_PROC = "PostProcessing" @@ -127,8 +135,6 @@ static Constant PSX_TUD_AVERAGE_ALL_COMBO_INDEX = NaN static StrConstant PSX_AVERAGE_FIT_RESULT_DEFAULT_HELP = "No fit results available for average accept" -static Constant PSX_DEFAULT_PEAK_SEARCH_RANGE_MS = 5 - static Constant PSX_STATS_TAU_FACTOR = 10 static Constant PSX_STATS_AMP_FACTOR = 100 @@ -140,7 +146,6 @@ static StrConstant PSX_PANEL_MACRO = "PSXPanel" /// @anchor PSXCacheKeyType ///@{ static Constant PSX_CACHE_KEY_EVENTS = 0x1 -static Constant PSX_CACHE_KEY_RISETIME = 0x2 static Constant PSX_CACHE_KEY_ANALYZE_PEAKS = 0x3 ///@} @@ -239,20 +244,24 @@ End /// @brief Filter the sweep data /// -/// @param sweepData data from a single sweep and channel *without* inserted TP -/// @param high high cutoff [Hz] -/// @param low low cutoff [Hz] -static Function/WAVE PSX_FilterSweepData(WAVE sweepData, variable low, variable high) +/// @param sweepDataOff data from a single sweep and channel *without* inserted TP already offsetted +/// @param high high cutoff [Hz] +/// @param low low cutoff [Hz] +static Function/WAVE PSX_FilterSweepData(WAVE/Z sweepDataOff, variable low, variable high) variable samp, err - samp = 1 / (deltax(sweepData) * MILLI_TO_ONE) + if(!WaveExists(sweepDataOff)) + return $"" + endif + + samp = 1 / (deltax(sweepDataOff) * MILLI_TO_ONE) ASSERT(low > high, "Expected a band pass filter with low > high") - Duplicate/FREE sweepData, filtered + Duplicate/FREE sweepDataOff, filtered - FilterIIR/ENDV=(filtered[0])/LO=(low / samp)/HI=(high / samp)/DIM=(ROWS) filtered; err = GetRTError(1) + FilterIIR/LO=(low / samp)/HI=(high / samp)/DIM=(ROWS)/ORD=6 filtered; err = GetRTError(1) SFH_ASSERT(!err, "Error filtering the data, msg: " + GetErrMessage(err)) return filtered @@ -324,7 +333,7 @@ End /// @param deconvFilter deconvolution filter settings static Function/WAVE PSX_DeconvoluteSweepData(WAVE sweepData, WAVE/C psxKernelFFT, WAVE deconvFilter) - variable numPoints, fftSize, samp, low, high, order, lowFrac, highFrac + variable numPoints, fftSize, samp, low, high, order, lowFrac, highFrac, err samp = 1 / (deltax(sweepData) * MILLI_TO_ONE) low = deconvFilter[%$"Filter Low"] @@ -332,13 +341,13 @@ static Function/WAVE PSX_DeconvoluteSweepData(WAVE sweepData, WAVE/C psxKernelFF order = deconvFilter[%$"Filter Order"] if(IsNaN(low)) - lowFrac = PSX_DECONV_FILTER_DEF_LOW + lowFrac = PSX_DECONV_FILTER_DEF_LOW / samp else lowFrac = low / samp endif if(IsNaN(high)) - highFrac = PSX_DECONV_FILTER_DEF_HIGH + highFrac = PSX_DECONV_FILTER_DEF_HIGH / samp else highFrac = high / samp endif @@ -347,7 +356,7 @@ static Function/WAVE PSX_DeconvoluteSweepData(WAVE sweepData, WAVE/C psxKernelFF order = PSX_DECONV_FILTER_DEF_ORDER endif - ASSERT(lowFrac < highFrac, "Expected a low pass filter with lowFrac < highFrac") + ASSERT(lowFrac > highFrac, "Expected a band pass filter with low > high") numPoints = DimSize(sweepData, ROWS) fftSize = DimSize(psxKernelFFT, ROWS) @@ -363,8 +372,12 @@ static Function/WAVE PSX_DeconvoluteSweepData(WAVE sweepData, WAVE/C psxKernelFF ASSERT(V_Value == -1, "Can not handle NaN in the deconvoluted wave") CopyScales sweepData, Deconv + FilterIIR/LO=(lowFrac)/HI=(highFrac)/ORD=(order) Deconv; err = GetRTError(0) - FilterFIR/ENDV={3}/LO={lowFrac, highFrac, order} Deconv + if(err) + printf "Error applying deconvolution filter: %s\r", GetRTErrMessage() + ClearRTError() + endif return Deconv End @@ -376,12 +389,10 @@ static Function/WAVE PSX_CreateHistogramOfDeconvSweepData(WAVE deconvSweepData) // we take +/- 80% of the average deviation around the average value WaveStats/Q deconvSweepData - binWidth = 0.0001 - range = V_adev * 0.8 + range = V_adev * 2 start = V_avg - range - n_bins = 2 * range / binWidth - - SFH_ASSERT(n_bins > 10, "Histogram creation failed due to too few data points") + n_bins = PSX_PEAK_NUM_HIST_BINS + binWidth = 2 * range / n_bins Make/D/FREE/N=0 hist Histogram/B={start, binWidth, n_bins}/DEST=hist deconvSweepData @@ -416,26 +427,26 @@ End /// - deconvolution /// - histogram of deconvolution /// - gaussian fit of histogram -static Function [WAVE sweepDataFiltOff, WAVE sweepDataFiltOffDeconv] PSX_Analysis(WAVE sweepData, WAVE psxKernelFFT, variable sweepFilterLow, variable sweepFilterHigh, WAVE deconvFilter) +static Function [WAVE sweepDataOffFilt, WAVE sweepDataOffFiltDeconv] PSX_Analysis(WAVE sweepData, WAVE psxKernelFFT, variable sweepFilterLow, variable sweepFilterHigh, WAVE deconvFilter) variable offset - WAVE sweepDataFilt = PSX_FilterSweepData(sweepData, sweepFilterLow, sweepFilterHigh) + [WAVE sweepDataOff, offset] = PSX_OffsetSweepData(sweepData) - [WAVE sweepDataFiltOff, offset] = PSX_OffsetSweepData(sweepDataFilt) + WAVE sweepDataOffFilt = PSX_FilterSweepData(sweepDataOff, sweepFilterLow, sweepFilterHigh) - if(!WaveExists(sweepDataFiltOff)) + if(!WaveExists(sweepDataOffFilt)) return [$"", $""] endif - WAVE sweepDataFiltOffDeconv = PSX_DeconvoluteSweepData(sweepDataFiltOff, psxKernelFFT, deconvFilter) + WAVE sweepDataOffFiltDeconv = PSX_DeconvoluteSweepData(sweepDataOffFilt, psxKernelFFT, deconvFilter) - return [sweepDataFiltOff, sweepDataFiltOffDeconv] + return [sweepDataOffFilt, sweepDataOffFiltDeconv] End /// Searches for peaks in sweepData /// -/// @param sweepDataFiltOffDeconv 1D wave +/// @param sweepDataOffFiltDeconv 1D wave /// @param threshold FindPeak parameter /// @param numPeaksMax maximum number of peaks to search /// @param start [optional, defaults first point] start x value @@ -443,7 +454,7 @@ End /// /// @retval peakX x-coordinates of peaks /// @retval peakY y-coordinates of peaks -static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataFiltOffDeconv, variable threshold, [variable numPeaksMax, variable start, variable stop]) +static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataOffFiltDeconv, variable threshold, [variable numPeaksMax, variable start, variable stop]) variable i @@ -452,17 +463,17 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataFiltOff endif if(ParamIsDefault(start)) - start = leftx(sweepDataFiltOffDeconv) + start = leftx(sweepDataOffFiltDeconv) endif if(ParamIsDefault(stop)) - stop = rightx(sweepDataFiltOffDeconv) + stop = rightx(sweepDataOffFiltDeconv) endif Make/FREE/D/N=(numPeaksMax) peakX, peakY for(i = 0; i < numPeaksMax; i += 1) - FindPeak/B=10/M=(threshold)/Q/R=(start, stop) sweepDataFiltOffDeconv + FindPeak/B=10/M=(threshold)/Q/R=(start, stop) sweepDataOffFiltDeconv if(V_Flag != 0) break @@ -485,88 +496,259 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataFiltOff return [peakX, peakY] End -/// @brief Analyze the peaks -static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFiltOff, WAVE peakX, WAVE peakY, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) +static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, WAVE sweepDataOffFilt, variable kernelAmp, variable kernelRiseTau, variable kernelDecayTau, WAVE psxEvent) - variable i, i_time, rel_peak, peak, dc_peak_t, isi, post_min, post_min_t, pre_max, pre_max_t, numCrossings - variable peak_end_search + variable numCrossings, idx, i + variable peak, peak_t, baseline, baseline_t, amplitude + variable overrideSignQC = NaN + string comboKey + + if(!WaveExists(peakXUnfiltered) || !WaveExists(peakYUnfiltered)) + return [$"", $""] + endif + + numCrossings = DimSize(peakXUnfiltered, ROWS) + + Make/FREE/D/N=(numCrossings) peakX, peakY - numCrossings = DimSize(peakX, ROWS) for(i = 0; i < numCrossings; i += 1) - i_time = peakX[i] - peak = peakY[i] + [peak, peak_t, baseline, baseline_t, amplitude] = PSX_CalculateEventProperties(peakXUnfiltered, peakYUnfiltered, sweepDataOffFilt, kernelAmp, kernelRiseTau, kernelDecayTau, i) - if(i < numCrossings - 1) - peak_end_search = min(i_time + PSX_DEFAULT_PEAK_SEARCH_RANGE_MS, peakX[i + 1]) - else - peak_end_search = i_time + PSX_DEFAULT_PEAK_SEARCH_RANGE_MS - endif +#ifdef AUTOMATED_TESTING + WAVE/Z overrideResults = GetOverrideResults() - WaveStats/M=1/Q/R=(i_time, peak_end_search) sweepDataFiltOff + if(WaveExists(overrideResults)) + comboKey = JWN_GetStringFromWaveNote(psxEvent, PSX_EVENTS_COMBO_KEY_WAVE_NOTE) - if(kernelAmp > 0) - post_min = V_max - post_min_t = V_maxloc - elseif(kernelAmp < 0) - post_min = V_min - post_min_t = V_minloc - else - ASSERT(0, "Can't handle kernelAmp of zero") + overrideSignQC = overrideResults[i][%$comboKey][%KernelAmpSignQC] endif +#endif + + if(IsNaN(overrideSignQC)) + if(sign(amplitude) != sign(kernelAmp)) + continue + endif + elseif(overrideSignQC == 0) + continue + endif + + peakX[idx] = peakXUnfiltered[i] + peakY[idx] = peakYUnfiltered[i] + + idx += 1 + endfor + + if(idx == 0) + return [$"", $""] + endif + + Redimension/N=(idx) peakX, peakY + + return [peakX, peakY] +End + +static Function [variable peak_t, variable peak] PSX_CalculateEventPeak(WAVE peakX, WAVE peakY, WAVE sweepDataOffFilt, variable kernelAmp, variable kernelRiseTau, variable kernelDecayTau, variable index) + + variable numCrossings, deconvPeak_t, prevDeconvPeak_t, nextDeconvPeak_t + variable peak_start_search, peak_end_search + + numCrossings = DimSize(peakX, ROWS) + + deconvPeak_t = peakX[index] + + // lower bound + if(index > 0) + prevDeconvPeak_t = peakX[index - 1] + else + prevDeconvPeak_t = -Inf + endif + + peak_start_search = max(deconvPeak_t - PSX_PEAK_RANGE_FACTOR_LEFT * kernelRiseTau, prevDeconvPeak_t) - EnsureLargeEnoughWave(psxEvent, indexShouldExist = i) + // upper bound + if(index < numCrossings - 1) + nextDeconvPeak_t = peakX[index + 1] + else + nextDeconvPeak_t = Inf + endif + + peak_end_search = min(deconvPeak_t + PSX_PEAK_RANGE_FACTOR_RIGHT * kernelDecayTau, nextDeconvPeak_t) + + WaveStats/M=1/Q/R=(peak_start_search, peak_end_search) sweepDataOffFilt + + if(kernelAmp > 0) + peak = V_max + peak_t = V_maxloc + elseif(kernelAmp < 0) + peak = V_min + peak_t = V_minloc + else + ASSERT(0, "Can't handle kernelAmp of zero") + endif + + return [peak_t, peak] +End + +static Function [variable baseline_t, variable baseline] PSX_CalculateEventBaseline(WAVE sweepDataOffFilt, variable peak_t, variable kernelAmp, variable kernelRiseTau) + + variable range + + WaveStats/M=1/Q/R=(peak_t - PSX_BASELINE_RANGE_FACTOR * kernelRiseTau, peak_t) sweepDataOffFilt - psxEvent[i][%post_min] = post_min - psxEvent[i][%post_min_t] = post_min_t + if(kernelAmp > 0) + baseline_t = V_minloc + elseif(kernelAmp < 0) + baseline_t = V_maxloc + else + ASSERT(0, "Can't handle kernelAmp of zero") + endif + + range = PSX_BASELINE_NUM_POINTS_AVERAGE * DimDelta(sweepDataOffFilt, ROWS) + WaveStats/M=1/Q/R=(baseline_t - range, baseline_t + range) sweepDataOffFilt + baseline = V_avg + + return [baseline_t, baseline] +End + +static Function [variable peak, variable peak_t, variable baseline, variable baseline_t, variable amplitude] PSX_CalculateEventProperties(WAVE peakX, WAVE peakY, WAVE sweepDataOffFilt, variable kernelAmp, variable kernelRiseTau, variable kernelDecayTau, variable index) + + [peak_t, peak] = PSX_CalculateEventPeak(peakX, peakY, sweepDataOffFilt, kernelAmp, kernelRiseTau, kernelDecayTau, index) + [baseline_t, baseline] = PSX_CalculateEventBaseline(sweepDataOffFilt, peak_t, kernelAmp, kernelRiseTau) + + amplitude = peak - baseline + + return [peak, peak_t, baseline, baseline_t, amplitude] +End + +/// @brief Analyze the peaks +static Function [WAVE/D peakX, WAVE/D peakY] PSX_AnalyzePeaks(WAVE sweepDataOffFiltDeconv, WAVE sweepDataOffFilt, WAVE sweepData, WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, variable maxTauFactor, variable kernelAmp, variable kernelRiseTau, variable kernelDecayTau, WAVE riseTimeParams, WAVE psxEvent, WAVE eventFit) + + variable i, numCrossings, deconvPeak, deconvPeak_t, peak, peak_t, baseline, baseline_t, amplitude, iei + + // we need to first throw away events with invalid amplitude so that + // we can then calculate the distance to the neighbour in peakX[i + 1] below + + [WAVE peakX, WAVE peakY] = PSX_FilterEventsKernelAmpSign(peakXUnfiltered, peakYUnfiltered, sweepDataOffFilt, kernelAmp, kernelRiseTau, kernelDecayTau, psxEvent) + WaveClear peakXUnfiltered, peakYUnfiltered + + if(!WaveExists(peakX) || !WaveExists(peakY)) + Redimension/N=(0, -1) psxEvent, eventFit + + return [$"", $""] + endif + + numCrossings = DimSize(peakX, ROWS) + Redimension/N=(numCrossings, -1) psxEvent, eventFit + + for(i = 0; i < numCrossings; i += 1) + + deconvPeak_t = peakX[i] + deconvPeak = peakY[i] + + [peak, peak_t, baseline, baseline_t, amplitude] = PSX_CalculateEventProperties(peakX, peakY, sweepDataOffFilt, \ + kernelAmp, kernelRiseTau, kernelDecayTau, i) if(i == 0) - isi = NaN + iei = NaN else - isi = i_time - psxEvent[i - 1][%peak_t] + iei = peak_t - psxEvent[i - 1][%peak_t] endif - WaveStats/Q/R=(i_time - 2, i_time) sweepDataFiltOff - pre_max = V_max - pre_max_t = V_maxloc - WaveStats/Q/R=(pre_max_t - 0.1, pre_max_t + 0.1) sweepDataFiltOff - pre_max = V_avg - - psxEvent[i][%index] = i - psxEvent[i][%peak_t] = i_time - psxEvent[i][%peak] = peak - - psxEvent[i][%pre_max] = pre_max - psxEvent[i][%pre_max_t] = pre_max_t - psxEvent[i][%rel_peak] = post_min - pre_max - psxEvent[i][%isi] = isi + psxEvent[i][%index] = i + psxEvent[i][%deconvPeak] = deconvPeak + psxEvent[i][%deconvPeak_t] = deconvPeak_t + psxEvent[i][%peak] = peak + psxEvent[i][%peak_t] = peak_t + psxEvent[i][%baseline] = baseline + psxEvent[i][%baseline_t] = baseline_t + psxEvent[i][%amplitude] = amplitude + psxEvent[i][%iei] = iei endfor - Redimension/N=(i, -1) eventFit, psxEvent - // safe defaults psxEvent[][%$"Event manual QC call"] = PSX_UNDET psxEvent[][%$"Fit manual QC call"] = PSX_UNDET psxEvent[][%$"Fit result"] = 0 - psxEvent[][%tau] = PSX_FitEventDecay(sweepDataFiltOff, psxEvent, maxTauFactor, eventFit, p) + Make/FREE/D/N=0 sweepDataDiff + Differentiate/EP=1 sweepDataOffFilt/D=sweepDataDiff + + // Also adds "Slew Rate" and "Slew Rate Time" + Multithread psxEvent[][%$"Onset Time"] = PSX_CalculateOnsetTime(sweepDataDiff, psxEvent, kernelAmp, \ + riseTimeParams[%$"Differentiate Threshold"], \ + p) + + Multithread psxEvent[][%$"Rise Time"] = PSX_CalculateRiseTime(sweepDataOffFilt, psxEvent, kernelAmp, \ + riseTimeParams[%$"Lower Threshold"], \ + riseTimeParams[%$"Upper Threshold"], \ + p) + + psxEvent[][%tau] = PSX_FitEventDecay(sweepDataOffFilt, psxEvent, maxTauFactor, eventFit, p) + + return [peakX, peakY] +End + +static Function PSX_GetGoodTau(WAVE psxEvent) + + string key + + key = CA_PSXEventGoodTauRange(psxEvent) + + WAVE/ZZ/D result = CA_TryFetchingEntryFromCache(key) + + if(!WaveExists(result)) + Make/FREE/D result = {PSX_GetGoodTauImpl(psxEvent)} + + CA_StoreEntryIntoCache(key, result, options = CA_OPTS_NO_DUPLICATE) + endif + + return result[0] +End + +// @brief Returns a good tau which does capture a lot of the tau events +static Function PSX_GetGoodTauImpl(WAVE psxEvent) + + variable numEvents, err, xVal, idx + + idx = FindDimLabel(psxEvent, COLS, "tau") + Duplicate/FREE/RMD=[][idx] psxEvent, tauWithNaN + + WAVE/Z tau = ZapNaNs(tauWithNaN) + + if(!WaveExists(tau)) + return PSX_DEFAULT_X_START_OFFSET + endif + + WaveStats/Q tau + + return V_avg + PSX_TAU_CALC_FACTOR * V_sdev End /// @brief Return the x-axis range useful for displaying and extracting a single event -static Function [variable first, variable last] PSX_GetSingleEventRange(WAVE psxEvent, variable index) +static Function [variable first, variable last] PSX_GetSingleEventRange(WAVE psxEvent, WAVE sweepDataOffFilt, variable index) - variable numEvents + variable numEvents, offset, onset, baseline numEvents = DimSize(psxEvent, ROWS) index = limit(index, 0, numEvents - 1) + offset = PSX_GetGoodTau(psxEvent) + + onset = psxEvent[index][%$"Onset Time"] + baseline = psxEvent[index][%baseline_t] + + if(!IsNaN(onset)) + first = min(onset, baseline) + else + first = baseline + endif + if(index == numEvents - 1) - first = psxEvent[index][%peak_t] - PSX_DEFAULT_X_START_OFFSET - last = psxEvent[index][%post_min_t] + PSX_DEFAULT_X_START_OFFSET + last = min(first + offset, IndexToScale(sweepDataOffFilt, DimSize(sweepDataOffFilt, ROWS) - 1, ROWS)) else - first = psxEvent[index][%peak_t] - PSX_DEFAULT_X_START_OFFSET - last = psxEvent[index + 1][%peak_t] - 0.5 + last = min(first + offset, psxEvent[index + 1][%baseline_t]) endif return [first, last] @@ -575,25 +757,25 @@ End /// @brief Return the x-axis range for single event fitting /// /// x-zero is taken from sweepData -static Function [variable start, variable stop] PSX_GetEventFitRange(WAVE sweepDataFiltOff, WAVE psxEvent, variable eventIndex) +static Function [variable start, variable stop] PSX_GetEventFitRange(WAVE sweepDataOffFilt, WAVE psxEvent, variable eventIndex) variable calcLength, maxLength - start = psxEvent[eventIndex][%post_min_t] + start = psxEvent[eventIndex][%deconvPeak_t] - maxLength = 10 * JWN_GetNumberFromWaveNote(psxEvent, SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/psxKernel/decayTau") + maxLength = PSX_FIT_RANGE_FACTOR * JWN_GetNumberFromWaveNote(psxEvent, SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/psxKernel/decayTau") if(eventIndex == (DimSize(psxEvent, ROWS) - 1)) calcLength = maxLength else - calcLength = min((psxEvent[eventIndex + 1][%post_min_t] - start) * 0.9, maxLength) + calcLength = min((psxEvent[eventIndex + 1][%deconvPeak_t] - start) * PSX_FIT_RANGE_PERC, maxLength) endif if(calcLength == 0) calcLength = maxLength endif - stop = min(start + calcLength, IndexToScale(sweepDataFiltOff, DimSize(sweepDataFiltOff, ROWS), ROWS)) + stop = min(start + calcLength, IndexToScale(sweepDataOffFilt, DimSize(sweepDataOffFilt, ROWS), ROWS)) ASSERT(start < stop, "Invalid fit range calculation") @@ -608,12 +790,12 @@ End /// exp_XOffset: :math:`y = K0 + K1 \cdot exp(-(x - x0)/K2)` /// /// \endrst -static Function PSX_FitEventDecay(WAVE sweepDataFiltOff, WAVE psxEvent, variable maxTauFactor, WAVE/WAVE eventFit, variable eventIndex) +static Function PSX_FitEventDecay(WAVE sweepDataOffFilt, WAVE psxEvent, variable maxTauFactor, WAVE/WAVE eventFit, variable eventIndex) - variable post_min_t, n_min_t, err, decayTau, fitRange, overrideTau + variable startTime, endTime, err, decayTau, fitRange, overrideTau string comboKey - [post_min_t, n_min_t] = PSX_GetEventFitRange(sweepDataFiltOff, psxEvent, eventIndex) + [startTime, endTime] = PSX_GetEventFitRange(sweepDataOffFilt, psxEvent, eventIndex) DFREF currDFR = GetDataFolderDFR() SetDataFolder NewFreeDataFolder() @@ -624,7 +806,7 @@ static Function PSX_FitEventDecay(WAVE sweepDataFiltOff, WAVE psxEvent, variable Make/FREE/D/N=3 coefWave AssertOnAndClearRTError() - CurveFit/Q/N=1/NTHR=1/M=0/W=2 exp_XOffset, kwCWave=coefWave, sweepDataFiltOff(post_min_t, n_min_t)/D/C=constraints; err = GetRTError(1) + CurveFit/Q/N=1/NTHR=1/M=0/W=2 exp_XOffset, kwCWave=coefWave, sweepDataOffFilt(startTime, endTime)/D/C=constraints; err = GetRTError(1) WAVE fit = MakeWaveFree($"fit__free_") @@ -655,7 +837,7 @@ static Function PSX_FitEventDecay(WAVE sweepDataFiltOff, WAVE psxEvent, variable return NaN endif - fitRange = n_min_t - post_min_t + fitRange = endTime - startTime if(IsFinite(decayTau) && decayTau > maxTauFactor * fitRange) psxEvent[eventIndex][%$"Fit manual QC call"] = PSX_REJECT @@ -683,7 +865,8 @@ End /// /// LAYERS: /// - 0: Fit result, see GetPSXEventWaveAsFree -/// - 1: Replacement tau, the default of NaN means don't use +/// - 1: Replacement tau, the default of NaN means don't override +/// - 2: Override sign check in PSX_AnalyzePeaks (0 failing, 1 passing), the default of NaN means don't override static Function/WAVE PSX_CreateOverrideResults(variable numEvents, WAVE/T combos) variable numCombos @@ -692,15 +875,16 @@ static Function/WAVE PSX_CreateOverrideResults(variable numEvents, WAVE/T combos numCombos = DimSize(combos, ROWS) - Make/D/N=(numEvents, numCombos, 2) root:overrideResults/WAVE=wv + Make/D/N=(numEvents, numCombos, 3) root:overrideResults/WAVE=wv SetDimensionLabels(wv, TextWaveToList(combos, ";"), COLS) - SetDimensionLabels(wv, "Fit Result;Tau", LAYERS) + SetDimensionLabels(wv, "Fit Result;Tau;KernelAmpSignQC", LAYERS) wv[] = NaN return wv End +/// @return 0 on success, 1 otherwise static Function PSX_OperationSweepGathering(string graph, WAVE/WAVE psxKernelDataset, variable parameterJsonID, variable sweepFilterLow, variable sweepFilterHigh, WAVE deconvFilter, variable index, WAVE/WAVE output) string key, comboKey, psxParametersAnalyzePeaks, cacheKey @@ -720,48 +904,57 @@ static Function PSX_OperationSweepGathering(string graph, WAVE/WAVE psxKernelDat WAVE/Z/WAVE psxAnalyzePeaksFromCache = CA_TryFetchingEntryFromCache(cacheKey) if(WaveExists(psxAnalyzePeaksFromCache)) - WAVE sweepDataFiltOff = psxAnalyzePeaksFromCache[%sweepDataFiltOff] - WAVE sweepDataFiltOffDeconv = psxAnalyzePeaksFromCache[%sweepDataFiltOffDeconv] + + if(DimSize(psxAnalyzePeaksFromCache, ROWS) == 0) + return 1 + endif + + WAVE sweepDataOffFilt = psxAnalyzePeaksFromCache[%sweepDataOffFilt] + WAVE sweepDataOffFiltDeconv = psxAnalyzePeaksFromCache[%sweepDataOffFiltDeconv] else - [WAVE sweepDataFiltOff, WAVE sweepDataFiltOffDeconv] = PSX_Analysis(sweepData, psxKernelFFT, sweepFilterLow, sweepFilterHigh, deconvFilter) + [WAVE sweepDataOffFilt, WAVE sweepDataOffFiltDeconv] = PSX_Analysis(sweepData, psxKernelFFT, sweepFilterLow, sweepFilterHigh, deconvFilter) - Make/FREE/WAVE/N=(2) psxAnalyzePeaks - SetDimensionLabels(psxAnalyzePeaks, "sweepDataFiltOff;sweepDataFiltOffDeconv", ROWS) - psxAnalyzePeaks[%sweepDataFiltOff] = sweepDataFiltOff - psxAnalyzePeaks[%sweepDataFiltOffDeconv] = sweepDataFiltOffDeconv + if(!WaveExists(sweepDataOffFilt) || !WaveExists(sweepDataOffFiltDeconv)) + Make/FREE/WAVE/N=(0) psxAnalyzePeaks + else + Make/FREE/WAVE/N=(2) psxAnalyzePeaks + SetDimensionLabels(psxAnalyzePeaks, "sweepDataOffFilt;sweepDataOffFiltDeconv", ROWS) + psxAnalyzePeaks[%sweepDataOffFilt] = sweepDataOffFilt + psxAnalyzePeaks[%sweepDataOffFiltDeconv] = sweepDataOffFiltDeconv + endif CA_StoreEntryIntoCache(cacheKey, psxAnalyzePeaks) + + if(DimSize(psxAnalyzePeaks, ROWS) == 0) + return 1 + endif endif key = PSX_GenerateKey("sweepData", index) output[%$key] = sweepData - key = PSX_GenerateKey("sweepDataFiltOff", index) - output[%$key] = sweepDataFiltOff + key = PSX_GenerateKey("sweepDataOffFilt", index) + output[%$key] = sweepDataOffFilt + + key = PSX_GenerateKey("sweepDataOffFiltDeconv", index) + output[%$key] = sweepDataOffFiltDeconv - key = PSX_GenerateKey("sweepDataFiltOffDeconv", index) - output[%$key] = sweepDataFiltOffDeconv + return 0 End /// @brief Implementation of psx operation -/// -/// @return 0 on success, 1 on failure -static Function PSX_OperationImpl(string graph, variable parameterJSONID, string id, variable peakThresh, variable maxTauFactor, WAVE riseTimeParams, variable kernelAmp, variable index, WAVE/WAVE output) +static Function PSX_OperationImpl(string graph, variable parameterJSONID, string id, variable peakThresh, variable maxTauFactor, WAVE riseTimeParams, variable kernelAmp, variable kernelRiseTau, variable kernelDecayTau, variable index, WAVE/WAVE output) string comboKey, key, psxOperationKey, psxParametersEvents key = PSX_GenerateKey("sweepData", index) WAVE sweepData = output[%$key] - key = PSX_GenerateKey("sweepDataFiltOff", index) - WAVE/Z sweepDataFiltOff = output[%$key] + key = PSX_GenerateKey("sweepDataOffFilt", index) + WAVE sweepDataOffFilt = output[%$key] - key = PSX_GenerateKey("sweepDataFiltOffDeconv", index) - WAVE/Z sweepDataFiltOffDeconv = output[%$key] - - if(!WaveExists(sweepDataFiltOff) || !WaveExists(sweepDataFiltOffDeconv)) - return NaN - endif + key = PSX_GenerateKey("sweepDataOffFiltDeconv", index) + WAVE sweepDataOffFiltDeconv = output[%$key] [WAVE selectData, WAVE range] = SFH_ParseToSelectDataWaveAndRange(sweepData) ASSERT(WaveExists(selectData) && WaveExists(range), "Could not recreate select/range wave") @@ -772,40 +965,28 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string WAVE/Z/WAVE psxOperationFromCache = CA_TryFetchingEntryFromCache(psxOperationKey) if(WaveExists(psxOperationFromCache)) - WAVE peakX = psxOperationFromCache[%peakX] - WAVE peakY = psxOperationFromCache[%peakY] - WAVE psxEvent = psxOperationFromCache[%psxEvent] - WAVE eventFit = psxOperationFromCache[%eventFit] + WAVE/Z/D peakX = psxOperationFromCache[%peakX] + WAVE/Z/D peakY = psxOperationFromCache[%peakY] + WAVE/Z psxEvent = psxOperationFromCache[%psxEvent] + WAVE/Z eventFit = psxOperationFromCache[%eventFit] else - [WAVE peakX, WAVE peakY] = PSX_FindPeaks(sweepDataFiltOffDeconv, peakThresh) - - if(!WaveExists(peakX) || !WaveExists(peakY)) - // clear entries from this combo - key = PSX_GenerateKey("sweepData", index) - output[%$key] = $"" - - key = PSX_GenerateKey("sweepDataFiltOff", index) - output[%$key] = $"" - - key = PSX_GenerateKey("sweepDataFiltOffDeconv", index) - output[%$key] = $"" - - printf "Could not find any events for combination: \"%s\"\r", comboKey - ControlWindowToFront() - - return 1 - endif + [WAVE peakXUnfiltered, WAVE peakYUnfiltered] = PSX_FindPeaks(sweepDataOffFiltDeconv, peakThresh) WAVE psxEvent = GetPSXEventWaveAsFree() - JWN_SetWaveNoteFromJSON(psxEvent, parameterJsonID, release = 0) - WAVE eventFit = GetPSXEventFitWaveAsFree() + JWN_SetWaveNoteFromJSON(psxEvent, parameterJsonID, release = 0) + JWN_SetStringInWaveNote(psxEvent, PSX_EVENTS_COMBO_KEY_WAVE_NOTE, comboKey) JWN_SetStringInWaveNote(psxEvent, PSX_X_DATA_UNIT, WaveUnits(sweepData, ROWS)) JWN_SetStringInWaveNote(psxEvent, PSX_Y_DATA_UNIT, WaveUnits(sweepData, -1)) - PSX_AnalyzePeaks(sweepDataFiltOffDeconv, sweepDataFiltOff, peakX, peakY, maxTauFactor, kernelAmp, psxEvent, eventFit) + [WAVE peakX, WAVE peakY] = PSX_AnalyzePeaks(sweepDataOffFiltDeconv, sweepDataOffFilt, \ + sweepData, \ + peakXUnfiltered, peakYUnfiltered, \ + maxTauFactor, kernelAmp, kernelRiseTau, \ + kernelDecayTau, riseTimeParams, \ + psxEvent, eventFit) Make/FREE/WAVE/N=(4) psxOperation SetDimensionLabels(psxOperation, "peakX;peakY;psxEvent;eventFit", ROWS) @@ -817,10 +998,17 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string CA_StoreEntryIntoCache(psxOperationKey, psxOperation) endif + if(!WaveExists(peakX) || !WaveExists(peakY)) + WaveClear psxEvent, eventFit + + printf "Could not find any events for combination: \"%s\"\r", comboKey + ControlWindowToFront() + endif + WAVE/Z psxEventFromCache = PSX_LoadEventsFromCache(comboKey, psxParametersEvents) if(WaveExists(psxEventFromCache)) - WAVE psxEvent = psxEventFromCache + WAVE/Z psxEventCandidate = UpgradePSXEventWave(psxEventFromCache) else // no cached psxEvent data exists // look into the results wave @@ -828,16 +1016,15 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string WAVE/Z psxEventFromResults = PSX_FilterEventContainer(psxEventContainer, comboKey) if(WaveExists(psxEventFromResults)) - WAVE psxEvent = psxEventFromResults + WAVE/Z psxEventCandidate = UpgradePSXEventWave(psxEventFromResults) endif endif - UpgradePSXEventWave(psxEvent) - - WAVE riseTime = PSX_CalculateRiseTime(psxEvent, sweepDataFiltOff, parameterJsonID, kernelAmp, riseTimeParams[%$"Lower Threshold"], riseTimeParams[%$"Upper Threshold"]) - ASSERT(DimSize(riseTime, ROWS) == DimSize(psxEvent, ROWS), "Unmatched number of rows for rise time") - psxEvent[][%$"Rise Time"] = riseTime[p] - WaveClear riseTime + if(WaveExists(psxEventCandidate) \ + && DimSize(peakX, ROWS) == DimSize(psxEventCandidate, ROWS) \ + && DimSize(peakY, ROWS) == DimSize(psxEventCandidate, ROWS)) + WAVE psxEvent = psxEventCandidate + endif key = PSX_GenerateKey("peakX", index) output[%$key] = peakX @@ -850,8 +1037,6 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string key = PSX_GenerateKey("eventFit", index) output[%$key] = eventFit - - return 0 End /// @brief Generate the dimension label for the output wave reference waves @@ -878,7 +1063,12 @@ static Function/WAVE PSX_GetPSXKernel(variable riseTau, variable decayTau, varia endif [WAVE psx_kernel, WAVE kernel_fft] = PSX_CreatePSXKernel(riseTau, decayTau, amp, numPoints, dt) - Make/FREE/WAVE result = {psx_kernel, kernel_fft} + + if(!WaveExists(psx_kernel) || !WaveExists(kernel_fft)) + Make/FREE/WAVE/N=0 result + else + Make/FREE/WAVE result = {psx_kernel, kernel_fft} + endif CA_StoreEntryIntoCache(key, result) @@ -905,6 +1095,10 @@ static Function [WAVE kernel, WAVE kernelFFT] PSX_CreatePSXKernel(variable riseT kernel_window = decayTau_p * 4 amp_prime = (decayTau_p / riseTau_p)^(riseTau_p / (riseTau_p - decayTau_p)) // normalization factor + if(kernel_window > numPoints) + return [$"", $""] + endif + Make/FREE/N=(kernel_window) timeIndex = p SetScale/P x, 0, dt, timeIndex @@ -925,13 +1119,28 @@ static Function [WAVE/D results, WAVE eventIndex, WAVE marker, WAVE/T comboKeys] strswitch(prop) case "amp": - propLabel = "rel_peak" + propLabel = "amplitude" break - case "xpos": + case "peak": + propLabel = "peak" + break + case "peaktime": propLabel = "peak_t" break + case "deconvpeak": + propLabel = "deconvpeak" + break + case "deconvpeaktime": + propLabel = "deconvpeak_t" + break + case "baseline": + propLabel = "baseline" + break + case "baselinetime": + propLabel = "baseline_t" + break case "xinterval": - propLabel = "isi" + propLabel = "iei" break case "tau": propLabel = "tau" @@ -945,20 +1154,37 @@ static Function [WAVE/D results, WAVE eventIndex, WAVE marker, WAVE/T comboKeys] case "fitresult": propLabel = "Fit result" break + case "slewrate": + propLabel = "Slew Rate" + break + case "slewratetime": + propLabel = "Slew Rate Time" + break case "risetime": propLabel = "Rise Time" break + case "onsettime": + propLabel = "Onset Time" + break default: - ASSERT(0, "Impossible prop") + ASSERT(0, "Impossible prop: " + prop) endswitch // use the correct event/fit state for the property strswitch(propLabel) - case "rel_peak": + case "amplitude": + case "peak": case "peak_t": - case "isi": + case "deconvPeak": + case "deconvPeak_t": + case "baseline": + case "baseline_t": + case "iei": case "Event manual QC call": + case "Slew Rate": + case "Slew Rate Time": case "Rise Time": + case "Onset Time": stateType = "Event manual QC call" break case "Fit result": @@ -967,7 +1193,7 @@ static Function [WAVE/D results, WAVE eventIndex, WAVE marker, WAVE/T comboKeys] stateType = "Fit manual QC call" break default: - ASSERT(0, "Unknown propLabel") + ASSERT(0, "Unknown propLabel: " + propLabel) endswitch Make/FREE/N=0 allEventIndex, allMarkers @@ -989,8 +1215,8 @@ static Function [WAVE/D results, WAVE eventIndex, WAVE marker, WAVE/T comboKeys] Redimension/N=(numEntries) results, marker, eventIndex, comboKeys - if(!cmpstr(propLabel, "isi") && numEntries >= 2) - // recalculate the isi as that might have changed due to in-between events being not selected + if(!cmpstr(propLabel, "iei") && numEntries >= 2) + // recalculate the iei as that might have changed due to in-between events being not selected Multithread results[0, numEntries - 1] = events[indizes[p]][%peak_t] - (p >= 1 ? events[indizes[p - 1]][%peak_t] : NaN) else Multithread results[] = events[indizes[p]][%$propLabel] @@ -1101,113 +1327,91 @@ static Function/WAVE PSX_GenerateSweepEquiv(WAVE selectData) return sweepEquiv End -/// @brief Collect all resolved ranges in allResolvedRanges together with a hash of the select data -Function PSX_CollectResolvedRanges(string graph, WAVE range, WAVE singleSelectData, WAVE allResolvedRanges, WAVE/T allSelectHashes) - - variable sweepNo, chanNr, chanType, numRows, mapIndex - - sweepNo = singleSelectData[0][%SWEEP] - chanNr = singleSelectData[0][%CHANNELNUMBER] - chanType = singleSelectData[0][%CHANNELTYPE] - mapIndex = singleSelectData[0][%SWEEPMAPINDEX] - - WAVE numericalValues = SFH_GetLabNoteBookForSweep(graph, sweepNo, mapIndex, LBN_NUMERICAL_VALUES) - WAVE textualValues = SFH_GetLabNoteBookForSweep(graph, sweepNo, mapIndex, LBN_TEXTUAL_VALUES) - SFH_ASSERT(WaveExists(textualValues) && WaveExists(numericalValues), "LBN not found for sweep " + num2istr(sweepNo)) - - [WAVE resolvedRanges, WAVE/T epochRangeNames] = SFH_GetNumericRangeFromEpoch(graph, numericalValues, textualValues, range, sweepNo, chanType, chanNr, mapIndex) - ASSERT(DimSize(resolvedRanges, COLS) == 1, "psxStats does not support epoch wildcards") - - numRows = DimSize(allSelectHashes, ROWS) - Redimension/N=(numRows + 1) allSelectHashes - allSelectHashes[numRows] = WaveHash(singleSelectData, HASH_SHA2_256) - - Concatenate/NP {resolvedRanges}, allResolvedRanges +/// @brief Check that the 2xN wave allResolvedRanges has only +/// non-intersecting ranges +static Function PSX_CheckResolvedRanges(WAVE allResolvedRanges) if(DimSize(allResolvedRanges, COLS) == 0) - Redimension/N=(-1, 1) allResolvedRanges + return NaN endif -End - -/// @brief Check that the 2xN wave allResolvedRanges has only -/// non-intersecting ranges for the same select data hash -static Function PSX_CheckResolvedRanges(WAVE allResolvedRanges, WAVE/T allSelectHashes) - - string selectHash - variable numRows, numColumns, i, idx - numRows = DimSize(allResolvedRanges, ROWS) - numColumns = DimSize(allResolvedRanges, COLS) + MatrixOp/FREE allResolvedRangesTransp = allResolvedRanges^t - ASSERT(numColumns == DimSize(allSelectHashes, ROWS), "Mismatched row sizes") - - for(selectHash : GetUniqueEntries(allSelectHashes)) - Make/N=(numRows, numColumns)/FREE work - - for(i = 0, idx = 0; i < numColumns; i += 1) - if(!cmpstr(selectHash, allSelectHashes[i])) - work[][idx] = allResolvedRanges[p][i] - idx += 1 - endif - endfor - - MatrixOp/FREE workTransposed = work^t - - ASSERT(idx > 0, "Invalid idx after searching") - Redimension/N=(idx, -1) workTransposed - - ASSERT(!AreIntervalsIntersecting(workTransposed), "Can't work with multiple intersecting ranges") - endfor + SFH_ASSERT(!AreIntervalsIntersecting(allResolvedRangesTransp), "Can't work with multiple intersecting ranges") End /// @brief Helper function of the `psxStats` operation -static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE rangeParam, WAVE selectData, string prop, string stateAsStr, string postProc) +static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE ranges, WAVE selectData, string prop, string stateAsStr, string postProc) string propLabelAxis, comboKey - variable numRows, numCols, i, j, k, index, sweepNo, chanNr, chanType, state, numRanges, lowerBoundary, upperBoundary, temp, err - variable refMarker, idx, mapIndex + variable numEquivChannelNumberTypes, numEquivSweeps, i, j, k, index, sweepNo, chanNr, chanType + variable state, numRanges, lowerBoundary, upperBoundary, temp, err, mapIndex, singleRange + variable refMarker, idx WAVE/WAVE output = SFH_CreateSFRefWave(graph, SF_OP_PSX_STATS, MINIMUM_WAVE_SIZE) // create equivalence classes where chanNr/chanType are the same and only the sweep number differs WAVE selectDataEquiv = PSX_GenerateSweepEquiv(selectData) - numRows = DimSize(selectDataEquiv, ROWS) - numCols = DimSize(selectDataEquiv, COLS) + numEquivChannelNumberTypes = DimSize(selectDataEquiv, ROWS) + numEquivSweeps = DimSize(selectDataEquiv, COLS) - WAVE/WAVE allRanges = SplitWavesToDimension(rangeParam) - numRanges = DimSize(allRanges, ROWS) - WaveClear rangeParam + numRanges = DimSize(ranges, ROWS) + SFH_ASSERT(numRanges > 0, "Expected at least one range") + singleRange = (numRanges == 1) - Make/D/FREE/N=(0) allResolvedRanges - Make/T/FREE/N=(0) allSelectHashes + if(!singleRange) + SFH_ASSERT(DimSize(selectDataEquiv, COLS) == numRanges, "The number of sweeps and ranges differ") + endif WAVE/Z eventContainerFromResults = PSX_GetEventContainerFromResults(id) WAVE/Z eventContainer = PSX_GetEventContainer(graph, requestID = id) Make/FREE/WAVE/N=(MINIMUM_WAVE_SIZE) allEvents - // iteration order: different chanType/chanNr (equivalence classes), range, sweepNo - for(i = 0; i < numRows; i += 1) - for(j = 0; j < numRanges; j += 1) - WAVE range = allRanges[j] + // iteration order: different chanType/chanNr (equivalence classes), sweepNo + for(i = 0; i < numEquivChannelNumberTypes; i += 1) + for(j = 0; j < numEquivSweeps; j += 1) + + [chanNr, chanType, sweepNo, mapIndex] = PSX_GetSweepEquivKeyAndValue(selectDataEquiv, i, j) + + if(!IsValidSweepNumber(sweepNo)) + break + endif - for(k = 0; k < numCols; k += 1) + WAVE singleSelectData = SFH_NewSelectDataWave(1, 1) - [chanNr, chanType, sweepNo, mapIndex] = PSX_GetSweepEquivKeyAndValue(selectDataEquiv, i, k) + singleSelectData[0][%SWEEP] = sweepNo + singleSelectData[0][%CHANNELNUMBER] = chanNr + singleSelectData[0][%CHANNELTYPE] = chanType + singleSelectData[0][%SWEEPMAPINDEX] = mapIndex - if(!IsValidSweepNumber(sweepNo)) - break - endif + WAVE rangesForSweep = ranges[singleRange ? 0 : j] + + WAVE/Z numericalValues = SFH_GetLabNoteBookForSweep(graph, sweepNo, mapIndex, LBN_NUMERICAL_VALUES) + WAVE/Z textualValues = SFH_GetLabNoteBookForSweep(graph, sweepNo, mapIndex, LBN_TEXTUAL_VALUES) + SFH_ASSERT(WaveExists(textualValues) && WaveExists(numericalValues), "LBN not found for sweep " + num2istr(sweepNo)) + + [WAVE resolvedRanges, WAVE/T epochRangeNames] = SFH_GetNumericRangeFromEpoch(graph, numericalValues, textualValues, rangesForSweep, sweepNo, chanType, chanNr, mapIndex) - WAVE singleSelectData = SFH_NewSelectDataWave(1, 1) + if(!WaveExists(resolvedRanges)) + continue + endif + + PSX_CheckResolvedRanges(resolvedRanges) - singleSelectData[0][%SWEEP] = sweepNo - singleSelectData[0][%CHANNELNUMBER] = chanNr - singleSelectData[0][%CHANNELTYPE] = chanType - singleSelectData[0][%SWEEPMAPINDEX] = mapIndex + numRanges = DimSize(resolvedRanges, COLS) + for(k = 0; k < numRanges; k += 1) + Duplicate/FREE/RMD=[*][k] resolvedRanges, range - comboKey = PSX_GenerateComboKey(graph, singleSelectData, range) + if(WaveExists(epochRangeNames)) + Make/T/FREE rangeText = {epochRangeNames[k]} + WAVE rangeAlt = rangeText + else + WAVE rangeAlt = range + endif + + comboKey = PSX_GenerateComboKey(graph, singleSelectData, rangeAlt) WAVE/Z events = PSX_FilterEventContainer(eventContainer, comboKey) @@ -1225,203 +1429,224 @@ static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE r allEvents[idx] = events idx += 1 WaveClear events - - PSX_CollectResolvedRanges(graph, range, singleSelectData, allResolvedRanges, allSelectHashes) endfor + endfor - Redimension/N=(idx) allEvents + Redimension/N=(idx) allEvents - SFH_ASSERT(DimSize(allEvents, ROWS) > 0, "Could not find any PSX events for all given combinations.") + SFH_ASSERT(DimSize(allEvents, ROWS) > 0, "Could not find any PSX events for all given combinations.") - strswitch(prop) - case "amp": - propLabelAxis = "Amplitude" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_Y_DATA_UNIT) + ")" - break - case "xpos": - propLabelAxis = "Event time" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" - break - case "xinterval": - propLabelAxis = "Event interval" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" - break - case "tau": - propLabelAxis = "Decay tau" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" - break - case "estate": - propLabelAxis = "Event manual QC" + " (enum)" - break - case "fstate": - propLabelAxis = "Fit manual QC" + " (enum)" - break - case "fitresult": - propLabelAxis = "Fit result" + " (0/1)" - break - case "risetime": - propLabelAxis = "Rise time" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" - break - default: - ASSERT(0, "Impossible prop") - endswitch + strswitch(prop) + case "amp": + propLabelAxis = "Amplitude" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_Y_DATA_UNIT) + ")" + break + case "peak": + propLabelAxis = "Event" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_Y_DATA_UNIT) + ")" + break + case "peaktime": + propLabelAxis = "Event time" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" + break + case "deconvpeak": + propLabelAxis = "Deconvoluted peak" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_Y_DATA_UNIT) + ")" + break + case "deconvpeaktime": + propLabelAxis = "Deconvoluted peak time" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" + break + case "baseline": + propLabelAxis = "Baseline" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_Y_DATA_UNIT) + ")" + break + case "baselinetime": + propLabelAxis = "Baseline time" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" + break + case "xinterval": + propLabelAxis = "Event interval" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" + break + case "tau": + propLabelAxis = "Decay tau" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" + break + case "estate": + propLabelAxis = "Event manual QC" + " (enum)" + break + case "fstate": + propLabelAxis = "Fit manual QC" + " (enum)" + break + case "fitresult": + propLabelAxis = "Fit result" + " (0/1)" + break + case "slewrate": + propLabelAxis = "Slew Rate" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_Y_DATA_UNIT) + ")" + break + case "slewratetime": + propLabelAxis = "Slew Rate time" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" + break + case "risetime": + propLabelAxis = "Rise time" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" + break + case "onsettime": + propLabelAxis = "Onset time" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_X_DATA_UNIT) + ")" + break - if(!cmpstr(stateAsStr, "every")) - WAVE allStates = PSX_GetStates() - else - Make/FREE allStates = {PSX_ParseState(stateAsStr)} + default: + ASSERT(0, "Impossible prop: " + prop) + endswitch + + if(!cmpstr(stateAsStr, "every")) + WAVE allStates = PSX_GetStates() + else + Make/FREE allStates = {PSX_ParseState(stateAsStr)} + endif + + for(state : allStates) + + [WAVE resultsRaw, WAVE eventIndex, WAVE marker, WAVE/T comboKeys] = PSX_GetStatsResults(allEvents, state, prop) + + if(!WaveExists(resultsRaw)) + continue endif - for(state : allStates) + strswitch(postProc) + case "nothing": + WAVE/D results = resultsRaw - [WAVE resultsRaw, WAVE eventIndex, WAVE marker, WAVE/T comboKeys] = PSX_GetStatsResults(allEvents, state, prop) + JWN_SetWaveInWaveNote(results, SF_META_XVALUES, eventIndex) + break + case "stats": + WAVE/Z resultsRawClean = ZapNaNs(resultsRaw) - if(!WaveExists(resultsRaw)) - continue - endif + if(!WaveExists(resultsRawClean)) + continue + endif - strswitch(postProc) - case "nothing": - WAVE/D results = resultsRaw + WaveStats/Q/M=2 resultsRawClean - JWN_SetWaveInWaveNote(results, SF_META_XVALUES, eventIndex) - break - case "stats": - WAVE/Z resultsRawClean = ZapNaNs(resultsRaw) + Make/FREE/D results = {V_avg, NaN, V_adev, V_sdev, V_skew, V_kurt} - if(!WaveExists(resultsRawClean)) - continue - endif + StatsQuantiles/Q/Z resultsRawClean + MakeWaveFree($"W_StatsQuantiles") - WaveStats/Q/M=2 resultsRawClean + if(!V_Flag) + results[1] = V_Median + endif - Make/FREE/D results = {V_avg, NaN, V_adev, V_sdev, V_skew, V_kurt} + WAVE/T statsLabels = ListToTextWave(PSX_STATS_LABELS, ";") + JWN_SetWaveInWaveNote(results, SF_META_XVALUES, statsLabels) + SetDimensionLabels(results, PSX_STATS_LABELS, ROWS) - StatsQuantiles/Q/Z resultsRawClean - MakeWaveFree($"W_StatsQuantiles") + // resize markers + Redimension/N=(DimSize(results, ROWS)) marker + refMarker = marker[0] + marker[] = refMarker - if(!V_Flag) - results[1] = V_Median - endif + break + case "nonfinite": + // map: + // -inf -> -1 + // NaN -> 0 + // +inf -> +1 + // finite -> NaN + Duplicate/FREE resultsRaw, results + Multithread results[] = resultsRaw[p] == -Inf ? -1 : (IsNaN(resultsRaw[p]) ? 0 : (resultsRaw[p] == +Inf ? +1 : NaN)) + + WAVE/Z resultsClean = ZapNaNs(results) + + if(!WaveExists(resultsClean)) + continue + endif - WAVE/T statsLabels = ListToTextWave(PSX_STATS_LABELS, ";") - JWN_SetWaveInWaveNote(results, SF_META_XVALUES, statsLabels) - SetDimensionLabels(results, PSX_STATS_LABELS, ROWS) - - // resize markers - Redimension/N=(DimSize(results, ROWS)) marker - refMarker = marker[0] - marker[] = refMarker - - break - case "nonfinite": - // map: - // -inf -> -1 - // NaN -> 0 - // +inf -> +1 - // finite -> NaN - Duplicate/FREE resultsRaw, results - Multithread results[] = resultsRaw[p] == -Inf ? -1 : (IsNaN(resultsRaw[p]) ? 0 : (resultsRaw[p] == +Inf ? +1 : NaN)) - - WAVE/Z resultsClean = ZapNaNs(results) - - if(!WaveExists(resultsClean)) - continue - endif + eventIndex[] = IsFinite(results[p]) ? eventIndex[p] : NaN + marker[] = IsFinite(results[p]) ? marker[p] : NaN + comboKeys[] = SelectString(IsFinite(results[p]), "", comboKeys[p]) - eventIndex[] = IsFinite(results[p]) ? eventIndex[p] : NaN - marker[] = IsFinite(results[p]) ? marker[p] : NaN - comboKeys[] = SelectString(IsFinite(results[p]), "", comboKeys[p]) - - WAVE markerClean = ZapNaNs(marker) - WAVE eventIndexClean = ZapNaNs(eventIndex) - RemoveTextWaveEntry1D(comboKeys, "", all = 1) - - // y-data will be eventIndex, and x the numeric categories of non-finiteness - WAVE marker = markerClean - WAVE results = eventIndexClean - WAVE xValues = resultsClean - - Redimension/D results - - JWN_SetWaveInWaveNote(results, SF_META_XVALUES, xValues) - - break - case "count": - MatrixOP/FREE results = numRows(resultsRaw) - break - case "hist": - Make/FREE/N=0/D results - - // truncate the input data to get usable histogram bins - // using allEvents assumes that the same psxKernel was used for - // all input events, which sounds reasonable. - if(!cmpstr(prop, "tau") || !cmpstr(prop, "amp")) - if(!cmpstr(prop, "tau")) - lowerBoundary = 0 - upperBoundary = PSX_STATS_TAU_FACTOR * JWN_GetNumberFromWaveNote(allEvents, SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/psxKernel/decayTau") - ASSERT(IsFinite(upperBoundary) && upperBoundary > 0, "Upper boundary for tau must be finite and positive") - elseif(!cmpstr(prop, "amp")) - temp = PSX_STATS_AMP_FACTOR * JWN_GetNumberFromWaveNote(allEvents, SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/psxKernel/amp") - lowerBoundary = -abs(temp) - upperBoundary = +abs(temp) - ASSERT(IsFinite(lowerBoundary) && IsFinite(upperBoundary), "Lower/Upper boundary for amp must be finite") - endif - - resultsRaw[] = LimitWithReplace(resultsRaw[p], lowerBoundary, upperBoundary, NaN) - endif + WAVE markerClean = ZapNaNs(marker) + WAVE eventIndexClean = ZapNaNs(eventIndex) + RemoveTextWaveEntry1D(comboKeys, "", all = 1) + + // y-data will be eventIndex, and x the numeric categories of non-finiteness + WAVE marker = markerClean + WAVE results = eventIndexClean + WAVE xValues = resultsClean + + Redimension/D results - WAVE/Z resultsRawClean = ZapNaNs(resultsRaw) + JWN_SetWaveInWaveNote(results, SF_META_XVALUES, xValues) - if((!WaveExists(resultsRawClean) && WaveExists(resultsRaw)) \ - || (DimSize(resultsRawClean, ROWS) != DimSize(resultsRaw, ROWS))) - if(!AlreadyCalledOnce(CO_PSX_CLIPPED_STATS)) - printf "psxStats removed out-of-range input data for histogram generation.\r" - ControlWindowToFront() - endif + break + case "count": + MatrixOP/FREE results = numRows(resultsRaw) + break + case "hist": + Make/FREE/N=0/D results + + // truncate the input data to get usable histogram bins + // using allEvents assumes that the same psxKernel was used for + // all input events, which sounds reasonable. + if(!cmpstr(prop, "tau") || !cmpstr(prop, "amp")) + if(!cmpstr(prop, "tau")) + lowerBoundary = 0 + upperBoundary = PSX_STATS_TAU_FACTOR * JWN_GetNumberFromWaveNote(allEvents, SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/psxKernel/decayTau") + ASSERT(IsFinite(upperBoundary) && upperBoundary > 0, "Upper boundary for tau must be finite and positive") + elseif(!cmpstr(prop, "amp")) + temp = PSX_STATS_AMP_FACTOR * JWN_GetNumberFromWaveNote(allEvents, SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/psxKernel/amp") + lowerBoundary = -abs(temp) + upperBoundary = +abs(temp) + ASSERT(IsFinite(lowerBoundary) && IsFinite(upperBoundary), "Lower/Upper boundary for amp must be finite") endif - if(!WaveExists(resultsRawClean)) - continue + resultsRaw[] = LimitWithReplace(resultsRaw[p], lowerBoundary, upperBoundary, NaN) + endif + + WAVE/Z resultsRawClean = ZapNaNs(resultsRaw) + + if((!WaveExists(resultsRawClean) && WaveExists(resultsRaw)) \ + || (DimSize(resultsRawClean, ROWS) != DimSize(resultsRaw, ROWS))) + if(!AlreadyCalledOnce(CO_PSX_CLIPPED_STATS)) + printf "psxStats removed out-of-range input data for histogram generation.\r" + ControlWindowToFront() endif + endif - Histogram/DP/B=5/DEST=results resultsRawClean - break - case "log10": - MatrixOp/FREE results = log(resultsRaw) - - JWN_SetWaveInWaveNote(results, SF_META_XVALUES, eventIndex) - break - default: - ASSERT(0, "Impossible postProc state") - endswitch - - JWN_SetWaveInWaveNote(results, SF_META_RANGE, range) - // passing in sweepNo is not correct when combining data from multiple sweeps - // but we need it to be set to something valid so that the headstage colors work - // we assume therefore that all sweeps use the same active HS/AD/DAC settings - JWN_SetNumberInWaveNote(results, SF_META_SWEEPNO, sweepNo) - JWN_SetNumberInWaveNote(results, SF_META_CHANNELTYPE, chanType) - JWN_SetNumberInWaveNote(results, SF_META_CHANNELNUMBER, chanNr) - - ASSERT(DimSize(results, ROWS) <= DimSize(marker, ROWS), "results wave got larger unexpectedly") - Redimension/N=(DimSize(results, ROWS)) marker, comboKeys - - JWN_SetNumberInWaveNote(results, SF_META_TRACE_MODE, TRACE_DISPLAY_MODE_MARKERS) - JWN_SetWaveInWaveNote(results, SF_META_MOD_MARKER, marker) - JWN_CreatePath(results, SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME) - JWN_SetWaveInWaveNote(results, SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME, comboKeys) - - JWN_CreatePath(results, SF_META_USER_GROUP + PSX_JWN_STATS_POST_PROC) - JWN_SetStringInWaveNote(results, SF_META_USER_GROUP + PSX_JWN_STATS_POST_PROC, postProc) - - JWN_SetNumberInWaveNote(results, SF_META_SHOW_LEGEND, 0) - - EnsureLargeEnoughWave(output, indexShouldExist = index) - output[index] = results - index += 1 - endfor + if(!WaveExists(resultsRawClean)) + continue + endif + + Histogram/DP/B=5/DEST=results resultsRawClean + break + case "log10": + MatrixOp/FREE results = log(resultsRaw) + + JWN_SetWaveInWaveNote(results, SF_META_XVALUES, eventIndex) + break + default: + ASSERT(0, "Impossible postProc state") + endswitch + + // passing in sweepNo is not correct as we combine data from multiple sweeps + // but we need it to be set to something valid so that the headstage colors work + // we assume therefore that all sweeps use the same active HS/AD/DAC settings + JWN_SetNumberInWaveNote(results, SF_META_SWEEPNO, sweepNo) + JWN_SetNumberInWaveNote(results, SF_META_CHANNELTYPE, chanType) + JWN_SetNumberInWaveNote(results, SF_META_CHANNELNUMBER, chanNr) + JWN_SetNumberInWaveNote(results, SF_META_SWEEPMAPINDEX, mapIndex) + + ASSERT(DimSize(results, ROWS) <= DimSize(marker, ROWS), "results wave got larger unexpectedly") + Redimension/N=(DimSize(results, ROWS)) marker, comboKeys + + JWN_SetNumberInWaveNote(results, SF_META_TRACE_MODE, TRACE_DISPLAY_MODE_MARKERS) + JWN_SetWaveInWaveNote(results, SF_META_MOD_MARKER, marker) + JWN_CreatePath(results, SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME) + JWN_SetWaveInWaveNote(results, SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME, comboKeys) + + JWN_CreatePath(results, SF_META_USER_GROUP + PSX_JWN_STATS_POST_PROC) + JWN_SetStringInWaveNote(results, SF_META_USER_GROUP + PSX_JWN_STATS_POST_PROC, postProc) + + JWN_SetNumberInWaveNote(results, SF_META_SHOW_LEGEND, 0) + + EnsureLargeEnoughWave(output, indexShouldExist = index) + output[index] = results + index += 1 endfor endfor - PSX_CheckResolvedRanges(allResolvedRanges, allSelectHashes) - Redimension/N=(index) output // PSX_MouseEventSelection works for "nothing" and "log10" post processing @@ -1461,43 +1686,24 @@ static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE r return output End -static Function/WAVE PSX_CalculateRiseTime(WAVE psxEvent, WAVE sweepDataFiltOff, variable parameterJsonID, variable kernelAmp, variable lowerThreshold, variable upperThreshold) - - string psxParameters, comboKey, cacheKey - variable numEvents - - psxParameters = PSX_GetPSXParameters(parameterJsonID, PSX_CACHE_KEY_RISETIME) - comboKey = JWN_GetStringFromWaveNote(psxEvent, PSX_EVENTS_COMBO_KEY_WAVE_NOTE) - - cacheKey = CA_PSXRiseTimeKey(comboKey, psxParameters) - WAVE/Z riseTimeFromCache = CA_TryFetchingEntryFromCache(cacheKey) - - if(WaveExists(riseTimeFromCache)) - return riseTimeFromCache - endif - - numEvents = DimSize(psxEvent, ROWS) - - Make/D/FREE/N=(numEvents) riseTime - - riseTime[] = PSX_CalculateRiseTimeImpl(psxEvent, sweepDataFiltOff, kernelAmp, psxEvent[p][%index], lowerThreshold, upperThreshold) - - CA_StoreEntryIntoCache(cacheKey, riseTime) - - return riseTime -End - -static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataFiltOff, variable kernelAmp, variable index, variable lowerThreshold, variable upperThreshold) +threadsafe static Function PSX_CalculateRiseTime(WAVE sweepDataOffFilt, WAVE psxEvent, variable kernelAmp, variable lowerThreshold, variable upperThreshold, variable index) variable dY, xStart, xEnd, yStart, yEnd, xlt, xupt, lowerLevel, upperLevel, riseTime variable printDebug string comboKey - xStart = psxEvent[index][%peak_t] - yStart = sweepDataFiltOff(xStart) + // deconvPeak is defined in the deconvoluted wave, + // so we can't use %deconvPeak as y-value + xStart = psxEvent[index][%$"Onset Time"] + + if(IsNaN(xStart)) + return NaN + endif + + yStart = sweepDataOffFilt(xStart) - xEnd = psxEvent[index][%post_min_t] - yEnd = psxEvent[index][%post_min] + xEnd = psxEvent[index][%peak_t] + yEnd = psxEvent[index][%peak] dY = abs(yStart - yEnd) @@ -1508,7 +1714,7 @@ static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataFiltOff, xlt = NaN xupt = NaN - FindLevel/R=(xStart, xEnd)/Q sweepDataFiltOff, lowerLevel + FindLevel/R=(xStart, xEnd)/Q sweepDataOffFilt, lowerLevel if(!V_flag) xlt = V_levelX @@ -1516,7 +1722,7 @@ static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataFiltOff, printDebug = 1 endif - FindLevel/R=(xStart, xEnd)/Q sweepDataFiltOff, upperLevel + FindLevel/R=(xStart, xEnd)/Q sweepDataOffFilt, upperLevel if(!V_flag) xupt = V_levelX @@ -1524,7 +1730,7 @@ static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataFiltOff, printDebug = 1 endif - ASSERT(kernelAmp != 0 && IsFinite(kernelAmp), "kernelAmp must be finite and not zero") + ASSERT_TS(kernelAmp != 0 && IsFinite(kernelAmp), "kernelAmp must be finite and not zero") riseTime = (xlt - xupt) * sign(kernelAmp) * (-1) #ifdef DEBUGGING_ENABLED @@ -1538,6 +1744,49 @@ static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataFiltOff, return riseTime End +threadsafe static Function PSX_CalculateOnsetTime(WAVE sweepDataDiff, WAVE psxEvent, variable kernelAmp, variable diffThreshPerc, variable index) + + variable slewRate, slewRate_t, level, baseline_t, peak_t + string msg + + peak_t = psxEvent[index][%peak_t] + baseline_t = psxEvent[index][%baseline_t] + + WaveStats/Q/M=1/R=(peak_t, baseline_t) sweepDataDiff + if(kernelAmp > 0) + slewRate = V_max + slewRate_t = V_maxLoc + elseif(kernelAmp < 0) + slewRate = V_min + slewRate_t = V_minLoc + else + ASSERT_TS(0, "Unsupported case: kernelAmp being zero") + endif + + psxEvent[index][%$"Slew Rate"] = slewRate + psxEvent[index][%$"Slew Rate Time"] = slewRate_t + + level = diffThreshPerc * (slewRate - sweepDataDiff(baseline_t)) + +#ifdef DEBUGGING_ENABLED + sprintf msg, "comboKey = %s\r", JWN_GetStringFromWaveNote(psxEvent, PSX_EVENTS_COMBO_KEY_WAVE_NOTE) + DEBUGPRINT_TS(msg) + sprintf msg, "index = %d, peak_t = %g, baseline_t = %g, slew rate = %g, slew rate time = %g\r", index, peak_t, baseline_t, slewRate, slewRate_t + DEBUGPRINT_TS(msg) + sprintf msg, "level = %g, [%g, %g]\r", level, slewRate_t, baseline_t + DEBUGPRINT_TS(msg) +#endif + + // search backwards in time + FindLevel/R=(slewRate_t, baseline_t)/Q sweepDataDiff, level + + if(V_flag) + return NaN + endif + + return V_levelX +End + /// @brief Return all possible fit/event states /// /// @param withAllState [optional, defaults to false] choose to include #PSX_ALL (true) or not (false) @@ -1663,14 +1912,22 @@ static Function PSX_UpdateSingleEventGraph(string win, variable index) DFREF comboDFR = PSX_GetCurrentComboFolder(win) + WAVE/WAVE eventFit = GetPSXEventFitWaveFromDFR(comboDFR) + + if(!(index >= 0 && index < DimSize(eventFit, ROWS))) + return NaN + endif + PSX_UpdateDisplayedFit(comboDFR, index) extSingleGraph = PSX_GetSingleEventGraph(win) PSX_UpdateSingleEventTextbox(extSingleGraph, eventIndex = index) - WAVE psxEvent = GetPSXEventWaveFromDFR(comboDFR) - [first, last] = PSX_GetSingleEventRange(psxEvent, index) + WAVE psxEvent = GetPSXEventWaveFromDFR(comboDFR) + WAVE sweepDataOffFilt = GetPSXSweepDataOffFiltWaveFromDFR(comboDFR) + + [first, last] = PSX_GetSingleEventRange(psxEvent, sweepDataOffFilt, index) WAVE singleEventFit = GetPSXSingleEventFitWaveFromDFR(comboDFR) @@ -1735,7 +1992,7 @@ static Function PSX_UpdateOffsetInAllEventGraph(string win) WAVE psxEvent = GetPSXEventWaveFromDFR(comboDFR) numEvents = DimSize(psxEvent, ROWS) - WAVE sweepDataFiltOff = GetPSXSweepDataFiltOffWaveFromDFR(comboDFR) + WAVE sweepDataOffFilt = GetPSXSweepDataOffFiltWaveFromDFR(comboDFR) DFREF singleEventDFR = GetPSXSingleEventFolder(comboDFR) @@ -1743,17 +2000,21 @@ static Function PSX_UpdateOffsetInAllEventGraph(string win) WAVE/Z/SDFR=singleEventDFR singleEvent = $GetIndexedObjNameDFR(singleEventDFR, COUNTOBJECTS_WAVES, i) ASSERT(WaveExists(singleEvent), "Non-existing single event wave") - [first, last] = PSX_GetSingleEventRange(psxEvent, i) + [first, last] = PSX_GetSingleEventRange(psxEvent, sweepDataOffFilt, i) - Duplicate/FREE/R=(first, last) sweepDataFiltOff, singleEventRaw + Duplicate/FREE/R=(first, last) sweepDataOffFilt, singleEventRaw switch(offsetMode) case PSX_HORIZ_OFFSET_ONSET: - xOffset = 0 - yOffset = sweepDataFiltOff(psxEvent[i][%peak_t]) + xOffset = IsFinite(psxEvent[i][%$"Onset Time"]) ? first - psxEvent[i][%$"Onset Time"] : 0 + yOffset = 0 break case PSX_HORIZ_OFFSET_PEAK: - xOffset = first - psxEvent[i][%post_min_t] + xOffset = first - psxEvent[i][%peak_t] + yOffset = 0 + break + case PSX_HORIZ_OFFSET_SLEW: + xOffset = first - psxEvent[i][%$"Slew Rate Time"] yOffset = 0 break default: @@ -1941,7 +2202,7 @@ static Function PSX_UpdateAverageTraces(string win, WAVE/T eventIndexFromTraces, numEvents = DimSize(eventIndexFromTraces, ROWS) Make/WAVE/FREE/N=(numEvents) contAverageAll, contAverageAccept, contAverageReject, contAverageUndet - Make/FREE/D/N=(numEvents) eventStartTime, eventStopTime + Make/FREE/D/N=(numEvents) eventStopTime for(i = 0; i < numEvents; i += 1) idx = str2num(eventIndexFromTraces[i]) @@ -1958,16 +2219,12 @@ static Function PSX_UpdateAverageTraces(string win, WAVE/T eventIndexFromTraces, case PSX_ACCEPT: contAverageAccept[acceptIndex] = singleEvent - WAVE sweepDataFiltOff = GetPSXSweepDataFiltOffWaveFromDFR(comboDFR) + WAVE sweepDataOffFilt = GetPSXSweepDataOffFiltWaveFromDFR(comboDFR) WAVE psxEvent = GetPSXEventWaveFromDFR(comboDFR) // single event waves are zeroed in x-direction to extractStartAbs - [extractStartAbs, extractStopAbs] = PSX_GetSingleEventRange(psxEvent, idx) - fitStartAbs = psxEvent[idx][%peak_t] - ASSERT(fitStartAbs > extractStartAbs, "Unexpected fit/extraction start positions") - - eventStartTime[acceptIndex] = fitStartAbs - extractStartAbs - eventStopTime[acceptIndex] = extractStopAbs - extractStartAbs + [extractStartAbs, extractStopAbs] = PSX_GetSingleEventRange(psxEvent, sweepDataOffFilt, idx) + eventStopTime[acceptIndex] = extractStopAbs - extractStartAbs acceptIndex += 1 break @@ -1993,8 +2250,8 @@ static Function PSX_UpdateAverageTraces(string win, WAVE/T eventIndexFromTraces, PSX_UpdateAverageWave(contAverageUndet, undetIndex, averageDFR, PSX_UNDET) PSX_UpdateAverageWave(contAverageAll, numEvents, averageDFR, PSX_ALL) - Redimension/N=(acceptIndex) eventStartTime, eventStopTime - PSX_FitAcceptAverage(win, averageDFR, eventStartTime, eventStopTime) + Redimension/N=(acceptIndex) eventStopTime + PSX_FitAcceptAverage(win, averageDFR, eventStopTime) End /// @brief Helper function to update the average waves for the all event graph @@ -2018,10 +2275,10 @@ static Function/DF PSX_GetAverageFolder(string win) endif End -static Function PSX_FitAcceptAverage(string win, DFREF averageDFR, WAVE eventStartTime, WAVE eventStopTime) +static Function PSX_FitAcceptAverage(string win, DFREF averageDFR, WAVE eventStopTime) string specialEventPanel, str, htmlStr, rawCode, browser, msg, fitFunc - variable err, numAveragePoints, start, stop + variable err, numAveragePoints, start, stop, meanStopTime WAVE acceptedAverageFit = GetPSXAcceptedAverageFitWaveFromDFR(averageDFR) @@ -2046,8 +2303,15 @@ static Function PSX_FitAcceptAverage(string win, DFREF averageDFR, WAVE eventSta FastOp acceptedAverageFit = (NaN) CopyScales average, acceptedAverageFit - start = max(0, mean(eventStartTime)) - stop = min(IndexToScale(average, DimSize(average, ROWS) - 1, ROWS), mean(eventStopTime)) + WAVE/Z eventStopTimeClean = ZapNaNs(eventStopTime) + if(WaveExists(eventStopTimeClean)) + meanStopTime = mean(eventStopTime) + else + meanStopTime = Inf + endif + + start = 0 + stop = min(IndexToScale(average, DimSize(average, ROWS) - 1, ROWS), meanStopTime) AssertOnAndClearRTError() fitFunc = GetPopupMenuString(specialEventPanel, "popupmenu_accept_fit_function") @@ -2133,10 +2397,6 @@ static Function/S PSX_GetPSXParameters(variable jsonID, variable cacheKeyType) switch(cacheKeyType) case PSX_CACHE_KEY_EVENTS: case PSX_CACHE_KEY_ANALYZE_PEAKS: - // remove riseTime as that does not influence the found events or the results from PSX_AnalyzePeaks - JSON_Remove(subJsonID, SF_OP_PSX_RISETIME) - break - case PSX_CACHE_KEY_RISETIME: // do nothing break default: @@ -2178,9 +2438,9 @@ static Function/WAVE PSX_LoadEventsFromCache(string comboKey, string psxParamete return $"" endif - UpgradePSXEventWave(psxEvent) + WAVE/Z psxEventUpgraded = UpgradePSXEventWave(psxEvent) - return psxEvent + return psxEventUpgraded End /// @brief Return the trace user data keys/values wave for the given trace type @@ -2552,15 +2812,18 @@ static Function PSX_UpdateSingleEventTextbox(string win, [variable eventIndex]) Make/FREE/T/N=(8, 2) input - input[0][0] = {"Event State:", "Fit State:", "Fit Result:", "Event:", "Position:", "IsI:", "Amp (rel.):", "Tau:", "Rise time:"} - input[0][1] = {PSX_StateToString(psxEvent[eventIndex][%$"Event manual QC call"]), \ - PSX_StateToString(psxEvent[eventIndex][%$"Fit manual QC call"]), \ - PSX_FitResultToString(psxEvent[eventIndex][%$"Fit Result"]), \ - num2istr(eventIndex), \ - num2str(psxEvent[eventIndex][%peak_t], "%8.02f") + " [ms]", \ - num2str(psxEvent[eventIndex][%isi], "%8.02f") + " [" + yUnit + "]", \ - num2str(psxEvent[eventIndex][%rel_peak], "%8.02f") + " [" + yUnit + "]", \ - num2str(psxEvent[eventIndex][%tau], "%8.02f") + " [ms]", \ + input[0][0] = {"Event State:", "Fit State:", "Fit Result:", "Event:", "Deconv Peak:", "Peak:", "Baseline:", "IeI:", "Amp (rel.):", "Tau:", "Onset time:", "Rise time:"} + input[0][1] = {PSX_StateToString(psxEvent[eventIndex][%$"Event manual QC call"]), \ + PSX_StateToString(psxEvent[eventIndex][%$"Fit manual QC call"]), \ + PSX_FitResultToString(psxEvent[eventIndex][%$"Fit Result"]), \ + num2istr(eventIndex), \ + num2str(psxEvent[eventIndex][%deconvPeak_t], "%8.02f") + " [ms]", \ + num2str(psxEvent[eventIndex][%peak_t], "%8.02f") + " [ms]", \ + num2str(psxEvent[eventIndex][%baseline_t], "%8.02f") + " [ms]", \ + num2str(psxEvent[eventIndex][%iei], "%8.02f") + " [ms]", \ + num2str(psxEvent[eventIndex][%amplitude], "%8.02f") + " [" + yUnit + "]", \ + num2str(psxEvent[eventIndex][%tau], "%8.02f") + " [ms]", \ + num2str(psxEvent[eventIndex][%$"Onset Time"], "%8.02f") + " [ms]", \ num2str(psxEvent[eventIndex][%$"Rise Time"], "%8.02f") + " [ms]"} str = "\F'Consolas'" + FormatTextWaveForLegend(input) @@ -2643,8 +2906,8 @@ static Function PSX_CenterCursor(string win, variable leftIndex, variable consta SetAxis/W=$win/A=0 bottom, left, right - SetAxis/W=$win/A=2 leftFiltOff - SetAxis/W=$win/A=2 leftFiltOffDeconv + SetAxis/W=$win/A=2 leftOffFilt + SetAxis/W=$win/A=2 leftOffFiltDeconv DoUpdate/W=$win End @@ -3098,6 +3361,7 @@ End static Function/WAVE PSX_GetEventContainerFromResults(string id) string entry, name + variable idx, hasValidWave WAVE/T textualResultsValues = GetLogbookWaves(LBT_RESULTS, LBN_TEXTUAL_VALUES) @@ -3114,10 +3378,23 @@ static Function/WAVE PSX_GetEventContainerFromResults(string id) for(WAVE/Z psxEvent : container) ASSERT(WaveExists(psxEvent), "Missing psxEvent") - UpgradePSXEventWave(psxEvent) + WAVE/Z psxEventUpgraded = UpgradePSXEventWave(psxEvent) + + if(WaveExists(psxEventUpgraded)) + hasValidWave = 1 + endif + + container[idx] = psxEventUpgraded + idx += 1 endfor - return container + ASSERT(idx > 0, "Expected at least one entry in container") + + if(hasValidWave) + return container + endif + + return $"" End static Function/WAVE PSX_FilterEventContainer(WAVE/Z/WAVE eventContainer, string refComboKey) @@ -3209,13 +3486,16 @@ End /// @brief Store the PSX panel GUI state in the window user data of `browser` static Function PSX_StoreGuiState(string win, string browser) - variable jsonID, childID + variable jsonID, childID, latestPanelVersion string specialEventPanel, mainWindow, ctrl, extAllGraph extAllGraph = PSX_GetAllEventGraph(win) specialEventPanel = PSX_GetSpecialPanel(win) - if(IsEmpty(browser) \ + latestPanelVersion = HasPanelLatestVersion(win, PSX_PLOT_PANEL_VERSION) + + if(!latestPanelVersion \ + || IsEmpty(browser) \ || !WindowExists(browser) \ || !WindowExists(extAllGraph) \ || !WindowExists(specialEventPanel)) @@ -3424,13 +3704,13 @@ static Function PSX_MoveWavesToDataFolders(DFREF workDFR, WAVE/Z/WAVE results, v MoveWave results[%$key][1], dfr:sweepData WAVE/SDFR=dfr sweepData - key = PSX_GenerateKey("sweepDataFiltOff", i) - MoveWave results[%$key][1], dfr:sweepDataFiltOff - WAVE/SDFR=dfr sweepDataFiltOff + key = PSX_GenerateKey("sweepDataOffFilt", i) + MoveWave results[%$key][1], dfr:sweepDataOffFilt + WAVE/SDFR=dfr sweepDataOffFilt - key = PSX_GenerateKey("sweepDataFiltOffDeconv", i) - MoveWave results[%$key][1], dfr:sweepDataFiltOffDeconv - WAVE/SDFR=dfr sweepDataFiltOffDeconv + key = PSX_GenerateKey("sweepDataOffFiltDeconv", i) + MoveWave results[%$key][1], dfr:sweepDataOffFiltDeconv + WAVE/SDFR=dfr sweepDataOffFiltDeconv ASSERT(DimSize(peakX, ROWS) == DimSize(peakY, ROWS), "Mismatched peak sizes") @@ -3452,7 +3732,7 @@ static Function PSX_MoveWavesToDataFolders(DFREF workDFR, WAVE/Z/WAVE results, v MoveWave eventMarker, dfr:eventMarker Duplicate peakY, dfr:peakYAtFilt/WAVE=peakYAtFilt - peakYAtFilt[] = sweepDataFiltOff(peakX[p]) + peakYAtFilt[] = sweepDataOffFilt(peakX[p]) Make/T/N=(numEvents, 2) dfr:eventLocationLabels/WAVE=eventLocationLabels SetDimLabel COLS, 1, $"Tick Type", eventLocationLabels @@ -3461,7 +3741,7 @@ static Function PSX_MoveWavesToDataFolders(DFREF workDFR, WAVE/Z/WAVE results, v Make/D/N=(numEvents) dfr:eventLocationTicks/WAVE=eventLocationTicks eventLocationTicks[] = peakX[p] - PSX_CreateSingleEventWaves(dfr, psxEvent, sweepDataFiltOff) + PSX_CreateSingleEventWaves(dfr, psxEvent, sweepDataOffFilt) // create all waves which need to exist for combo changing WAVE singleEventFit = GetPSXSingleEventFitWaveFromDFR(dfr) @@ -3491,8 +3771,8 @@ static Function/S PSX_CheckForUniqueIDs(DFREF workDFR) return uniqueIDs[0] End -/// @brief Extract a single wave for each event from sweepDataFiltOff -static Function PSX_CreateSingleEventWaves(DFREF comboDFR, WAVE psxEvent, WAVE sweepDataFiltOff) +/// @brief Extract a single wave for each event from sweepDataOffFilt +static Function PSX_CreateSingleEventWaves(DFREF comboDFR, WAVE psxEvent, WAVE sweepDataOffFilt) variable i, numEvents, first, last, offset string name @@ -3503,9 +3783,9 @@ static Function PSX_CreateSingleEventWaves(DFREF comboDFR, WAVE psxEvent, WAVE s for(i = 0; i < numEvents; i += 1) - [first, last] = PSX_GetSingleEventRange(psxEvent, i) + [first, last] = PSX_GetSingleEventRange(psxEvent, sweepDataOffFilt, i) - Duplicate/FREE/R=(first, last) sweepDataFiltOff, singleEvent + Duplicate/FREE/R=(first, last) sweepDataOffFilt, singleEvent Note/K singleEvent @@ -3574,6 +3854,8 @@ static Function PSX_CreatePSXGraphAndSubwindows(string win, string graph, STRUCT PSX_ApplyMacroToExistingPanel(mainWin, "PSXPanel") + AddVersionToPanel(mainWin, PSX_PLOT_PANEL_VERSION) + DFREF workDFR = PSX_GetWorkingFolder(win) DFREF comboDFR = GetPSXFolderForCombo(workDFR, 0) @@ -3586,21 +3868,21 @@ static Function PSX_CreatePSXGraphAndSubwindows(string win, string graph, STRUCT WAVE peakY = GetPSXPeakYWaveFromDFR(comboDFR) WAVE peakYAtFilt = GetPSXPeakYAtFiltWaveFromDFR(comboDFR) WAVE sweepData = GetPSXSweepDataWaveFromDFR(comboDFR) - WAVE sweepDataFiltOff = GetPSXSweepDataFiltOffWaveFromDFR(comboDFR) - WAVE sweepDataFiltOffDeconv = GetPSXSweepDataFiltOffDeconvWaveFromDFR(comboDFR) + WAVE sweepDataOffFilt = GetPSXSweepDataOffFiltWaveFromDFR(comboDFR) + WAVE sweepDataOffFiltDeconv = GetPSXSweepDataOffFiltDeconvWaveFromDFR(comboDFR) [STRUCT RGBColor color] = SF_GetTraceColor(graph, plotMetaData.opStack, sweepData, $"") - AppendToGraph/W=$win/C=(color.red, color.green, color.blue)/L=leftFiltOff sweepDataFiltOff - AppendToGraph/W=$win/L=leftFiltOff peakYAtFilt vs peakX + AppendToGraph/W=$win/C=(color.red, color.green, color.blue)/L=leftOffFilt sweepDataOffFilt + AppendToGraph/W=$win/L=leftOffFilt peakYAtFilt vs peakX - AppendToGraph/W=$win/C=(color.red, color.green, color.blue)/L=leftFiltOffDeconv sweepDataFiltOffDeconv - AppendToGraph/W=$win/L=leftFiltOffDeconv peakY vs peakX + AppendToGraph/W=$win/C=(color.red, color.green, color.blue)/L=leftOffFiltDeconv sweepDataOffFiltDeconv + AppendToGraph/W=$win/L=leftOffFiltDeconv peakY vs peakX ModifyGraph/W=$win msize(peakY)=10, msize(peakYAtFilt)=10 - ModifyGraph/W=$win axisEnab(leftFiltOff)={0.51, 1}, lblPos(leftFiltOff)=70, freePos(leftFiltOff)=0 - ModifyGraph/W=$win axisEnab(leftFiltOffDeconv)={0, 0.49}, lblPos(leftFiltOffDeconv)=70, freePos(leftFiltOffDeconv)=0 + ModifyGraph/W=$win axisEnab(leftOffFilt)={0.51, 1}, lblPos(leftOffFilt)=70, freePos(leftOffFilt)=0 + ModifyGraph/W=$win axisEnab(leftOffFiltDeconv)={0, 0.49}, lblPos(leftOffFiltDeconv)=70, freePos(leftOffFiltDeconv)=0 PSX_MarkGraphForPSX(win) @@ -3631,7 +3913,7 @@ static Function PSX_CreatePSXGraphAndSubwindows(string win, string graph, STRUCT PopupMenu popup_block, win=$extSubWin, value=#("PSX_GetAllEventBlockNumbers(\"" + win + "\")") - AppendToGraph/W=$extSingleGraph/C=(color.red, color.green, color.blue) sweepDataFiltOff + AppendToGraph/W=$extSingleGraph/C=(color.red, color.green, color.blue) sweepDataOffFilt AppendToGraph/W=$extSingleGraph peakYAtFilt vs peakX SetAxis/A=2/W=$extSingleGraph left @@ -3840,6 +4122,13 @@ static Function [variable eventIndex, variable waveIndex, variable comboIndex] P return [eventIndex, yPointNumber, comboIndex] End +static Function PSX_AbortWithOldPanel(string win) + + if(!HasPanelLatestVersion(win, PSX_PLOT_PANEL_VERSION)) + DoAbortNow("Can not continue with this psx plot. The psx panel is too old to be usable. Please close it and open a new one.") + endif +End + /// @brief Window hook responsible for keyboard and mouse support /// /// Works with `psx` and `psxStats` graphs. @@ -3856,10 +4145,12 @@ Function PSX_PlotInteractionHook(STRUCT WMWinHookStruct &s) break endif - win = s.winName - eventIndex = s.pointNumber + win = s.winName - psxGraph = PSX_GetPSXGraph(win) + PSX_AbortWithOldPanel(win) + + eventIndex = s.pointNumber + psxGraph = PSX_GetPSXGraph(win) if(!cmpstr(win, psxGraph)) PSX_UpdateSingleEventGraph(psxGraph, eventIndex) @@ -3888,6 +4179,7 @@ Function PSX_PlotInteractionHook(STRUCT WMWinHookStruct &s) case EVENT_WINDOW_HOOK_KEYBOARD: win = s.winName + PSX_AbortWithOldPanel(win) // workaround IP bug where the currently selected graph is not in s.winName GetWindow $win, activeSW @@ -3943,9 +4235,9 @@ Function PSX_PlotInteractionHook(STRUCT WMWinHookStruct &s) WAVE/DF comboFolders = PSX_GetAllCombinationFolders(workDFR) DFREF comboDFR = comboFolders[comboIndex] - WAVE sweepDataFiltOff = GetPSXSweepDataFiltOffWaveFromDFR(comboDFR) + WAVE sweepDataOffFilt = GetPSXSweepDataOffFiltWaveFromDFR(comboDFR) WAVE psxEvent = GetPSXEventWaveFromDFR(comboDFR) - [first, last] = PSX_GetEventFitRange(sweepDataFiltOff, psxEvent, eventIndex) + [first, last] = PSX_GetEventFitRange(sweepDataOffFilt, psxEvent, eventIndex) sprintf msg, "Fit range for event %d: [%g, %g]", eventIndex, first, last DEBUGPRINT(msg) @@ -3958,6 +4250,8 @@ Function PSX_PlotInteractionHook(STRUCT WMWinHookStruct &s) break endif + PSX_AbortWithOldPanel(win) + // psxGraph if((s.eventMod & WINDOW_HOOK_EMOD_CTRLKEYDOWN) == WINDOW_HOOK_EMOD_CTRLKEYDOWN) DEBUGPRINT("Left mouse click and CTRL") @@ -4242,26 +4536,38 @@ Function PSX_PostPlot(string win) PSX_ApplySpecialPlotProperties(win, eventLocationTicks, eventLocationLabels) End +static Function PSX_OperationSetDimensionLabels(WAVE/WAVE output, variable numCombos, WAVE/T labels, WAVE/T labelsTemplate) + + variable i + + numCombos = DimSize(output, ROWS) / PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY + + for(i = 0; i < numCombos; i += 1) + labels[] = PSX_GenerateKey(labelsTemplate[p], i) + SetDimensionLabels(output, TextWaveToList(labels, ";"), ROWS, startPos = i * PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY) + endfor +End + /// @brief Implementation of the `psx` operation /// // Returns a SweepFormula dataset with n * PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY // entries where n denotes the number of range/channel/sweep combinations // // Output[0] = sweepData(0) -// Output[1] = sweepDataFiltOff(0) -// Output[2] = sweepDataFiltOffDeconv(0) +// Output[1] = sweepDataOffFilt(0) +// Output[2] = sweepDataOffFiltDeconv(0) // Output[3] = peakX(0) // Output[4] = peakY(0) // Output[5] = psxEvent(0) // Output[6] = psxFit(0) // Output[0] = sweepData(1) -// Output[1] = sweepDataFiltOff(1) +// Output[1] = sweepDataOffFilt(1) // ... Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) variable numberOfSDs, sweepFilterLow, sweepFilterHigh, parameterJsonID, numCombos, i, addedData, kernelAmp - variable maxTauFactor, peakThresh, numFailures - string parameterPath, id, psxParameters, dataUnit + variable maxTauFactor, peakThresh, idx, success, kernelRiseTau, kernelDecayTau + string parameterPath, id, psxParameters, dataUnit, path id = SFH_GetArgumentAsText(jsonID, jsonPath, graph, SF_OP_PSX, 0, checkFunc = IsValidObjectName) @@ -4288,6 +4594,7 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) JSON_AddTreeObject(parameterJsonID, parameterPath) JSON_AddVariable(parameterJsonID, parameterPath + "/upperThreshold", riseTime[%$"Upper Threshold"]) JSON_AddVariable(parameterJsonID, parameterPath + "/lowerThreshold", riseTime[%$"Lower Threshold"]) + JSON_AddVariable(parameterJsonID, parameterPath + "/differentiateThreshold", riseTime[%$"Differentiate Threshold"]) parameterPath = SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/" + SF_OP_PSX_DECONV_FILTER JSON_AddTreeObject(parameterJsonID, parameterPath) JSON_AddVariable(parameterJsonID, parameterPath + "/filterLow", deconvFilter[%$"Filter Low"]) @@ -4299,33 +4606,39 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) WAVE/WAVE output = SFH_CreateSFRefWave(graph, SF_OP_PSX, numCombos * PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY) - kernelAmp = JWN_GetNumberFromWaveNote(psxKernelDataset, SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/" + SF_OP_PSX_KERNEL + "/amp") + path = SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/" + SF_OP_PSX_KERNEL + kernelAmp = JWN_GetNumberFromWaveNote(psxKernelDataset, path + "/amp") ASSERT(IsFinite(kernelAmp), "psxKernel amplitude must be finite") + kernelRiseTau = JWN_GetNumberFromWaveNote(psxKernelDataset, path + "/riseTau") + ASSERT(IsFinite(kernelRiseTau), "riseTau must be finite") + kernelDecayTau = JWN_GetNumberFromWaveNote(psxKernelDataset, path + "/decayTau") + ASSERT(IsFinite(kernelDecayTau), "decayTau must be finite") WAVE/T labelsTemplate = ListToTextWave(PSX_EVENT_DIMENSION_LABELS, ";") ASSERT(DimSize(labelsTemplate, ROWS) == PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY, "Mismatched label wave") Duplicate/FREE/T labelsTemplate, labels - // generate dimension labels for all potential output - for(i = 0; i < numCombos; i += 1) - labels[] = PSX_GenerateKey(labelsTemplate[p], i) - SetDimensionLabels(output, TextWaveToList(labels, ";"), ROWS, startPos = i * PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY) - endfor + PSX_OperationSetDimensionLabels(output, numCombos, labels, labelsTemplate) for(i = 0; i < numCombos; i += 1) - PSX_OperationSweepGathering(graph, psxKernelDataset, parameterJsonID, sweepFilterLow, sweepFilterHigh, deconvFilter, i, output) + success = !PSX_OperationSweepGathering(graph, psxKernelDataset, parameterJsonID, sweepFilterLow, sweepFilterHigh, deconvFilter, idx, output) + idx += success endfor + numCombos = idx + + if(numCombos == 0) + Abort + endif + + Redimension/N=(numCombos * PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY) output + [WAVE hist, WAVE fit, peakThresh, dataUnit] = PSX_CalculatePeakThreshold(output, numCombos, numberOfSDs) WaveClear hist, fit for(i = 0; i < numCombos; i += 1) - numFailures += PSX_OperationImpl(graph, parameterJsonID, id, peakThresh, maxTauFactor, riseTime, kernelAmp, i, output) + PSX_OperationImpl(graph, parameterJsonID, id, peakThresh, maxTauFactor, riseTime, kernelAmp, kernelRiseTau, kernelDecayTau, i, output) endfor - - if(numFailures == numCombos) - Abort - endif catch if(WaveExists(output)) SFH_CleanUpInput(output) @@ -4334,7 +4647,8 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) JSON_Release(parameterJsonID) SFH_CleanUpInput(psxKernelDataset) - Abort + + SFH_ASSERT(0, "Could not gather sweep data for psx") endtry JWN_SetWaveNoteFromJSON(output, parameterJsonID) @@ -4358,7 +4672,7 @@ End // ... Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph) - variable riseTau, decayTau, amp, dt, numPoints, numCombos, i, offset + variable riseTau, decayTau, amp, dt, numPoints, numCombos, i, offset, idx string parameterPath, key WAVE/WAVE selectDataCompArray = SFH_GetArgumentSelect(jsonID, jsonPath, graph, SF_OP_PSX_KERNEL, 0) @@ -4367,6 +4681,8 @@ Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph decayTau = SFH_GetArgumentAsNumeric(jsonID, jsonPath, graph, SF_OP_PSX_KERNEL, 2, defValue = 15, checkFunc = IsStrictlyPositiveAndFinite) amp = SFH_GetArgumentAsNumeric(jsonID, jsonPath, graph, SF_OP_PSX_KERNEL, 3, defValue = -5, checkFunc = IsFinite) + SFH_ASSERT(decayTau > riseTau, "decay tau must be strictly larger than the rise tau") + SFH_ASSERT(DimSize(selectDataCompArray, ROWS) == 1, "Only supports a single selection at the moment") WAVE/WAVE selectDataComp = selectDataCompArray[0] @@ -4398,21 +4714,36 @@ Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph WAVE/WAVE result = PSX_GetPSXKernel(riseTau, decayTau, amp, numPoints, dt, range) + if(DimSize(result, ROWS) == 0) + continue + endif + Duplicate/FREE/T rawLabels, labels - labels[] = PSX_GenerateKey(rawLabels[p], i) - SetDimensionLabels(output, TextWaveToList(labels, ";"), ROWS, startPos = i * PSX_KERNEL_OUTPUTWAVES_PER_ENTRY) + labels[] = PSX_GenerateKey(rawLabels[p], idx) + SetDimensionLabels(output, TextWaveToList(labels, ";"), ROWS, startPos = idx * PSX_KERNEL_OUTPUTWAVES_PER_ENTRY) - key = PSX_GenerateKey("psxKernel", i) + key = PSX_GenerateKey("sweepData", idx) + output[%$key] = sweepData + key = PSX_GenerateKey("psxKernel", idx) output[%$key] = result[0] - key = PSX_GenerateKey("psxKernelFFT", i) + key = PSX_GenerateKey("psxKernelFFT", idx) output[%$key] = result[1] - key = PSX_GenerateKey("sweepData", i) - output[%$key] = sweepData + + idx += 1 endfor + numCombos = idx + + SFH_ASSERT(numCombos > 0, "Could not create psxKernel") + + Redimension/N=(PSX_KERNEL_OUTPUTWAVES_PER_ENTRY * numCombos) output + parameterPath = SF_META_USER_GROUP + PSX_JWN_PARAMETERS + "/" + SF_OP_PSX_KERNEL + + WAVE rangeClean = ZapNullRefs(range) + JWN_CreatePath(output, parameterPath) - JWN_SetWaveInWaveNote(output, parameterPath + "/range", range) // not the same as SF_META_RANGE + JWN_SetWaveInWaveNote(output, parameterPath + "/range", rangeClean) // not the same as SF_META_RANGE JWN_SetNumberInWaveNote(output, parameterPath + "/riseTau", riseTau) JWN_SetNumberInWaveNote(output, parameterPath + "/decayTau", decayTau) JWN_SetNumberInWaveNote(output, parameterPath + "/amp", amp) @@ -4424,15 +4755,16 @@ End Function/WAVE PSX_OperationRiseTime(variable jsonId, string jsonPath, string graph) - variable lowerThreshold, upperThreshold + variable lowerThreshold, upperThreshold, differentiateThreshold - SFH_CheckArgumentCount(jsonId, jsonPath, SF_OP_PSX_RISETIME, 0, maxArgs = 2) + SFH_CheckArgumentCount(jsonId, jsonPath, SF_OP_PSX_RISETIME, 0, maxArgs = 3) - lowerThreshold = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_RISETIME, 0, defValue = 20, checkFunc = BetweenZeroAndOneHoundredExc) - upperThreshold = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_RISETIME, 1, defValue = 80, checkFunc = BetweenZeroAndOneHoundredExc) + lowerThreshold = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_RISETIME, 0, defValue = 20, checkFunc = BetweenZeroAndOneHoundredExc) + upperThreshold = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_RISETIME, 1, defValue = 80, checkFunc = BetweenZeroAndOneHoundredExc) + differentiateThreshold = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_RISETIME, 2, defValue = 5, checkFunc = BetweenZeroAndOneHoundredExc) - Make/D/FREE thresholds = {lowerThreshold / ONE_TO_PERCENT, upperThreshold / ONE_TO_PERCENT} - SetDimensionLabels(thresholds, "Lower Threshold;Upper Threshold", ROWS) + Make/D/FREE thresholds = {lowerThreshold / ONE_TO_PERCENT, upperThreshold / ONE_TO_PERCENT, differentiateThreshold / ONE_TO_PERCENT} + SetDimensionLabels(thresholds, "Lower Threshold;Upper Threshold;Differentiate Threshold", ROWS) WAVE/WAVE output = SFH_CreateSFRefWave(graph, SF_OP_PSX_RISETIME, 1) @@ -4449,7 +4781,7 @@ Function/WAVE PSX_OperationDeconvFilter(variable jsonId, string jsonPath, string low = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_DECONV_FILTER, 0, defValue = NaN, checkFunc = IsNullOrPositiveAndFinite, checkDefault = 0) high = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_DECONV_FILTER, 1, defValue = NaN, checkFunc = IsNullOrPositiveAndFinite, checkDefault = 0) - order = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_DECONV_FILTER, 2, defValue = NaN, checkFunc = IsOdd, checkDefault = 0) + order = SFH_GetArgumentAsNumeric(jsonId, jsonPath, graph, SF_OP_PSX_DECONV_FILTER, 2, defValue = NaN, checkFunc = IsStrictlyPositiveAndFinite, checkDefault = 0) Make/D/FREE params = {low, high, order} SetDimensionLabels(params, "Filter Low;Filter High;Filter Order", ROWS) @@ -4461,6 +4793,21 @@ Function/WAVE PSX_OperationDeconvFilter(variable jsonId, string jsonPath, string return SFH_GetOutputForExecutor(output, graph, SF_OP_PSX_DECONV_FILTER) End +static Function/WAVE PSX_GetAllStatsProperties() + + Make/FREE/T allProps = {"amp", \ + "peak", "peaktime", \ + "deconvpeak", "deconvpeaktime", \ + "baseline", "baselinetime", \ + "xinterval", \ + "tau", \ + "estate", "fstate", "fitresult", \ + "slewrate", "slewratetime", \ + "risetime", "onsettime"} + + return allProps +End + Function/WAVE PSX_OperationStats(variable jsonId, string jsonPath, string graph) string stateAsStr, postProc, id, prop @@ -4477,7 +4824,7 @@ Function/WAVE PSX_OperationStats(variable jsonId, string jsonPath, string graph) WAVE/Z selectData = selectDataComp[%SELECTION] WAVE/WAVE range = selectDataComp[%RANGE] - Make/FREE/T allProps = {"amp", "xpos", "xinterval", "tau", "estate", "fstate", "fitresult", "risetime"} + WAVE allProps = PSX_GetAllStatsProperties() prop = SFH_GetArgumentAsText(jsonID, jsonPath, graph, SF_OP_PSX_STATS, 2, allowedValues = allProps) Make/FREE/T allStates = {"accept", "reject", "undetermined", "all", "every"} stateAsStr = SFH_GetArgumentAsText(jsonID, jsonPath, graph, SF_OP_PSX_STATS, 3, allowedValues = allStates) @@ -4548,16 +4895,16 @@ End static Function [WAVE hist, WAVE fit, variable peakThresh, string dataUnit] PSX_CalculatePeakThreshold(WAVE/WAVE results, variable numCombos, variable numSDs) // Concatenate all input waves - Make/FREE/N=(numCombos)/WAVE input = results[%$PSX_GenerateKey("sweepDataFiltOffDeconv", p)] - Concatenate/NP/FREE {input}, sweepDataFiltOffDeconv + Make/FREE/N=(numCombos)/WAVE input = results[%$PSX_GenerateKey("sweepDataOffFiltDeconv", p)] + Concatenate/NP/FREE {input}, sweepDataOffFiltDeconv - WAVE hist = PSX_CreateHistogramOfDeconvSweepData(sweepDataFiltOffDeconv) + WAVE hist = PSX_CreateHistogramOfDeconvSweepData(sweepDataOffFiltDeconv) [WAVE coef, WAVE fit] = PSX_FitHistogram(hist) if(WaveExists(coef) && WaveExists(fit)) - peakThresh = RoundNumber(coef[3] * numSDs, 3) - dataUnit = WaveUnits(sweepDataFiltOffDeconv, -1) + peakThresh = coef[3] * numSDs + dataUnit = WaveUnits(sweepDataOffFiltDeconv, -1) return [hist, fit, peakThresh, dataUnit] endif @@ -4572,7 +4919,7 @@ End Function PSX_MouseEventSelection(variable newState, variable stateType) string win, bottomLabel, bsPanel, browser - variable left, right, filtOffTop, filtOffBottom, filtOffDeconvTop, filtOffDeconvBottom, bottom, top + variable left, right, offFiltTop, offFiltBottom, offFiltDeconvTop, offFiltDeconvBottom, bottom, top variable numMatches, numEntries, i, needsUpdate, indexOrient [left, right] = GetMarqueeHelper("bottom", horiz = 1, doAssert = 1, win = win) @@ -4606,20 +4953,20 @@ Function PSX_MouseEventSelection(variable newState, variable stateType) endif // now check wether the y-coordinates of the events are inside for either axis - [filtOffBottom, filtOffTop] = GetMarqueeHelper("leftFiltOff", vert = 1, doAssert = 0) - [filtOffDeconvBottom, filtOffDeconvTop] = GetMarqueeHelper("leftFiltOffDeconv", vert = 1, doAssert = 0, kill = 1) + [offFiltBottom, offFiltTop] = GetMarqueeHelper("leftOffFilt", vert = 1, doAssert = 0) + [offFiltDeconvBottom, offFiltDeconvTop] = GetMarqueeHelper("leftOffFiltDeconv", vert = 1, doAssert = 0, kill = 1) - if(IsNaN(filtOffTop) || IsNaN(filtOffBottom) || IsNaN(filtOffDeconvTop) || IsNaN(filtOffDeconvBottom)) + if(IsNaN(offFiltTop) || IsNaN(offFiltBottom) || IsNaN(offFiltDeconvTop) || IsNaN(offFiltDeconvBottom)) return NaN endif Make/FREE/N=(numMatches) xCrds = peakX[matches[p]] - WAVE filtOffMatch = PSX_GetEventsInsideAxisRange(win, "sweepDataFiltOff", filtOffBottom, filtOffTop, xCrds) - WAVE filtOffDeconvMatch = PSX_GetEventsInsideAxisRange(win, "sweepDataFiltOffDeconv", filtOffDeconvBottom, filtOffDeconvTop, xCrds) + WAVE offFiltMatch = PSX_GetEventsInsideAxisRange(win, "sweepDataOffFilt", offFiltBottom, offFiltTop, xCrds) + WAVE offFiltDeconvMatch = PSX_GetEventsInsideAxisRange(win, "sweepDataOffFiltDeconv", offFiltDeconvBottom, offFiltDeconvTop, xCrds) Redimension/S matches - matches[] = (IsFinite(filtOffMatch[p]) || IsFinite(filtOffDeconvMatch[p])) ? matches[p] : NaN + matches[] = (IsFinite(offFiltMatch[p]) || IsFinite(offFiltDeconvMatch[p])) ? matches[p] : NaN WAVE/Z matchesClean = ZapNaNs(matches) @@ -5218,7 +5565,7 @@ Function PSX_PlotStartupSettings() End /// @brief Apply the macro `mac` onto the panel `win` -Function PSX_ApplyMacroToExistingPanel(string win, string mac) +static Function PSX_ApplyMacroToExistingPanel(string win, string mac) string line, currWindow @@ -5244,7 +5591,8 @@ Function PSX_ApplyMacroToExistingPanel(string win, string mac) macroCode[Inf] = "" currWindow = GetCurrentWindow() - SetActiveSubwindow $win + DoWindow/F $win + SetActiveSubwindow ## for(line : macroCode) if(IsEmpty(line)) diff --git a/Packages/MIES/MIES_SweepFormula_PSX_Macro.ipf b/Packages/MIES/MIES_SweepFormula_PSX_Macro.ipf index 30d2cd5c39..8afc551a11 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX_Macro.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX_Macro.ipf @@ -126,7 +126,7 @@ Window PSXPanel() : Panel PopupMenu popup_block, mode=1, popvalue="", value=#"\"\"" PopupMenu popupmenu_event_offset, pos={136.00, 168.00}, size={53.00, 19.00}, proc=PSX_PopupMenuState PopupMenu popupmenu_event_offset, help={"Select the time point in x direction for aligning the single event traces in the all event graph"} - PopupMenu popupmenu_event_offset, mode=1, popvalue="Onset", value=#"\"Onset;Peak\"" + PopupMenu popupmenu_event_offset, mode=1, popvalue="Onset", value=#"\"Onset;Peak;Slew\"" DefineGuide leftMenu={FL, 0.2, FR}, horizCenter={leftMenu, 0.5, FR} SetWindow kwTopWin, hook(resetScaling)=IH_ResetScaling SetWindow kwTopWin, hook(ctrl)=PSX_AllEventGraphHook diff --git a/Packages/MIES/MIES_Utilities_GUI.ipf b/Packages/MIES/MIES_Utilities_GUI.ipf index 0e3714a646..d7bbcab752 100644 --- a/Packages/MIES/MIES_Utilities_GUI.ipf +++ b/Packages/MIES/MIES_Utilities_GUI.ipf @@ -725,3 +725,27 @@ Function EqualizeCheckBoxes(string win, string checkBoxIn, string checkBoxPartne SetCheckBoxState(win, checkBoxPartner, checkBoxInState) DAG_Update(win, checkBoxPartner, val = checkBoxInState) End + +Function RemoveAllControls(string win) + + string control + + WAVE/T controls = ListToTextWave(ControlNameList(win), ";") + for(control : controls) + KillControl/W=$win $control + endfor +End + +Function RemoveAllDrawLayers(string win) + + SetDrawLayer/W=$win/K ProgBack + SetDrawLayer/W=$win/K UserBack + SetDrawLayer/W=$win/K ProgFront + SetDrawLayer/W=$win/K UserFront + SetDrawLayer/W=$win/K Overlay + + if(WinType(win) == WINTYPE_GRAPH) + SetDrawLayer/W=$win/K ProgAxes + SetDrawLayer/W=$win/K UserAxes + endif +End diff --git a/Packages/MIES/MIES_Utilities_WaveHandling.ipf b/Packages/MIES/MIES_Utilities_WaveHandling.ipf index f34d05100f..e220801862 100644 --- a/Packages/MIES/MIES_Utilities_WaveHandling.ipf +++ b/Packages/MIES/MIES_Utilities_WaveHandling.ipf @@ -509,7 +509,7 @@ End /// @brief Return a wave with deep copies of all referenced waves /// /// The deep copied waves will be free waves. -/// Does not allow invalid wave references in `src`. +/// Does allow invalid wave references in `src`. /// /// @param src wave reference wave /// @param dimension [optional] copy only a single dimension, requires `index` or @@ -544,15 +544,18 @@ threadsafe Function/WAVE DeepCopyWaveRefWave(WAVE/WAVE src, [variable dimension, for(i = 0; i < numEntries; i += 1) WAVE/Z srcWave = dst[i] - ASSERT_TS(WaveExists(srcWave), "Missing wave at linear index" + num2str(i)) - if(!ParamIsDefault(indexWave)) - index = indexWave[i] + if(!WaveExists(srcWave)) + continue endif if(ParamIsDefault(dimension)) Duplicate/FREE srcWave, dstWave else + if(!ParamIsDefault(indexWave)) + index = indexWave[i] + endif + switch(dimension) case ROWS: Duplicate/FREE/R=[index][][][] srcWave, dstWave @@ -567,6 +570,7 @@ threadsafe Function/WAVE DeepCopyWaveRefWave(WAVE/WAVE src, [variable dimension, Duplicate/FREE/R=[][][][index] srcWave, dstWave break endswitch + ReduceWaveDimensionality(dstWave, minDimension = dimension) endif diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index 4ef248ae38..24aa398c09 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -8191,18 +8191,30 @@ End /// @name SweepFormula PSX ///@{ -static Constant PSX_WAVE_VERSION = 2 -static Constant PSX_EVENT_WAVE_COLUMNS = 14 +static Constant PSX_WAVE_VERSION = 3 +static Constant PSX_EVENT_WAVE_COLUMNS = 17 -Function UpgradePSXEventWave(WAVE psxEvent) +/// @brief Return the upgraded psxEvent wave +Function/WAVE UpgradePSXEventWave(WAVE psxEvent) if(WaveVersionIsAtLeast(psxEvent, PSX_WAVE_VERSION)) - // latest version + return psxEvent + elseif(WaveVersionIsAtLeast(psxEvent, 2)) + + if(!AlreadyCalledOnce(CO_PSX_UPGRADE_EVENT)) + print "The algorithm for psp/psc event detection was heavily overhauled, therefore we are very sorry " \ + + "to say that we can't upgrade your existing data." + ControlWindowToFront() + endif + + return $"" elseif(WaveVersionIsAtLeast(psxEvent, 1)) SetPSXEventDimensionLabels(psxEvent) else ASSERT(0, "Missing upgrade path") endif + + return psxEvent End /// @brief Return a 2D events wave as free wave @@ -8211,22 +8223,29 @@ End /// - count /// /// Cols: -/// - 0/index: Event index -/// - 1/peak_t: Event time [ms] -/// - 2/peak: Event amplitude in deconvoluted data [y unit of data] -/// - 3/post_min: Minimum of filtered and offsetted data in the range [time, time + 2ms] -/// - 4/post_min_t: X location of [2] -/// - 5/pre_max: Maximum of filtered and offsetted data in the range [time - 2ms, time], averaged over +/- 0.1 ms -/// - 6/pre_max_t: X location of [5] -/// - 7/rel_peak: Relative amplitude: [2] - [4] -/// - 8/isi: Time difference to previous event [ms] +/// - 0/index: event index +/// - 1/deconvPeak: event amplitude in deconvoluted data [y unit of data] +/// - 2/deconvPeak_t: deconvolved peak time [ms] +/// - 3/peak: Maximum (positive kernel amp sign) or minimum (negative kernel amp sign) in the range of +/// [deconvPeak_t – kernelRiseTau or devonvPeak_t of the previous event (whichever comes later), +/// deconvPeak_t + 0.33 * kernelDecayTau or deconvPeak_t of the next event (which ever comes first)] +/// in the filtered sweep wave +/// - 4/peak_t: peak time +/// - 5/baseline: Maximum (negative kernel amp sign) or minimum (positive kernel amp sign) in the range of +/// [peak_t – 10 * kernelRiseTau, peak_t], averaged over +/- 5 points, in the filtered sweep wave +/// - 6/baseline_t: baseline time +/// - 7/amplitude: Relative amplitude: [3] - [5] +/// - 8/iei: Time difference to previous event (inter event interval) [ms] /// - 9/tau: Decay constant tau of exponential fit /// - 10/Fit manual QC call: One of @ref PSXStates /// - 11/Fit result: 1 for success, everything smaller than 0 is failure: -/// - `]-10000, 0[`: CurveFit error codes -/// - `]inf, -10000]`: Custom error codes, one of @ref FitEventDecayCustomErrors +/// - `]-10000, 0[`: CurveFit error codes +/// - `]-inf, -10000]`: Custom error codes, one of @ref FitEventDecayCustomErrors /// - 12/Event manual QC call: One of @ref PSXStates -/// - 13/Rise Time: rise time as calculated by PSX_CalculateRiseTime() +/// - 13/Onset time as calculated by PSX_CalculateOnsetTime +/// - 14/Rise Time as calculated by PSX_CalculateRiseTime +/// - 15/Slew Rate +/// - 16/Slew Rate Time Function/WAVE GetPSXEventWaveAsFree() variable versionOfWave = PSX_WAVE_VERSION @@ -8240,22 +8259,25 @@ Function/WAVE GetPSXEventWaveAsFree() return wv End -Function SetPSXEventDimensionLabels(WAVE wv) +static Function SetPSXEventDimensionLabels(WAVE wv) SetDimLabel COLS, 0, index, wv - SetDimLabel COLS, 1, peak_t, wv - SetDimLabel COLS, 2, peak, wv - SetDimLabel COLS, 3, post_min, wv - SetDimLabel COLS, 4, post_min_t, wv - SetDimLabel COLS, 5, pre_max, wv - SetDimLabel COLS, 6, pre_max_t, wv - SetDimLabel COLS, 7, rel_peak, wv - SetDimLabel COLS, 8, isi, wv + SetDimLabel COLS, 1, deconvPeak, wv + SetDimLabel COLS, 2, deconvPeak_t, wv + SetDimLabel COLS, 3, peak, wv + SetDimLabel COLS, 4, peak_t, wv + SetDimLabel COLS, 5, baseline, wv + SetDimLabel COLS, 6, baseline_t, wv + SetDimLabel COLS, 7, amplitude, wv + SetDimLabel COLS, 8, iei, wv SetDimLabel COLS, 9, tau, wv SetDimLabel COLS, 10, $"Fit manual QC call", wv SetDimLabel COLS, 11, $"Fit result", wv SetDimLabel COLS, 12, $"Event manual QC call", wv - SetDimLabel COLS, 13, $"Rise Time", wv + SetDimLabel COLS, 13, $"Onset Time", wv + SetDimLabel COLS, 14, $"Rise Time", wv + SetDimLabel COLS, 15, $"Slew Rate", wv + SetDimLabel COLS, 16, $"Slew Rate Time", wv End Function/WAVE GetPSXSingleEventFitWaveFromDFR(DFREF dfr) @@ -8347,14 +8369,14 @@ Function/WAVE GetPSXSweepDataWaveFromDFR(DFREF dfr) return GetWaveFromFolder(dfr, "sweepData") End -Function/WAVE GetPSXSweepDataFiltOffWaveFromDFR(DFREF dfr) +Function/WAVE GetPSXSweepDataOffFiltWaveFromDFR(DFREF dfr) - return GetWaveFromFolder(dfr, "sweepDataFiltOff") + return GetWaveFromFolder(dfr, "sweepDataOffFilt") End -Function/WAVE GetPSXSweepDataFiltOffDeconvWaveFromDFR(DFREF dfr) +Function/WAVE GetPSXSweepDataOffFiltDeconvWaveFromDFR(DFREF dfr) - return GetWaveFromFolder(dfr, "sweepDataFiltOffDeconv") + return GetWaveFromFolder(dfr, "sweepDataOffFiltDeconv") End Function/WAVE GetPSXEventLocationLabels(DFREF dfr) diff --git a/Packages/MIES/SweepFormulaHelp.ifn b/Packages/MIES/SweepFormulaHelp.ifn index 7c5f49404f..857d84e64a 100644 Binary files a/Packages/MIES/SweepFormulaHelp.ifn and b/Packages/MIES/SweepFormulaHelp.ifn differ diff --git a/Packages/doc/SweepFormula.rst b/Packages/doc/SweepFormula.rst index bcef4a7f25..59116b9884 100644 --- a/Packages/doc/SweepFormula.rst +++ b/Packages/doc/SweepFormula.rst @@ -1368,9 +1368,10 @@ numberOfSDs psxRiseTime """"""""""" -The `psxRiseTime` operation is a helper operation for `psx` to manage the lower and upper thresholds for the rise time calculation. +The `psxRiseTime` operation is a helper operation for `psx` to manage the lower and upper thresholds for the rise time calculation +and the differential threshold for the onset time calculcation. - psxRiseTime([lowerThreshold, upperThreshold]) + psxRiseTime([lowerThreshold, upperThreshold, diffThreshold]) The function accepts zero to two arguments. @@ -1380,15 +1381,20 @@ lowerThreshold upperThreshold defaults to 80% +diffThreshold + defaults to 5% + .. code-block:: bash psxRiseTime(0.5) psxRiseTime(0.5, 0.9) + psxRiseTime(0.5, 0.9, 0.15) psxDeconvFilter """"""""""""""" The `psxDeconvFilter` operation is a helper operation for `psx` to manage the deconvolution filter settings. +This filter is a bandpass filter. psxDeconvFilter([lowFreq, highFreq, order]) @@ -1404,21 +1410,21 @@ order defaults to `NaN` The default values of `NaN` are replaced inside `psx`. For the order this is -`101`, for the frequencies this is a normalized frequency which depends on the -sampling interval of the data. Here `lowFreq` is the end of the passband and -`highFreq` the start of the reject band see also the description of `/LO` from -`FilterFIR`. +`7`, for the frequencies `500` (`lowFreq`) and `50` (`highFreq`). +Here `lowFreq` is the end and `highFreq` the start of the +passband, see also the description of `/LO` and `/HI` from `FilterIIR`. .. code-block:: bash - psxDeconvFilter(500, 1000) - psxDeconvFilter(400, 600, 91) + psxDeconvFilter(800, 100) + psxDeconvFilter(400, 50, 11) psxstats """""""" Plot properties of the result waves of a miniature PSC/PSP classification. The -operation combines the data from all input sweeps. +operation combines the data from all input sweeps. Also all ranges for each +sweep are combined. The operation allows to visualize `psx` data from the results wave or locally, i.e. from an `psx` operation from another formula separated by `and`. The @@ -1443,7 +1449,8 @@ select prop column of the `psx` event results waves to plot. - Choices are: `amp`, `xpos`, `xinterval`, `tau`, `estate`, `fstate`, `fitresult`, `risetime` + Choices are: `amp`, `peak`, `peaktime`, `deconvpeak`, `deconvpeaktime`, `baseline`, `baselinetime`, `xinterval`, + `tau`, `estate`, `fstate`, `fitresult`, `slewrate`, `slewratetime`, `risetime`, `onsettime` state QC state to select the events. @@ -1451,8 +1458,8 @@ state The used QC state depends on `prop`: - - Event state QC -> `amp`/`xpos`/`xinterval`/`estate`/`risetime` - Fit state QC -> `tau`/`fstate`/`fitresult` + - Event state QC for everything else The difference between `all` and `every` is that `all` plots the events from all possible states in **one** trace whereas `every` creates **multiple** diff --git a/Packages/doc/SweepFormula_PSX.rst b/Packages/doc/SweepFormula_PSX.rst index 140c75d691..c0b1773cb6 100644 --- a/Packages/doc/SweepFormula_PSX.rst +++ b/Packages/doc/SweepFormula_PSX.rst @@ -4,6 +4,37 @@ SweepFormula PSC/PSP classification =================================== +Algorithm +^^^^^^^^^ + +The algorithm for finding psc/psp events can be summarized as follows: + +- The deconvolution kernel is created by the `psxKernel` operation using the rise/decay tau and an amplitude +- Sweep data is zeroed, filtered using a bandpass filter and then deconvoluted with the kernel +- With the number of standard deviations passed to `psx` we then calculate the peak threshold in the + deconvoluted data +- This peak threshold is then used to find the events in the deconvoluted data this gives `deconvPeak` and + `deoconvPeak_t` +- Throw away events which have an amplitude with different sign as the kernel amplitude +- Calculate `peak` and `peak_t` via taking the maximum (positive kernel amp sign) or minimum (negative kernel + amp sign) in the range of `[deconvPeak_t – kernelRiseTau or devonvPeak_t of the previous event (whichever + comes later), deconvPeak_t + 0.33 * kernelDecayTau or deconvPeak_t of the next event (which ever comes + first)]` in the filtered sweep wave +- Calculate `baseline` and `baseline_t` via maximum (negative kernel amp sign) or minimum (positive kernel amp + sign) in the range of `[peak_t – 10 * kernelRiseTau, peak_t]`, averaged over +/- 5 points, in the filtered + sweep wave +- `iei` is the time difference between two events' `peak_t` values +- `tau` and the fit result values are calculated from an exponential fit +- Calculate `Slew Rate` and `Slew Rate Time` via taking the maximum (positive kernel amp sign) or minimum (negative kernel + amp sign) in the range of `[peak_t, baseline_t]` +- Calculate `Onset Time` using the y level crossing at differential threshold percentage from `psxRiseTime` of + the difference between the `Slew Rate` and filteered sweep data at `baseline_t` +- Calculate `Rise Time` by finding the two level crossings, lower and upper thresholds from `psxRiseTime` in + the range `Onset Time` to `peak_t` corrected by invertred kernel amplitude sign + +GUI +^^^ + When using the :ref:`sf_op_psx` SweepFormula operation the normal graphing is enhanced by various additional graphs and user interface options. The following graph shows the layout for a `psx` and `psxStats` operation with @@ -144,7 +175,7 @@ the selection, either fit or event state, is determined by the popup menu. combination (checked) or use all of them (unchecked) - ``Fit State/Event State``: Select the state to use as basis for selection - ``dblexp_peak/dblexp_XOffset``: Select the fit curve for the average fit -- ``Onset/peak``: Select the event property to offset the events in the all +- ``Onset/Peak/Slew``: Select the event property to offset the events in the all events graph to - ``Block size [%]``: Percentage to select what part of the events are displayed in the all events graph. This can help with reducing the number of diff --git a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index bb73912a07..1431cbb447 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -464,23 +464,212 @@ static Function StatsComplainsWithoutEvents() endtry End +static Function StatsRangeTesting() + + string formulaGraph, browser, device, result, stateAsStr, postProc, prop + string error, id, comboKeyA, comboKeyB, comboKeyC, comboKeyD, ref, key, keyTxt + variable numComboKeys + + [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() + + // events A + [WAVE rangeA, WAVE selectDataA] = GetFakeRangeAndSelectData() + selectDataA[0][%CHANNELNUMBER] = 0 + + WAVE psxEventA = GetPSXEventWaveAsFree() + Redimension/N=(10, -1) psxEventA + + comboKeyA = MIES_PSX#PSX_GenerateComboKey(browser, selectDataA, rangeA) + sprintf ref, "Range[100, 200], Sweep [1], Channel [AD0], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + CHECK_EQUAL_STR(comboKeyA, ref) + + id = "myID" + FillEventWave_IGNORE(psxEventA, id, comboKeyA) + + // events B + [WAVE rangeB, WAVE selectDataB] = GetFakeRangeAndSelectData() + rangeB = {101, 201} + selectDataB[0][%SWEEP] = 2 + selectDataB[0][%CHANNELNUMBER] = 0 + + comboKeyB = MIES_PSX#PSX_GenerateComboKey(browser, selectDataB, rangeB) + sprintf ref, "Range[101, 201], Sweep [2], Channel [AD0], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + CHECK_EQUAL_STR(comboKeyB, ref) + + WAVE psxEventB = GetPSXEventWaveAsFree() + Redimension/N=(10, -1) psxEventB + + id = "myID" + FillEventWave_IGNORE(psxEventB, id, comboKeyB) + + // events C + [key, keyTxt] = PrepareLBN_IGNORE(device) + Duplicate/FREE selectDataB, selectDataC + Make/T/FREE rangeC = {"E0"} + selectDataC[0][%SWEEP] = 3 + selectDataC[0][%CHANNELNUMBER] = 0 + + comboKeyC = MIES_PSX#PSX_GenerateComboKey(browser, selectDataC, rangeC) + sprintf ref, "Range[E0], Sweep [3], Channel [AD0], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + CHECK_EQUAL_STR(comboKeyC, ref) + + Make/FREE/T/N=(3, 1, 1) epochKeys + epochKeys[0][0][0] = EPOCHS_ENTRY_KEY + epochKeys[2][0][0] = LABNOTEBOOK_NO_TOLERANCE + + WAVE/T epochsWave = GetEpochsWave(device) + variable DAC = 2 + epochsWave[0][EPOCH_COL_STARTTIME][DAC][XOP_CHANNEL_TYPE_DAC] = "102" + epochsWave[0][EPOCH_COL_ENDTIME][DAC][XOP_CHANNEL_TYPE_DAC] = "151" + epochsWave[0][EPOCH_COL_TAGS][DAC][XOP_CHANNEL_TYPE_DAC] = "ShortName=E0;stuff" + epochsWave[0][EPOCH_COL_TREELEVEL][DAC][XOP_CHANNEL_TYPE_DAC] = "0" + + epochsWave[1][EPOCH_COL_STARTTIME][DAC][XOP_CHANNEL_TYPE_DAC] = "152" + epochsWave[1][EPOCH_COL_ENDTIME][DAC][XOP_CHANNEL_TYPE_DAC] = "202" + epochsWave[1][EPOCH_COL_TAGS][DAC][XOP_CHANNEL_TYPE_DAC] = "ShortName=E1;nothing" + epochsWave[1][EPOCH_COL_TREELEVEL][DAC][XOP_CHANNEL_TYPE_DAC] = "1" + + Make/FREE/T/N=(1, 1, LABNOTEBOOK_LAYER_COUNT) epochInfo = EP_EpochWaveToStr(epochsWave, DAC, XOP_CHANNEL_TYPE_DAC) + ED_AddEntriesToLabnotebook(epochInfo, epochKeys, selectDataC[0][%SWEEP], device, DATA_ACQUISITION_MODE) + + Make/T/FREE rangeD = {"E0"} + selectDataC[0][%SWEEP] = 3 + selectDataC[0][%CHANNELNUMBER] = 0 + + WAVE psxEventC = GetPSXEventWaveAsFree() + Redimension/N=(10, -1) psxEventC + + id = "myID" + FillEventWave_IGNORE(psxEventC, id, comboKeyC) + + // events D + Duplicate/FREE selectDataC, selectDataD + Make/T/FREE rangeD = {"E1"} + + comboKeyD = MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeD) + sprintf ref, "Range[E1], Sweep [3], Channel [AD0], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + CHECK_EQUAL_STR(comboKeyD, ref) + + WAVE psxEventD = GetPSXEventWaveAsFree() + Redimension/N=(10, -1) psxEventD + + id = "myID" + FillEventWave_IGNORE(psxEventD, id, comboKeyD) + + Make/FREE/WAVE psxEventContainer = {psxEventA, psxEventB, psxEventC, psxEventD} + MIES_PSX#PSX_StoreIntoResultsWave(browser, SFH_RESULT_TYPE_PSX_EVENTS, psxEventContainer, id) + + prop = "tau" + stateAsStr = MIES_PSX#PSX_StateToString(PSX_ACCEPT) + postProc = "nothing" + + // non-matching range number with sweeps + try + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeA, rangeB}, selectDataA, prop, stateAsStr, postProc) + FAIL() + catch + error = ROStr(GetSweepFormulaParseErrorMessage()) + CHECK_EQUAL_STR(error, "The number of sweeps and ranges differ") + endtry + + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeA}, selectDataA, prop, stateAsStr, postProc) + CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) + numComboKeys = 3 + CHECK_EQUAL_VAR(DimSize(results[0], ROWS), numComboKeys) + + Make/T/FREE comboKeysRef = {MIES_PSX#PSX_GenerateComboKey(browser, selectDataA, rangeA), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataA, rangeA), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataA, rangeA)} + WAVE/T comboKeys = JWN_GetTextWaveFromWaveNote(results[0], SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME) + CHECK_EQUAL_TEXTWAVES(comboKeys, comboKeysRef) + + // different range for each sweep + Concatenate/NP=(ROWS)/FREE {selectDataA, selectDataB}, selectData + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeA, rangeB}, selectData, prop, stateAsStr, postProc) + CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) + // -> twice as many events + numComboKeys = 6 + CHECK_EQUAL_VAR(DimSize(results[0], ROWS), 6) + + Make/T/FREE comboKeysRef = {MIES_PSX#PSX_GenerateComboKey(browser, selectDataA, rangeA), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataA, rangeA), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataA, rangeA), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataB, rangeB), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataB, rangeB), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataB, rangeB)} + WAVE/T comboKeys = JWN_GetTextWaveFromWaveNote(results[0], SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME) + CHECK_EQUAL_TEXTWAVES(comboKeys, comboKeysRef) + + // epoch name + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeC}, selectDataC, prop, stateAsStr, postProc) + CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) + numComboKeys = 3 + CHECK_EQUAL_VAR(DimSize(results[0], ROWS), numComboKeys) + + Make/T/FREE comboKeysRef = {MIES_PSX#PSX_GenerateComboKey(browser, selectDataC, rangeC), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataC, rangeC), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataC, rangeC)} + WAVE/T comboKeys = JWN_GetTextWaveFromWaveNote(results[0], SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME) + CHECK_EQUAL_TEXTWAVES(comboKeys, comboKeysRef) + + // multiple epoch names + Make/FREE/T rangeEpoch0 = {"E0"} + Make/FREE/T rangeEpoch1 = {"E1"} + Make/FREE/T rangeEpochs = {rangeEpoch0[0], rangeEpoch1[0]} + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeEpochs}, selectDataD, prop, stateAsStr, postProc) + CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) + numComboKeys = 6 + CHECK_EQUAL_VAR(DimSize(results[0], ROWS), numComboKeys) + + Make/T/FREE comboKeysRef = {MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch0), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch0), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch0), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch1), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch1), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch1)} + WAVE/T comboKeys = JWN_GetTextWaveFromWaveNote(results[0], SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME) + CHECK_EQUAL_TEXTWAVES(comboKeys, comboKeysRef) + + // epoch wildcards + Make/FREE/T rangeEpochs = {"E*"} + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeEpochs}, selectDataD, prop, stateAsStr, postProc) + CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) + numComboKeys = 6 + CHECK_EQUAL_VAR(DimSize(results[0], ROWS), numComboKeys) + + Make/T/FREE comboKeysRef = {MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch0), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch0), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch0), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch1), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch1), \ + MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeEpoch1)} + WAVE/T comboKeys = JWN_GetTextWaveFromWaveNote(results[0], SF_META_USER_GROUP + PSX_JWN_COMBO_KEYS_NAME) + CHECK_EQUAL_TEXTWAVES(comboKeys, comboKeysRef) +End + static Function FillEventWave_IGNORE(WAVE psxEvent, string id, string comboKey) variable jsonID - CHECK_EQUAL_VAR(DimSize(psxEvent, COLS), 14) // test needs update if that fails - - psxEvent[][%index] = p - psxEvent[][%peak_t] = 100 * p - psxEvent[][%peak] = NaN - psxEvent[][%post_min] = NaN - psxEvent[][%post_min_t] = -10 * p - psxEvent[][%pre_max] = NaN - psxEvent[][%pre_max_t] = NaN - psxEvent[][%rel_peak] = p == 0 ? NaN : 10 * p - psxEvent[][%isi] = 1000 * p - psxEvent[][%tau] = 1e-6 * p - psxEvent[][%$"Rise Time"] = p == 0 ? NaN : 0.1 * p + INFO("Check that the size of psxEvent is what we expect") + + CHECK_EQUAL_VAR(DimSize(psxEvent, COLS), 17) + + psxEvent[][%index] = p + psxEvent[][%deconvpeak_t] = 100 * p + psxEvent[][%deconvpeak] = NaN + psxEvent[][%peak] = NaN + psxEvent[][%peak_t] = 10 * p + psxEvent[][%baseline] = NaN + psxEvent[][%baseline_t] = NaN + psxEvent[][%amplitude] = p == 0 ? NaN : 10 * p + psxEvent[][%iei] = 1000 * p + psxEvent[][%tau] = 1e-6 * p + psxEvent[][%$"Rise Time"] = p == 0 ? NaN : 0.1 * p + psxEvent[][%$"Onset Time"] = p == 0 ? NaN : 0.2 * p + psxEvent[][%$"Slew Rate"] = NaN + psxEvent[][%$"Slew Rate Time"] = p == 0 ? NaN : 200 * p + // PSX_ACCEPT:1 // PSX_REJECT:2 // PSX_UNDET: 4 @@ -583,7 +772,7 @@ Function/WAVE StatsTest_GetInput() Duplicate/FREE/T template, wv6 WAVE/T input = wv6 - input[%prop] = "xpos" + input[%prop] = "peaktime" input[%state] = "undetermined" input[%postProc] = "hist" @@ -599,7 +788,8 @@ Function/WAVE StatsTest_GetInput() input[%state] = "undetermined" input[%postProc] = "log10" - JWN_SetWaveInWaveNote(input, "/results", {NaN, log(600 - 200), log(900 - 600)}) + Make/FREE/D result = {NaN, log(60 - 20), log(90 - 60)} + JWN_SetWaveInWaveNote(input, "/results", result) JWN_SetWaveInWaveNote(input, "/xValues", {2, 6, 9}) JWN_SetWaveInWaveNote(input, "/marker", {PSX_MARKER_UNDET, PSX_MARKER_UNDET, PSX_MARKER_UNDET}) @@ -615,7 +805,7 @@ Function/WAVE StatsTest_GetInput() JWN_SetWaveInWaveNote(input, "/xValues", {1, 3, 5, 7, 9}) JWN_SetWaveInWaveNote(input, "/marker", {PSX_MARKER_UNDET, PSX_MARKER_UNDET, PSX_MARKER_UNDET, PSX_MARKER_UNDET, PSX_MARKER_UNDET}) - // wv8 + // wv9 Duplicate/FREE/T template, wv9 WAVE/T input = wv9 @@ -631,7 +821,7 @@ Function/WAVE StatsTest_GetInput() Duplicate/FREE/T template, wv10 WAVE/T input = wv10 - input[%prop] = "xpos" + input[%prop] = "peaktime" input[%state] = "all" input[%postProc] = "nonfinite" @@ -907,7 +1097,7 @@ Function/WAVE StatsTestSpecialCases_GetInput() input[%outOfRange] = "0" JWN_CreatePath(input, "/0") - JWN_SetWaveInWaveNote(input, "/0/results", {NaN, 200, NaN, 200}) + JWN_SetWaveInWaveNote(input, "/0/results", {NaN, 20, NaN, 20}) JWN_SetWaveInWaveNote(input, "/0/xValues", {1, 3, 1, 3}) JWN_SetWaveInWaveNote(input, "/0/marker", {PSX_MARKER_ACCEPT, PSX_MARKER_ACCEPT, PSX_MARKER_ACCEPT, PSX_MARKER_ACCEPT}) @@ -1018,7 +1208,7 @@ End static Function StatsComplainsAboutIntersectingRanges() - string browser, device, formulaGraph, comboKey, id + string browser, device, formulaGraph, comboKey, id, error [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() @@ -1032,6 +1222,8 @@ static Function StatsComplainsAboutIntersectingRanges() Duplicate/FREE range0, range1 + Concatenate/FREE/NP=(COLS) {range0, range1}, ranges + // 2nd event wave where we shift the range WAVE/Z psxEvent = CreateEventWaveInComboFolder_IGNORE(comboIndex = 1) range1[] += 0.5 * (range0[1] - range0[0]) @@ -1040,13 +1232,45 @@ static Function StatsComplainsAboutIntersectingRanges() FillEventWave_IGNORE(psxEvent, id, comboKey) try - MIES_PSX#PSX_OperationStatsImpl(browser, id, {range0, range1}, selectData, "amp", "all", "nothing") + MIES_PSX#PSX_OperationStatsImpl(browser, id, {ranges}, selectData, "amp", "all", "nothing") FAIL() catch - CHECK_NO_RTE() + error = ROStr(GetSweepFormulaParseErrorMessage()) + CHECK_EQUAL_STR(error, "Can't work with multiple intersecting ranges") endtry End +static Function/WAVE GetAllStatsProperties() + + WAVE wv = MIES_PSX#PSX_GetAllStatsProperties() + CHECK_WAVE(wv, TEXT_WAVE) + + SetDimensionLabelsFromWaveContents(wv) + + return wv +End + +/// IUTF_TD_GENERATOR s0:GetAllStatsProperties +static Function StatsAllProperties([STRUCT IUTF_mData &m]) + + string browser, device, formulaGraph, comboKey, id, error, prop + + prop = m.s0 + + [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() + + [WAVE range, WAVE selectData] = GetFakeRangeAndSelectData() + + // 1st event wave + WAVE/Z psxEvent = GetEventWave(comboIndex = 0) + comboKey = MIES_PSX#PSX_GenerateComboKey(browser, selectData, range) + id = "myID" + FillEventWave_IGNORE(psxEvent, id, comboKey) + + MIES_PSX#PSX_OperationStatsImpl(browser, id, {range}, selectData, prop, "all", "nothing") + CHECK_NO_RTE() +End + Function/WAVE FakeSweepDataGeneratorPSXKernel(WAVE sweep, variable numChannels) variable pnts = 1001 @@ -1103,6 +1327,29 @@ static Function TestOperationPSXKernel() CheckDimensionScaleHelper(dataWref[4], 0, 0.01) CheckDimensionScaleHelper(dataWref[5], 50, 0.2) + // three waves from first range, none from second + Make/FREE/T/N=(3, 1, 1) epochKeys + epochKeys[0][0][0] = EPOCHS_ENTRY_KEY + epochKeys[2][0][0] = LABNOTEBOOK_NO_TOLERANCE + + WAVE/T epochsWave = GetEpochsWave(device) + variable DAC = 2 + epochsWave[0][EPOCH_COL_STARTTIME][DAC][XOP_CHANNEL_TYPE_DAC] = "0.050" + epochsWave[0][EPOCH_COL_ENDTIME][DAC][XOP_CHANNEL_TYPE_DAC] = "0.150" + epochsWave[0][EPOCH_COL_TAGS][DAC][XOP_CHANNEL_TYPE_DAC] = "ShortName=E0;stuff" + epochsWave[0][EPOCH_COL_TREELEVEL][DAC][XOP_CHANNEL_TYPE_DAC] = "0" + + Make/FREE/T/N=(1, 1, LABNOTEBOOK_LAYER_COUNT) epochInfo = EP_EpochWaveToStr(epochsWave, DAC, XOP_CHANNEL_TYPE_DAC) + ED_AddEntriesToLabnotebook(epochInfo, epochKeys, 0, device, DATA_ACQUISITION_MODE) + + str = "psxKernel(select(selrange([E0]), selchannels(AD6), selsweeps([0]), selvis(all)), 1, 15, -5)" + WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) + CHECK_WAVE(dataWref, WAVE_WAVE) + CHECK_EQUAL_VAR(DimSize(dataWref, ROWS), 3) + + WAVE/Z/T range = JWN_GetTextWaveFromWaveNote(dataWref[2], "/Range") + CHECK_EQUAL_TEXTWAVES(range, {"E0"}, mode = WAVE_DATA) + // no data from select statement str = "psxKernel(select(selrange([50, 150]), selchannels(AD15), selsweeps(0)), 1, 15, -5)" try @@ -1120,6 +1367,15 @@ static Function TestOperationPSXKernel() catch PASS() endtry + + // too large decayTau + str = "psxKernel([50, 150], select(selchannels(AD15), selsweeps([0])), 1, 150, -5)" + try + WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) + FAIL() + catch + PASS() + endtry End static Function CheckDimensionScaleHelper(WAVE wv, variable refOffset, variable refPerPoint) @@ -1157,9 +1413,10 @@ End static Function TestOperationPSX([STRUCT IUTF_mData &m]) string win, device, str, comboKey - variable jsonID, kernelAmp + variable jsonID, kernelAmp, kernelAmpSign - kernelAmp = m.v0 + kernelAmp = m.v0 + kernelAmpSign = sign(kernelAmp) Make/FREE/T/N=2 combos @@ -1172,7 +1429,9 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) // all decay fits are successfull - overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 [win, device] = CreateEmptyUnlockedDataBrowserWindow() @@ -1186,11 +1445,11 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) // check dimension labels Make/FREE=1/N=14/T dimlabels = GetDimLabel(dataWref, ROWS, p) - CHECK_EQUAL_TEXTWAVES(dimlabels, {"sweepData_0", "sweepDataFiltOff_0", "sweepDataFiltOffDeconv_0", "peakX_0", "peakY_0", "psxEvent_0", "eventFit_0", \ - "sweepData_1", "sweepDataFiltOff_1", "sweepDataFiltOffDeconv_1", "peakX_1", "peakY_1", "psxEvent_1", "eventFit_1"}) + CHECK_EQUAL_TEXTWAVES(dimlabels, {"sweepData_0", "sweepDataOffFilt_0", "sweepDataOffFiltDeconv_0", "peakX_0", "peakY_0", "psxEvent_0", "eventFit_0", \ + "sweepData_1", "sweepDataOffFilt_1", "sweepDataOffFiltDeconv_1", "peakX_1", "peakY_1", "psxEvent_1", "eventFit_1"}) - CheckEventDataHelper(dataWref, 0) - CheckEventDataHelper(dataWref, 1) + CheckEventDataHelper(dataWref, 0, kernelAmpSign) + CheckEventDataHelper(dataWref, 1, kernelAmpSign) // check that we have parameters in the JSON wave note jsonID = JWN_GetWaveNoteAsJSON(dataWref) @@ -1205,7 +1464,7 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) WAVE/Z params = JSON_GetKeys(jsonID, SF_META_USER_GROUP + "Parameters/" + SF_OP_PSX_RISETIME) CHECK_WAVE(params, TEXT_WAVE) - CHECK_EQUAL_VAR(DimSize(params, ROWS), 2) + CHECK_EQUAL_VAR(DimSize(params, ROWS), 3) JSON_Release(jsonID) @@ -1215,14 +1474,54 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) CHECK_NO_RTE() CHECK_WAVE(dataWref, WAVE_WAVE) - // complains without events found - str = "psx(myID, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([0, 2]), selvis(all)), 5000, 15, -5), 25, 100, 0)" + // without events found we get empty waves + str = "psx(myID, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([0, 2]), selvis(all)), 10, 15, -5), 250, 10, 0)" + WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) + CHECK_WAVE(dataWref, WAVE_WAVE) + Make/FREE/N=(DimSize(dataWref, ROWS)) sizes = WaveExists(dataWref[p]) ? DimSize(dataWref[p], ROWS) : NaN + CHECK_EQUAL_WAVES(sizes, {500, 500, 500, NaN, NaN, NaN, NaN, 500, 500, 500, NaN, NaN, NaN, NaN}) + + // complains with no sweep data try + str = "psx(myID, psxKernel(select(selrange([150, 160]), selchannels(AD6), selsweeps([0, 2]), selvis(all)), 1, 2, -5), 2.5, 100, 0)" WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) FAIL() catch - PASS() + CHECK_NO_RTE() endtry + + // returns empty waves without events found due to kernelAmp sign + overrideResults[][][%$"KernelAmpSignQC"] = 0 + str = "psx(id, psxKernel(select(selrange([50, 150]), selchannels(AD6), selvis(all), selsweeps([0, 2])), 1, 15, -4))" + WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) + CHECK_WAVE(dataWref, WAVE_WAVE) + Make/FREE/N=(DimSize(dataWref, ROWS)) sizes = WaveExists(dataWref[p]) ? DimSize(dataWref[p], ROWS) : NaN + CHECK_EQUAL_WAVES(sizes, {500, 500, 500, NaN, NaN, NaN, NaN, 500, 500, 500, NaN, NaN, NaN, NaN}) +End + +static Function PSXHandlesPartialResults() + + string browser, str, comboKey + + browser = SetupDatabrowserWithSomeData() + + Make/FREE/T/N=2 combos + + sprintf comboKey, "Range[25, 120], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + + sprintf comboKey, "Range[25, 120], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + // all decay fits are successfull + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 + + str = "psx(myID, psxKernel(select(selrange([25, 120]), selchannels(AD6), selsweeps([0, 2]), selvis(all)), 1, 2, -5), 2.5, 10, 0)" + WAVE/WAVE dataWref = SF_ExecuteFormula(str, browser, useVariables = 0) + PASS() End static Function TestOperationPSXTooLargeDecayTau() @@ -1237,8 +1536,9 @@ static Function TestOperationPSXTooLargeDecayTau() WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(2, combos) // all decay fits are successfull - overrideResults[][][%$"Fit Result"] = 1 - overrideResults[][][%Tau] = 1000 + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%Tau] = 1000 + overrideResults[][][%$"KernelAmpSignQC"] = 1 [win, device] = CreateEmptyUnlockedDataBrowserWindow() @@ -1257,7 +1557,7 @@ static Function TestOperationPSXTooLargeDecayTau() CHECK_EQUAL_WAVES(fitResult, {PSX_DECAY_FIT_ERROR, PSX_DECAY_FIT_ERROR}, mode = WAVE_DATA) End -static Function CheckEventDataHelper(WAVE/Z/WAVE dataWref, variable index) +static Function CheckEventDataHelper(WAVE/Z/WAVE dataWref, variable index, variable kernelAmpSign) variable numEvents @@ -1286,10 +1586,19 @@ static Function CheckEventDataHelper(WAVE/Z/WAVE dataWref, variable index) comp = sign(psxEvent[p][%$"Rise Time"]) CHECK_EQUAL_VAR(Sum(comp), numEvents) - // 1 NaN for the first event only WaveStats/M=0/Q psxEvent - CHECK_EQUAL_VAR(V_numNaNs, 1) CHECK_EQUAL_VAR(V_numInfs, 0) + + INFO("index = %d, V_numNaNs = %d, kernelAmpSign = %d", n0 = index, n1 = V_numNans, n2 = kernelAmpSign) + + // 1 NaN for the first event only, the rest is onset Time + if(kernelAmpSign == 1) + CHECK_EQUAL_VAR(V_numNaNs, 1) + elseif(kernelAmpSign == -1) + CHECK_EQUAL_VAR(V_numNaNs, 9) + else + FAIL() + endif End static Function CheckPSXEventField(WAVE/WAVE psxEventWaves, WAVE/T colLabels, WAVE indices, variable val) @@ -1334,8 +1643,9 @@ static Function MouseSelectionPSX() WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) - overrideResults[][][%$"Fit Result"] = 1 - overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = DB_OpenDataBrowser() device = HW_ITC_BuildDeviceString(StringFromList(0, DEVICE_TYPES_ITC), StringFromList(0, DEVICE_NUMBERS)) @@ -1359,7 +1669,7 @@ static Function MouseSelectionPSX() CheckPSXEventField({psxEvent_0, psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) // select event 0 - SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftFiltOffDeconv" 80, 15e-3, 110, 5e-3 + SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftOffFiltDeconv" 80, 15e-2, 110, 5e-2 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_ACCEPT, PSX_STATE_EVENT) @@ -1373,7 +1683,7 @@ static Function MouseSelectionPSX() CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) // select event 1 - SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftFiltOffDeconv" 120, 25e-3, 200, 5e-3 + SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftOffFiltDeconv" 120, 25e-2, 200, 5e-2 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_REJECT, PSX_STATE_EVENT) @@ -1386,7 +1696,7 @@ static Function MouseSelectionPSX() CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) // select both events top axis pair, event and fit state - SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftFiltOff" 50, 0, 200, 1 + SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftOffFilt" 50, -1, 200, 11 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_REJECT, PSX_STATE_FIT | PSX_STATE_EVENT) @@ -1397,7 +1707,7 @@ static Function MouseSelectionPSX() CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) // select nothing in both directions - SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftFiltOff" 0, 1, 50, 10 + SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftOffFilt" 0, 1, 50, 10 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_REJECT, PSX_STATE_FIT | PSX_STATE_EVENT) @@ -1408,7 +1718,7 @@ static Function MouseSelectionPSX() CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) // select nothing in x direction - SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftFiltOff" 0, 0, 50, 1 + SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftOffFilt" 0, 0, 50, 1 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_REJECT, PSX_STATE_FIT | PSX_STATE_EVENT) @@ -1419,7 +1729,7 @@ static Function MouseSelectionPSX() CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) // select nothing in y direction - SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftFiltOff" 50, 1, 200, 10 + SetMarquee/W=$psxPlot/HAX=bottom/VAX=$"leftOffFilt" 50, 1, 200, 10 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_REJECT, PSX_STATE_FIT | PSX_STATE_EVENT) @@ -1495,8 +1805,9 @@ static Function MouseSelectionPSXStats([STRUCT IUTF_mData &m]) combos[1] = comboKey WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) - overrideResults[][][%$"Fit Result"] = 1 - overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 postProc = m.s0 logMode = m.v0 @@ -1516,8 +1827,8 @@ static Function MouseSelectionPSXStats([STRUCT IUTF_mData &m]) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) // required for stats DoUpdate @@ -1532,8 +1843,8 @@ static Function MouseSelectionPSXStats([STRUCT IUTF_mData &m]) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) // unchanged - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_UNDET) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) // changed CheckPSXEventField({psxEvent_0}, {"Event manual QC call"}, {0}, PSX_ACCEPT) @@ -1542,7 +1853,7 @@ static Function MouseSelectionPSXStats([STRUCT IUTF_mData &m]) // select event 0 from combo 1 SetActiveSubwindow $psxStatsGraph - SetMarquee/W=$psxStatsGraph/HAX=bottom/VAX=left -0.1, AdaptForPostProc(postProc, 130), 0.1, AdaptForPostProc(postProc, 125) + SetMarquee/W=$psxStatsGraph/HAX=bottom/VAX=left -0.1, AdaptForPostProc(postProc, 50), 0.1, AdaptForPostProc(postProc, 80) PSX_MouseEventSelection(PSX_REJECT, PSX_STATE_EVENT) @@ -1550,27 +1861,25 @@ static Function MouseSelectionPSXStats([STRUCT IUTF_mData &m]) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) // unchanged - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2, 3}, PSX_UNDET) CheckPSXEventField({psxEvent_0}, {"Event manual QC call"}, {0}, PSX_ACCEPT) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_UNDET) // changed CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_REJECT) - DoUpdate // select all events from both combos SetActiveSubwindow $psxStatsGraph - SetMarquee/W=$psxStatsGraph/HAX=bottom/VAX=left -0.1, AdaptForPostProc(postProc, 100), 1.1, AdaptForPostProc(postProc, 140) - + SetMarquee/W=$psxStatsGraph/HAX=bottom/VAX=left -0.1, AdaptForPostProc(postProc, 50), 3.1, AdaptForPostProc(postProc, 141) PSX_MouseEventSelection(PSX_UNDET, PSX_STATE_EVENT | PSX_STATE_FIT) // refetch the changed waves after each selection [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) // changed - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) End static Function MouseSelectionStatsPostProcNonFinite() @@ -1593,6 +1902,8 @@ static Function MouseSelectionStatsPostProcNonFinite() overrideResults[0][%$combos[1]][%$"Fit Result"] = 1 overrideResults[0][%$combos[1]][%$"Tau"] = +Inf + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = GetTestCode("nonfinite", eventState = "all", prop = "tau") @@ -1698,7 +2009,7 @@ static Function/S GetTestCode(string postProc, [string eventState, string prop]) endif if(ParamIsDefault(prop)) - prop = "xpos" + prop = "peaktime" endif code = "psx(myId, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([0, 2]), selvis(all))), 5, 100, 0)" @@ -1714,17 +2025,17 @@ static Function/WAVE GetCodeVariations() string code - Make/T/N=2/FREE wv + Make/T/N=(2)/FREE wv wv[0] = GetTestCode("nothing") code = "" // one sweep per operation separated with `with` - code = "psx(myId, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([0]), selvis(all))), 10, 100, 0)" + code = "psx(myId, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([0]), selvis(all))), 2, 100, 0)" code += "\r with \r" - code += "psx(myId, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([2]), selvis(all))), 2.5, 100, 0)" + code += "psx(myId, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([2]), selvis(all))), 1.5, 100, 0)" code += "\r and \r" - code += "psxStats(myId, select(selrange([50, 150]), selchannels(AD6), selsweeps([0, 2]), selvis(all)), xpos, all, nothing)" + code += "psxStats(myId, select(selrange([50, 150]), selchannels(AD6), selsweeps([0, 2]), selvis(all)), peak, all, nothing)" wv[1] = code code = "" @@ -1734,9 +2045,20 @@ End /// IUTF_TD_GENERATOR s0:GetCodeVariations static Function AllEventGraph([STRUCT IUTF_mData &m]) - string browser, code, extAllGraph, win, trace, info, rgbValue, mainWindow, specialEventPanel + string browser, code, extAllGraph, win, trace, info, rgbValue, mainWindow, specialEventPanel, comboKey variable numEvents + Make/FREE/T/N=2 combos + sprintf comboKey, "Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + sprintf comboKey, "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = m.s0 @@ -1770,23 +2092,23 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) WAVE/T allTraces = GetTracesHelper(extAllGraph, 1) - Make/FREE/T allTracesRef = {"T000000", "T000001", \ - "T000002_averageAccept_ComboIndex0", "T000003_averageReject_ComboIndex0", \ - "T000004_averageUndetermined_ComboIndex0", "T000005_averageAll_ComboIndex0", \ - "T000006_acceptAverageFit_ComboIndex0", \ - "T000007", \ - "T000008_averageAccept_ComboIndex1", "T000009_averageReject_ComboIndex1", \ - "T000010_averageUndetermined_ComboIndex1", "T000011_averageAll_ComboIndex1", \ - "T000012_acceptAverageFit_ComboIndex1", \ - "T000013_averageAccept_global", "T000014_averageReject_global", \ - "T000015_averageUndetermined_global", "T000016_averageAll_global", \ - "T000017_acceptAverageFit_global"} + Make/FREE/T allTracesRef = {"T000000", "T000001", "T000002", "T000003", \ + "T000004_averageAccept_ComboIndex0", "T000005_averageReject_ComboIndex0", \ + "T000006_averageUndetermined_ComboIndex0", "T000007_averageAll_ComboIndex0", \ + "T000008_acceptAverageFit_ComboIndex0", \ + "T000009", "T000010", "T000011", \ + "T000012_averageAccept_ComboIndex1", "T000013_averageReject_ComboIndex1", \ + "T000014_averageUndetermined_ComboIndex1", "T000015_averageAll_ComboIndex1", \ + "T000016_acceptAverageFit_ComboIndex1", \ + "T000017_averageAccept_global", "T000018_averageReject_global", \ + "T000019_averageUndetermined_global", "T000020_averageAll_global", \ + "T000021_acceptAverageFit_global"} CHECK_EQUAL_TEXTWAVES(allTracesRef, allTraces) // currently shown traces WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000000", "T000001", "T000007"} + Make/FREE/T dispTracesRef = {"T000000", "T000001", "T000002", "T000003", "T000009", "T000010", "T000011"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) CheckTraceColors(extAllGraph, dispTraces, PSX_UNDET) @@ -1816,7 +2138,7 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) PGC_SetAndActivateControl(specialEventPanel, "checkbox_average_events_undetermined", val = 1) WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000015_averageUndetermined_global"} + Make/FREE/T dispTracesRef = {"T000019_averageUndetermined_global"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) CheckTraceColors(extAllGraph, dispTraces, PSX_UNDET) @@ -1826,7 +2148,7 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) PGC_SetAndActivateControl(specialEventPanel, "checkbox_average_events_all", val = 1) WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000016_averageAll_global"} + Make/FREE/T dispTracesRef = {"T000020_averageAll_global"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) CheckTraceColors(extAllGraph, dispTraces, PSX_ALL) @@ -1834,32 +2156,11 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) // restrict to current combo PGC_SetAndActivateControl(specialEventPanel, "checkbox_restrict_events_to_current_combination", val = 1) WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000011_averageAll_ComboIndex1"} + Make/FREE/T dispTracesRef = {"T000015_averageAll_ComboIndex1"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) CheckTraceColors(extAllGraph, dispTraces, PSX_ALL) - // check average wave contents - - // combo1 - - // all - WAVE averageWaveFromTrace = TraceNameToWaveRef(extAllGraph, "T000011_averageAll_ComboIndex1") - - DFREF comboDFR = MIES_PSX#PSX_GetCurrentComboFolder(win) - DFREF singleEventDFR = GetPSXSingleEventFolder(comboDFR) - - WAVE/WAVE singleEventWaves = ListToWaveRefWave(GetListOfObjects(singleEventDFR, ".*", fullPath = 1)) - CHECK_EQUAL_VAR(DimSize(singleEventWaves, ROWS), 1) - CHECK_EQUAL_WAVES(singleEventWaves[0], averageWaveFromTrace, mode = WAVE_DATA) - - // same as undet - PGC_SetAndActivateControl(specialEventPanel, "checkbox_average_events_undetermined", val = 1) - PGC_SetAndActivateControl(specialEventPanel, "checkbox_average_events_all", val = 0) - - WAVE averageWaveFromTrace = TraceNameToWaveRef(extAllGraph, "T000010_averageUndetermined_ComboIndex1") - CHECK_EQUAL_WAVES(singleEventWaves[0], averageWaveFromTrace, mode = WAVE_DATA) - // combo0 PGC_SetAndActivateControl(mainWindow, "listbox_select_combo", val = 0) @@ -1869,13 +2170,13 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) PGC_SetAndActivateControl(specialEventPanel, "checkbox_average_events_undetermined", val = 0) PGC_SetAndActivateControl(specialEventPanel, "checkbox_average_events_all", val = 1) - WAVE averageWaveFromTrace = TraceNameToWaveRef(extAllGraph, "T000005_averageAll_ComboIndex0") + WAVE averageWaveFromTrace = TraceNameToWaveRef(extAllGraph, "T000007_averageAll_ComboIndex0") DFREF comboDFR = MIES_PSX#PSX_GetCurrentComboFolder(win) DFREF singleEventDFR = GetPSXSingleEventFolder(comboDFR) WAVE/WAVE singleEventWaves = ListToWaveRefWave(GetListOfObjects(singleEventDFR, ".*", fullPath = 1)) - CHECK_EQUAL_VAR(DimSize(singleEventWaves, ROWS), 2) + CHECK_EQUAL_VAR(DimSize(singleEventWaves, ROWS), 4) WAVE/Z/WAVE calcAvgPack = MIES_fWaveAverage(singleEventWaves, 1, IGOR_TYPE_64BIT_FLOAT) CHECK_WAVE(calcAvgPack, WAVE_WAVE) WAVE/Z calcAvg = calcAvgPack[0] @@ -1886,7 +2187,7 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) PGC_SetAndActivateControl(specialEventPanel, "checkbox_average_events_undetermined", val = 1) PGC_SetAndActivateControl(specialEventPanel, "checkbox_average_events_all", val = 0) - WAVE averageWaveFromTrace = TraceNameToWaveRef(extAllGraph, "T000004_averageUndetermined_ComboIndex0") + WAVE averageWaveFromTrace = TraceNameToWaveRef(extAllGraph, "T000006_averageUndetermined_ComboIndex0") CHECK_EQUAL_WAVES(calcAvg, averageWaveFromTrace, mode = WAVE_DATA) // now let's change some event/fit states @@ -1904,7 +2205,7 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) MIES_PSX#PSX_UpdateEventWaves(win, val = PSX_ACCEPT, index = 1, stateType = PSX_STATE_FIT) WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000000", "T000001"} + Make/FREE/T dispTracesRef = {"T000000", "T000001", "T000002", "T000003"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) CheckTraceColors(extAllGraph, dispTraces, PSX_UNDET) @@ -1915,7 +2216,7 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) DoUpdate WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000000", "T000001"} + Make/FREE/T dispTracesRef = {"T000000", "T000001", "T000002", "T000003"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) CheckTraceColors(extAllGraph, {"T000000"}, PSX_REJECT) @@ -1931,13 +2232,22 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) PGC_SetAndActivateControl(specialEventPanel, "popupmenu_state_type", str = "Event*") WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000000"} + Make/FREE/T dispTracesRef = {"T000000", "T000002", "T000003"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) End static Function JumpToUndet() - string browser, code, psxGraph, win, mainWindow + string browser, code, psxGraph, win, mainWindow, comboKey + + Make/FREE/T/N=2 combos + sprintf comboKey, "Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + sprintf comboKey, "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -1976,8 +2286,8 @@ static Function JumpToUndet() // find event 0 of next combo PGC_SetAndActivateControl(mainWindow, "button_jump_first_undet") - CHECK_EQUAL_VAR(pcsr(A, psxGraph), 0) - CHECK_EQUAL_VAR(MIES_PSX#PSX_GetCurrentComboIndex(win), 1) + CHECK_EQUAL_VAR(pcsr(A, psxGraph), 2) + CHECK_EQUAL_VAR(MIES_PSX#PSX_GetCurrentComboIndex(win), 0) // undet event state event 1 of combo 0 MIES_PSX#PSX_UpdateEventWaves(win, val = PSX_UNDET, index = 1, stateType = PSX_STATE_EVENT, comboIndex = 0) @@ -1995,9 +2305,18 @@ End /// UTF_TD_GENERATOR s0:SupportedPostProcForEventSelection static Function JumpToSelectedEvents([STRUCT IUTF_mData &m]) - string browser, code, psxGraph, win, mainWindow, postProc, psxStatsGraph + string browser, code, psxGraph, win, mainWindow, postProc, psxStatsGraph, comboKey variable logMode + Make/FREE/T/N=2 combos + sprintf comboKey, "Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + sprintf comboKey, "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 + postProc = m.s0 logMode = m.v0 @@ -2021,7 +2340,7 @@ static Function JumpToSelectedEvents([STRUCT IUTF_mData &m]) // select event 0, combo 1 SetActiveSubwindow $psxStatsGraph - SetMarquee/W=$psxStatsGraph/HAX=bottom/VAX=left -0.1, AdaptForPostProc(postProc, 130), 0.1, AdaptForPostProc(postProc, 125) + SetMarquee/W=$psxStatsGraph/HAX=bottom/VAX=left -0.1, AdaptForPostProc(postProc, 49), 0.1, AdaptForPostProc(postProc, 80) PSX_JumpToEvents() @@ -2030,7 +2349,7 @@ static Function JumpToSelectedEvents([STRUCT IUTF_mData &m]) // select all events SetActiveSubwindow $psxStatsGraph - SetMarquee/W=$psxStatsGraph/HAX=bottom/VAX=left -0.1, AdaptForPostProc(postProc, 130), 1.1, AdaptForPostProc(postProc, 100) + SetMarquee/W=$psxStatsGraph/HAX=bottom/VAX=left -0.1, AdaptForPostProc(postProc, 49), 1.1, AdaptForPostProc(postProc, 100) PSX_JumpToEvents() @@ -2042,7 +2361,8 @@ static StrConstant PSXGRAPH_REF_TRACE = "PeakY" static Function CheckCurrentEvent(string win, variable comboIndex, variable eventIndex, variable waveIndex) - string singleEventGraph, annoInfo + string singleEventGraph, annoInfo, eventIndexStr + variable eventIndexAnno INFO("win %s comboIndex %d, eventIndex %d, waveIndex %d", s0 = win, n0 = comboIndex, n1 = eventIndex, n2 = waveIndex) @@ -2051,12 +2371,25 @@ static Function CheckCurrentEvent(string win, variable comboIndex, variable even CHECK_EQUAL_VAR(pcsr(A, win), waveIndex) CHECK_EQUAL_VAR(MIES_PSX#PSX_GetCurrentComboIndex(win), comboIndex) annoInfo = AnnotationInfo(singleEventGraph, "description") - CHECK(GrepString(annoInfo, "Event:[[:space:]]*" + num2istr(eventIndex))) + + SplitString/E="Event:[[:space:]]*([[:digit:]]+)" annoInfo, eventIndexStr + CHECK_EQUAL_VAR(V_flag, 1) + eventIndexAnno = str2num(eventIndexStr) + CHECK_EQUAL_VAR(eventIndexAnno, eventIndex) End static Function CursorMovement() - string browser, code, psxGraph, win, mainWindow + string browser, code, psxGraph, win, mainWindow, comboKey + + Make/FREE/T/N=2 combos + sprintf comboKey, "Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + sprintf comboKey, "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -2089,7 +2422,16 @@ End static Function CursorMovementStats() - string browser, code, psxGraph, win, mainWindow, psxStatsGraph, trace, tracenames + string browser, code, psxGraph, win, mainWindow, psxStatsGraph, trace, tracenames, comboKey + + Make/FREE/T/N=2 combos + sprintf comboKey, "Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + sprintf comboKey, "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -2124,7 +2466,17 @@ static Function CursorMovementStats() Cursor/W=$psxStatsGraph/P A, $trace, 2 - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 0, 2, 2) + CheckCurrentEvent(psxGraph, 0, 2, 2) + + Cursor/W=$psxStatsGraph/P A, $trace, 3 + + CheckCurrentEvent(psxStatsGraph, 0, 3, 3) + CheckCurrentEvent(psxGraph, 0, 3, 3) + + Cursor/W=$psxStatsGraph/P A, $trace, 4 + + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) CheckCurrentEvent(psxGraph, 1, 0, 0) End @@ -2150,8 +2502,9 @@ static Function KeyboardInteractions() combos[1] = comboKey WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) - overrideResults[][][%$"Fit Result"] = 1 - overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -2173,8 +2526,8 @@ static Function KeyboardInteractions() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxGraph, UP_KEY) @@ -2185,89 +2538,131 @@ static Function KeyboardInteractions() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_UNDET) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxGraph, DOWN_KEY) DoUpdate - CheckCurrentEvent(psxGraph, 1, 0, 0) + CheckCurrentEvent(psxGraph, 0, 2, 2) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) + + SendKey(psxGraph, DOWN_KEY) + + DoUpdate + + CheckCurrentEvent(psxGraph, 0, 3, 3) + + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) + + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) + + SendKey(psxGraph, UP_KEY) + + DoUpdate + + CheckCurrentEvent(psxGraph, 1, 0, 0) + + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) + + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxGraph, LEFT_KEY) DoUpdate // cursor changed - CheckCurrentEvent(psxGraph, 0, 1, 1) + CheckCurrentEvent(psxGraph, 0, 3, 3) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) // but not the event/fit states - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxGraph, LEFT_KEY) DoUpdate // cursor changed - CheckCurrentEvent(psxGraph, 0, 0, 0) + CheckCurrentEvent(psxGraph, 0, 2, 2) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) // but not the event/fit states - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxGraph, C_KEY) DoUpdate // only changes axis scaling - CheckCurrentEvent(psxGraph, 0, 0, 0) + CheckCurrentEvent(psxGraph, 0, 2, 2) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) // and not the event/fit states - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxGraph, R_KEY) // we are now going backwards - SendKey(psxGraph, DOWN_KEY) + SendKey(psxGraph, UP_KEY) DoUpdate - CheckCurrentEvent(psxGraph, 1, 0, 0) + CheckCurrentEvent(psxGraph, 0, 1, 1) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxGraph, -1) DoUpdate + // and more backwards + SendKey(psxGraph, LEFT_KEY) + SendKey(psxGraph, LEFT_KEY) + SendKey(psxGraph, LEFT_KEY) + SendKey(psxGraph, LEFT_KEY) + + DoUpdate + + CheckCurrentEvent(psxGraph, 1, 0, 0) + + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) + + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) + // ignores unkonwn key CheckCurrentEvent(psxGraph, 1, 0, 0) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxGraph, E_KEY) @@ -2278,8 +2673,9 @@ static Function KeyboardInteractions() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_ACCEPT) @@ -2294,8 +2690,9 @@ static Function KeyboardInteractions() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_REJECT) @@ -2308,8 +2705,9 @@ static Function KeyboardInteractions() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_ACCEPT) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_REJECT) @@ -2323,8 +2721,9 @@ static Function KeyboardInteractions() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_REJECT) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_REJECT) @@ -2337,8 +2736,9 @@ static Function KeyboardInteractions() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_UNDET) @@ -2351,8 +2751,9 @@ static Function KeyboardInteractions() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 2, 3}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_ACCEPT) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_ACCEPT) End @@ -2369,8 +2770,9 @@ static Function KeyboardInteractionsStats() WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) - overrideResults[][][%$"Fit Result"] = 1 - overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -2396,77 +2798,108 @@ static Function KeyboardInteractionsStats() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1}, PSX_UNDET) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) - SendKey(psxStatsGraph, UP_KEY) + SendKey(psxGraph, UP_KEY) DoUpdate - CheckCurrentEvent(psxStatsGraph, 0, 1, 1) + CheckCurrentEvent(psxGraph, 0, 1, 1) - [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_UNDET) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) - SendKey(psxStatsGraph, DOWN_KEY) + SendKey(psxGraph, DOWN_KEY) DoUpdate - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxGraph, 0, 2, 2) - [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) + + SendKey(psxGraph, DOWN_KEY) + + DoUpdate - SendKey(psxStatsGraph, LEFT_KEY) + CheckCurrentEvent(psxGraph, 0, 3, 3) + + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) + + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) + + SendKey(psxGraph, UP_KEY) + + DoUpdate + + CheckCurrentEvent(psxGraph, 1, 0, 0) + + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) + + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) + + SendKey(psxGraph, LEFT_KEY) DoUpdate // cursor changed - CheckCurrentEvent(psxStatsGraph, 0, 1, 1) + CheckCurrentEvent(psxGraph, 0, 3, 3) - [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) // but not the event/fit states - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) - SendKey(psxStatsGraph, LEFT_KEY) + SendKey(psxGraph, LEFT_KEY) DoUpdate // cursor changed - CheckCurrentEvent(psxStatsGraph, 0, 0, 0) + CheckCurrentEvent(psxGraph, 0, 2, 2) - [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) // but not the event/fit states - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) - SendKey(psxStatsGraph, C_KEY) + SendKey(psxGraph, C_KEY) DoUpdate // only changes axis scaling - CheckCurrentEvent(psxStatsGraph, 0, 0, 0) + CheckCurrentEvent(psxGraph, 0, 2, 2) - [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) + [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxGraph) // and not the event/fit states - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxStatsGraph, R_KEY) // we are now going backwards + SendKey(psxStatsGraph, DOWN_KEY) + SendKey(psxStatsGraph, DOWN_KEY) + + CheckCurrentEvent(psxStatsGraph, 0, 0, 0) + SendKey(psxStatsGraph, DOWN_KEY) DoUpdate @@ -2476,40 +2909,43 @@ static Function KeyboardInteractionsStats() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) // correct for below tests assuming a certain position SendKey(psxStatsGraph, RIGHT_KEY) SendKey(psxStatsGraph, RIGHT_KEY) + SendKey(psxStatsGraph, RIGHT_KEY) + SendKey(psxStatsGraph, RIGHT_KEY) - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) SendKey(psxStatsGraph, -1) DoUpdate // ignores unkonwn key - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxStatsGraph, E_KEY) DoUpdate // no cursor change - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_ACCEPT) @@ -2520,12 +2956,13 @@ static Function KeyboardInteractionsStats() DoUpdate // no cursor change - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_REJECT) @@ -2534,12 +2971,13 @@ static Function KeyboardInteractionsStats() DoUpdate // no cursor change - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_ACCEPT) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_REJECT) @@ -2549,12 +2987,13 @@ static Function KeyboardInteractionsStats() DoUpdate // no cursor change - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_REJECT) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_REJECT) @@ -2563,12 +3002,13 @@ static Function KeyboardInteractionsStats() DoUpdate // no cursor change - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_UNDET) @@ -2577,12 +3017,13 @@ static Function KeyboardInteractionsStats() DoUpdate // no cursor change - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 0, 4) [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {3}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0, 1, 2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1, 2}, PSX_UNDET) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_ACCEPT) CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_ACCEPT) End @@ -2599,8 +3040,9 @@ static Function KeyboardInteractionsStatsSpecial() WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) - overrideResults[][][%$"Fit Result"] = 1 - overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -2616,6 +3058,8 @@ static Function KeyboardInteractionsStatsSpecial() SendKey(psxGraph, UP_KEY) SendKey(psxGraph, DOWN_KEY) + SendKey(psxGraph, DOWN_KEY) + SendKey(psxGraph, DOWN_KEY) SendKey(psxGraph, UP_KEY) // replot so that stats now has data @@ -2638,8 +3082,9 @@ static Function KeyboardInteractionsStatsSpecial() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1, 2, 3}, PSX_REJECT) CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_UNDET) // going one right, moves two events SendKey(psxGraph, RIGHT_KEY) @@ -2676,6 +3121,8 @@ static Function KeyboardInteractionsStatsPostProcNonFinite() overrideResults[0][%$combos[1]][%$"Fit Result"] = 1 overrideResults[0][%$combos[1]][%$"Tau"] = +Inf + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = GetTestCode("nonfinite", eventState = "all", prop = "tau") @@ -2700,23 +3147,35 @@ static Function KeyboardInteractionsStatsPostProcNonFinite() [WAVE psxEvent_0, WAVE psxEvent_1] = GetPSXEventWavesHelper(psxStatsGraph) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call"}, {0}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Event manual QC call"}, {0}, PSX_UNDET) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_UNDET) - - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call"}, {0, 3}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call"}, {1, 2}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Event manual QC call"}, {0, 1, 2, 3}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0, 1}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0, 1, 2}, PSX_UNDET) SendKey(psxStatsGraph, UP_KEY) SendKey(psxStatsGraph, DOWN_KEY) + SendKey(psxStatsGraph, DOWN_KEY) SendKey(psxStatsGraph, UP_KEY) - CheckCurrentEvent(psxStatsGraph, 1, 0, 2) + CheckCurrentEvent(psxStatsGraph, 1, 2, 4) + + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call"}, {0, 3}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call"}, {2}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Fit manual QC call"}, {1}, PSX_REJECT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call"}, {0}, PSX_REJECT) CheckPSXEventField({psxEvent_0}, {"Event manual QC call"}, {0}, PSX_ACCEPT) - CheckPSXEventField({psxEvent_0}, {"Fit manual QC call", "Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Event manual QC call"}, {1}, PSX_REJECT) + CheckPSXEventField({psxEvent_0}, {"Event manual QC call"}, {2}, PSX_UNDET) + CheckPSXEventField({psxEvent_0}, {"Event manual QC call"}, {3}, PSX_REJECT) - CheckPSXEventField({psxEvent_1}, {"Fit manual QC call", "Event manual QC call"}, {0}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {0}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {1}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Fit manual QC call"}, {2}, PSX_REJECT) + CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {0}, PSX_ACCEPT) + CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {1}, PSX_UNDET) + CheckPSXEventField({psxEvent_1}, {"Event manual QC call"}, {2}, PSX_UNDET) End static Function NoEventsAtAll() @@ -2725,7 +3184,7 @@ static Function NoEventsAtAll() browser = SetupDatabrowserWithSomeData() - code = "psx(psxKernel([50, 150], select(channels(AD6), [0, 2], all)), 100, 100, 0)" + code = "psx(psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([0, 2]), selvis(all))), 100, 100, 0)" win = ExecuteSweepFormulaCode(browser, code) @@ -2739,7 +3198,16 @@ End static Function CheckResultsWavesForAverageFitResult() - string browser, code, psxGraph, win, mainWindow, specialEventPanel, name, entry + string browser, code, psxGraph, win, mainWindow, specialEventPanel, name, entry, comboKey + + Make/FREE/T/N=2 combos + sprintf comboKey, "Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + sprintf comboKey, "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -2775,7 +3243,16 @@ End static Function TestBlockIndexLogic() - string browser, code, psxGraph, win, mainWindow, specialEventPanel, extAllGraph + string browser, code, psxGraph, win, mainWindow, specialEventPanel, extAllGraph, comboKey + + Make/FREE/T/N=2 combos + sprintf comboKey, "Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + sprintf comboKey, "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -2795,7 +3272,7 @@ static Function TestBlockIndexLogic() CHECK_EQUAL_STR(PSX_GetAllEventBlockNumbers(specialEventPanel), "0;") WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000000", "T000001", "T000007"} + Make/FREE/T dispTracesRef = {"T000000", "T000001", "T000002", "T000003", "T000009", "T000010", "T000011"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) // 50% block size @@ -2809,7 +3286,7 @@ static Function TestBlockIndexLogic() CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "0") WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000000"} + Make/FREE/T dispTracesRef = {"T000000", "T000001", "T000002"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) // second block @@ -2820,7 +3297,7 @@ static Function TestBlockIndexLogic() CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "1") WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000001", "T000007"} + Make/FREE/T dispTracesRef = {"T000003", "T000009", "T000010", "T000011"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) // 33% block size @@ -2830,7 +3307,7 @@ static Function TestBlockIndexLogic() DoUpdate - CHECK_EQUAL_STR(PSX_GetAllEventBlockNumbers(specialEventPanel), "0;1;2;") + CHECK_EQUAL_STR(PSX_GetAllEventBlockNumbers(specialEventPanel), "0;1;2;3;") // first block CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "0") @@ -2858,7 +3335,20 @@ static Function TestBlockIndexLogic() CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "2") WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000007"} + Make/FREE/T dispTracesRef = {"T000002"} + CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) + + // fourth block + PGC_SetAndActivateControl(specialEventPanel, "popup_block", str = "3") + + DoUpdate + + CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "3") + + WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) + // while it is suprising to see four here and only one in the other blocks it + // works with larger event numbers from real data + Make/FREE/T dispTracesRef = {"T000003", "T000009", "T000010", "T000011"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) // current combination only @@ -2869,7 +3359,7 @@ static Function TestBlockIndexLogic() CHECK_EQUAL_STR(PSX_GetAllEventBlockNumbers(specialEventPanel), "0;") WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000000", "T000001"} + Make/FREE/T dispTracesRef = {"T000000", "T000001", "T000002", "T000003"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) // 50% block size @@ -2883,7 +3373,7 @@ static Function TestBlockIndexLogic() CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "0") WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000000"} + Make/FREE/T dispTracesRef = {"T000000", "T000001"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) // second block @@ -2894,19 +3384,19 @@ static Function TestBlockIndexLogic() CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "1") WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) - Make/FREE/T dispTracesRef = {"T000001"} + Make/FREE/T dispTracesRef = {"T000002", "T000003"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) - // 33% block size + // 20% block size // reset block index PGC_SetAndActivateControl(specialEventPanel, "popup_block", str = "0") - PGC_SetAndActivateControl(specialEventPanel, "setvar_event_block_size", val = 33) + PGC_SetAndActivateControl(specialEventPanel, "setvar_event_block_size", val = 20) DoUpdate - // two few events for 3 blocks - CHECK_EQUAL_STR(PSX_GetAllEventBlockNumbers(specialEventPanel), "0;1;") + // two few events for 5 blocks + CHECK_EQUAL_STR(PSX_GetAllEventBlockNumbers(specialEventPanel), "0;1;2;3;") // first block CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "0") @@ -2925,48 +3415,82 @@ static Function TestBlockIndexLogic() WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) Make/FREE/T dispTracesRef = {"T000001"} CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) + + // third block + PGC_SetAndActivateControl(specialEventPanel, "popup_block", str = "2") + + DoUpdate + + CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "2") + + WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) + Make/FREE/T dispTracesRef = {"T000002"} + CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) + + // fourth block + PGC_SetAndActivateControl(specialEventPanel, "popup_block", str = "3") + + DoUpdate + + CHECK_EQUAL_STR(GetPopupMenuString(specialEventPanel, "popup_block"), "3") + + WAVE/T dispTraces = GetTracesHelper(extAllGraph, 1 + 2^2) + Make/FREE/T dispTracesRef = {"T000003"} + CHECK_EQUAL_TEXTWAVES(dispTracesRef, dispTraces) End -static Function [variable lowerThreshold, variable upperThreshold] TestRiseTimeContainer(WAVE/WAVE dataWref) +static Function [variable lowerThreshold, variable upperThreshold, variable diffThreshold] TestRiseTimeContainer(WAVE/WAVE dataWref) CHECK_WAVE(dataWref, WAVE_WAVE) CHECK_EQUAL_VAR(DimSize(dataWref, ROWS), 1) WAVE/Z data = dataWref[0] CHECK_WAVE(data, NUMERIC_WAVE) - CHECK_EQUAL_VAR(DimSize(data, ROWS), 2) + CHECK_EQUAL_VAR(DimSize(data, ROWS), 3) upperThreshold = data[%$"Upper Threshold"] CHECK(BetweenZeroAndOneExc(upperThreshold)) lowerThreshold = data[%$"Lower Threshold"] CHECK(BetweenZeroAndOneExc(lowerThreshold)) + diffThreshold = data[%$"Differentiate Threshold"] + CHECK(BetweenZeroAndOneExc(lowerThreshold)) - return [lowerThreshold, upperThreshold] + return [lowerThreshold, upperThreshold, diffThreshold] End static Function TestOperationRiseTime() string win, str - variable lowerThreshold, upperThreshold + variable lowerThreshold, upperThreshold, diffThreshold win = SetupDatabrowserWithSomeData() str = "psxRiseTime()" WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) - [lowerThreshold, upperThreshold] = TestRiseTimeContainer(dataWref) + [lowerThreshold, upperThreshold, diffThreshold] = TestRiseTimeContainer(dataWref) CHECK_EQUAL_VAR(lowerThreshold, 0.2) CHECK_EQUAL_VAR(upperThreshold, 0.8) + CHECK_EQUAL_VAR(diffThreshold, 0.05) str = "psxRiseTime(10)" WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) - [lowerThreshold, upperThreshold] = TestRiseTimeContainer(dataWref) + [lowerThreshold, upperThreshold, diffThreshold] = TestRiseTimeContainer(dataWref) CHECK_EQUAL_VAR(lowerThreshold, 0.1) CHECK_EQUAL_VAR(upperThreshold, 0.8) + CHECK_EQUAL_VAR(diffThreshold, 0.05) str = "psxRiseTime(10, 90)" WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) - [lowerThreshold, upperThreshold] = TestRiseTimeContainer(dataWref) + [lowerThreshold, upperThreshold, diffThreshold] = TestRiseTimeContainer(dataWref) CHECK_EQUAL_VAR(lowerThreshold, 0.1) CHECK_EQUAL_VAR(upperThreshold, 0.9) + CHECK_EQUAL_VAR(diffThreshold, 0.05) + + str = "psxRiseTime(10, 90, 45)" + WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) + [lowerThreshold, upperThreshold, diffThreshold] = TestRiseTimeContainer(dataWref) + CHECK_EQUAL_VAR(lowerThreshold, 0.1) + CHECK_EQUAL_VAR(upperThreshold, 0.9) + CHECK_EQUAL_VAR(diffThreshold, 0.45) // checks parameters try @@ -2988,7 +3512,16 @@ End static Function TestOperationPrep() - string win, device, code, psxCode + string win, device, code, psxCode, comboKey + + Make/FREE/T/N=2 combos + sprintf comboKey, "Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[0] = comboKey + sprintf comboKey, "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() + combos[1] = comboKey + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 [win, device] = CreateEmptyUnlockedDataBrowserWindow() @@ -3040,8 +3573,9 @@ static Function TestStoreAndLoad() combos[1] = comboKey WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) - overrideResults[][][%$"Fit Result"] = 1 - overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 browser = SetupDatabrowserWithSomeData() @@ -3214,7 +3748,7 @@ static Function TestOperationDeconvFilter() endtry try - str = "psxDeconvFilter(1, 1, 2)" + str = "psxDeconvFilter(1, 1, -1)" WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) FAIL() catch diff --git a/Packages/tests/Basic/UTF_Utils_GUI.ipf b/Packages/tests/Basic/UTF_Utils_GUI.ipf index 1025480276..abc0f2cdf3 100644 --- a/Packages/tests/Basic/UTF_Utils_GUI.ipf +++ b/Packages/tests/Basic/UTF_Utils_GUI.ipf @@ -83,3 +83,33 @@ Function FTWWorks() End /// @} + +Function TestRemoveControls() + + string win + + NewPanel + win = S_name + + Button abcd + PopupMenu efgh + + CHECK_EQUAL_STR(ControlNameList(win), "abcd;efgh;") + RemoveAllControls(win) + CHECK_EQUAL_STR(ControlNameList(win), "") +End + +Function TestRemoveDrawLayers() + + string win + Display + win = S_name + + DrawText/W=$win 47, 475, "my text" + + DrawAction/W=$win commands + CHECK_GT_VAR(strlen(S_recreation), 0) + RemoveAllDrawLayers(win) + DrawAction/W=$win commands + CHECK_EQUAL_VAR(strlen(S_recreation), 0) +End diff --git a/Packages/tests/Basic/UTF_Utils_WaveHandling.ipf b/Packages/tests/Basic/UTF_Utils_WaveHandling.ipf index e8fe0d9b74..95fcc5b34a 100644 --- a/Packages/tests/Basic/UTF_Utils_WaveHandling.ipf +++ b/Packages/tests/Basic/UTF_Utils_WaveHandling.ipf @@ -666,20 +666,14 @@ static Function TestDeepCopyWaveRefWave() endtry Make/FREE/WAVE/N=(1, 1) invalidSrc1 - try - WAVE/WAVE cpy = DeepCopyWaveRefWave(invalidSrc1); AbortOnRTE - FAIL() - catch - PASS() - endtry + WAVE/WAVE cpy = DeepCopyWaveRefWave(invalidSrc1) + CHECK_EQUAL_WAVES(GetWaveDimensions(cpy), {1, 1, 0, 0}, mode = WAVE_DATA) + CHECK_WAVE(cpy[0], NULL_WAVE) Make/FREE/WAVE/N=(1) invalidSrc2 - try - WAVE/WAVE cpy = DeepCopyWaveRefWave(invalidSrc2); AbortOnRTE - FAIL() - catch - PASS() - endtry + WAVE/WAVE cpy = DeepCopyWaveRefWave(invalidSrc2) + CHECK_EQUAL_WAVES(GetWaveDimensions(cpy), {1, 0, 0, 0}, mode = WAVE_DATA) + CHECK_WAVE(cpy[0], NULL_WAVE) WAVE src = $"" try