From 8219a537573a0f249d01470acdf9056f4516a7fb Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 23 Feb 2024 15:42:31 +0100 Subject: [PATCH 01/31] SweepFormula/psxKernel: Skip kernel creation for too large decayTau Requested change by Tim Jarsky. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 37 +++++++++++++++---- Packages/tests/Basic/UTF_SweepFormula_PSX.ipf | 9 +++++ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index aa1e3ae9a4..5675e38145 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -878,7 +878,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 +910,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 @@ -4358,7 +4367,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) @@ -4398,18 +4407,30 @@ 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 JWN_CreatePath(output, parameterPath) JWN_SetWaveInWaveNote(output, parameterPath + "/range", range) // not the same as SF_META_RANGE diff --git a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index bb73912a07..4ed6ab4284 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -1120,6 +1120,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) From 2ba79ecc16b8db0f1c93c19c1a3e8fd88fe8788a Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 23 Feb 2024 16:57:09 +0100 Subject: [PATCH 02/31] SF_OperationEpochsImpl: Fix giving up too early We want to continue the loop even if one single select dataset did not had any epoch info. Bug introduced in 595daef0 (MIES_SweepFormula_PSX.ipf: Add support for multiple ranges, 2024-02-02). --- Packages/MIES/MIES_SweepFormula.ipf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_SweepFormula.ipf b/Packages/MIES/MIES_SweepFormula.ipf index d13da2d04e..e951a0afcd 100644 --- a/Packages/MIES/MIES_SweepFormula.ipf +++ b/Packages/MIES/MIES_SweepFormula.ipf @@ -3678,7 +3678,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) From 58c8095fd327d8df9942396e9615a1b50a3e1e66 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 23 Feb 2024 16:58:53 +0100 Subject: [PATCH 03/31] PSX_OperationKernel: Avoid assertion with invalid ranges We need to zap all null waves before storing the wave ref wave in the JSON wavenote. The order does matter but SFH_GetSweepsForFormula also ignores null ranges so we end up being ordered again in the end. Bug introduced in 595daef0 (MIES_SweepFormula_PSX.ipf: Add support for multiple ranges, 2024-02-02). --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 5 +++- Packages/tests/Basic/UTF_SweepFormula_PSX.ipf | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 5675e38145..9c948d5ed8 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -4432,8 +4432,11 @@ Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph 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) diff --git a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index 4ed6ab4284..9f9291df85 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -1103,6 +1103,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 From 5089b3c7d5127730935ccea8e82fabe56ca8ccb3 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 23 Feb 2024 17:02:49 +0100 Subject: [PATCH 04/31] SFH_ExtendIncompleteRanges: Ignore null ranges The additional /Z in the range based for loop is not required, but that is a bug reported to WM. Forgotten in 422eac80 (SF: Adapt SFH_EvaluateRange for multi dataset input, 2024-01-20). --- Packages/MIES/MIES_SweepFormula_Helpers.ipf | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_Helpers.ipf b/Packages/MIES/MIES_SweepFormula_Helpers.ipf index d2c4a9b636..26543e885c 100644 --- a/Packages/MIES/MIES_SweepFormula_Helpers.ipf +++ b/Packages/MIES/MIES_SweepFormula_Helpers.ipf @@ -362,9 +362,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] From 9fda580bde7ca5cdd023edd365f77058e59fb7c1 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 27 Feb 2024 14:40:39 +0100 Subject: [PATCH 05/31] PSX_OperationSetDimensionLabels: Factor it out --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 9c948d5ed8..86ad44fc90 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -4251,6 +4251,18 @@ 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 @@ -4315,11 +4327,7 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) 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) From d359a7a64a78cc988aa6cf7b66764a63dcf8dd0e Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 27 Feb 2024 16:06:39 +0100 Subject: [PATCH 06/31] PSX_Operation: Handle partial results better We are now removing empty entries in the output wave. This avoids an issue with psxPrep which did not anticipate that. As we are now not feeding in any null waves into PSX_OperationImpl we can also remove the checks there. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 61 ++++++++++++++----- Packages/tests/Basic/UTF_SweepFormula_PSX.ipf | 35 ++++++++++- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 86ad44fc90..6c83dcb833 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -701,6 +701,7 @@ static Function/WAVE PSX_CreateOverrideResults(variable numEvents, WAVE/T combos 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,17 +721,30 @@ static Function PSX_OperationSweepGathering(string graph, WAVE/WAVE psxKernelDat WAVE/Z/WAVE psxAnalyzePeaksFromCache = CA_TryFetchingEntryFromCache(cacheKey) if(WaveExists(psxAnalyzePeaksFromCache)) + + if(DimSize(psxAnalyzePeaksFromCache, ROWS) == 0) + return 1 + endif + WAVE sweepDataFiltOff = psxAnalyzePeaksFromCache[%sweepDataFiltOff] WAVE sweepDataFiltOffDeconv = psxAnalyzePeaksFromCache[%sweepDataFiltOffDeconv] else [WAVE sweepDataFiltOff, WAVE sweepDataFiltOffDeconv] = 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(sweepDataFiltOff) || !WaveExists(sweepDataFiltOffDeconv)) + Make/FREE/WAVE/N=(0) psxAnalyzePeaks + else + Make/FREE/WAVE/N=(2) psxAnalyzePeaks + SetDimensionLabels(psxAnalyzePeaks, "sweepDataFiltOff;sweepDataFiltOffDeconv", ROWS) + psxAnalyzePeaks[%sweepDataFiltOff] = sweepDataFiltOff + psxAnalyzePeaks[%sweepDataFiltOffDeconv] = sweepDataFiltOffDeconv + endif CA_StoreEntryIntoCache(cacheKey, psxAnalyzePeaks) + + if(DimSize(psxAnalyzePeaks, ROWS) == 0) + return 1 + endif endif key = PSX_GenerateKey("sweepData", index) @@ -741,6 +755,8 @@ static Function PSX_OperationSweepGathering(string graph, WAVE/WAVE psxKernelDat key = PSX_GenerateKey("sweepDataFiltOffDeconv", index) output[%$key] = sweepDataFiltOffDeconv + + return 0 End /// @brief Implementation of psx operation @@ -754,14 +770,10 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string WAVE sweepData = output[%$key] key = PSX_GenerateKey("sweepDataFiltOff", index) - WAVE/Z sweepDataFiltOff = output[%$key] + WAVE sweepDataFiltOff = output[%$key] key = PSX_GenerateKey("sweepDataFiltOffDeconv", index) - WAVE/Z sweepDataFiltOffDeconv = output[%$key] - - if(!WaveExists(sweepDataFiltOff) || !WaveExists(sweepDataFiltOffDeconv)) - return NaN - endif + WAVE sweepDataFiltOffDeconv = output[%$key] [WAVE selectData, WAVE range] = SFH_ParseToSelectDataWaveAndRange(sweepData) ASSERT(WaveExists(selectData) && WaveExists(range), "Could not recreate select/range wave") @@ -4281,7 +4293,7 @@ End Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) variable numberOfSDs, sweepFilterLow, sweepFilterHigh, parameterJsonID, numCombos, i, addedData, kernelAmp - variable maxTauFactor, peakThresh, numFailures + variable maxTauFactor, peakThresh, numFailures, idx, success string parameterPath, id, psxParameters, dataUnit id = SFH_GetArgumentAsText(jsonID, jsonPath, graph, SF_OP_PSX, 0, checkFunc = IsValidObjectName) @@ -4330,9 +4342,18 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) 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 @@ -4340,8 +4361,20 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) numFailures += PSX_OperationImpl(graph, parameterJsonID, id, peakThresh, maxTauFactor, riseTime, kernelAmp, i, output) endfor - if(numFailures == numCombos) - Abort + if(numFailures > 0) + // remove null waves + WAVE/Z outputClean = ZapNullRefs(output) + + if(!WaveExists(outputClean)) + Abort + endif + + WAVE outputNew = MoveWaveWithOverwrite(output, outputClean) + WAVE output = outputNew + WaveClear outputClean, outputNew + + numCombos = DimSize(output, ROWS) / PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY + PSX_OperationSetDimensionLabels(output, numCombos, labels, labelsTemplate) endif catch if(WaveExists(output)) diff --git a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index 9f9291df85..e789231741 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -1255,6 +1255,39 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) catch PASS() endtry + + // 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 + CHECK_NO_RTE() + endtry +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 + + 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() @@ -2757,7 +2790,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) From 49503f947cd921b890598ae08bbd8f1302d43560 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 27 Feb 2024 16:09:07 +0100 Subject: [PATCH 07/31] PSX_Operation: Output error message when we could not generate data --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 6c83dcb833..c2520dd196 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -4384,7 +4384,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) From 667d3f1ce1c2c025fea0ef543f39ab6f98ec9960 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 1 Mar 2024 23:18:51 +0100 Subject: [PATCH 08/31] PSX_OperationStatsImpl: Rework range handling The current implementation for the ranges did not handle multiple passed epochs nor epoch wildcards. The check for intersecting ranges added in 6d107905 (PSX_OperationStatsImpl: Assert on intersecting ranges, 2024-02-06) was also broken. While thinking about the current approach it was recognized that we actually want to collect the event data from all sweep ranges of all sweeps from the same equivalence class. This has now been done. We also support list of epochs and epoch wildcards. --- Packages/MIES/MIES_Constants.ipf | 2 + Packages/MIES/MIES_SweepFormula_PSX.ipf | 468 ++++++++---------- Packages/tests/Basic/UTF_SweepFormula_PSX.ipf | 192 ++++++- 3 files changed, 411 insertions(+), 251 deletions(-) diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index 74eb6a2f9a..885bd7624b 100644 --- a/Packages/MIES/MIES_Constants.ipf +++ b/Packages/MIES/MIES_Constants.ipf @@ -2353,6 +2353,8 @@ Constant PSX_DECONV_FILTER_DEF_LOW = 0.002 Constant PSX_DECONV_FILTER_DEF_HIGH = 0.004 Constant PSX_DECONV_FILTER_DEF_ORDER = 101 +StrConstant PSX_JWN_COMBO_KEYS_NAME = "ComboKeys" + StrConstant SF_OP_MERGE = "merge" StrConstant SF_OP_FIT = "fit" StrConstant SF_OP_FITLINE = "fitline" diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index c2520dd196..3f899b77dc 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -86,7 +86,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" @@ -1122,113 +1121,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) - for(k = 0; k < numCols; k += 1) + [chanNr, chanType, sweepNo, mapIndex] = PSX_GetSweepEquivKeyAndValue(selectDataEquiv, i, j) - [chanNr, chanType, sweepNo, mapIndex] = PSX_GetSweepEquivKeyAndValue(selectDataEquiv, i, k) + if(!IsValidSweepNumber(sweepNo)) + break + endif - if(!IsValidSweepNumber(sweepNo)) - break - endif + WAVE singleSelectData = SFH_NewSelectDataWave(1, 1) + + singleSelectData[0][%SWEEP] = sweepNo + singleSelectData[0][%CHANNELNUMBER] = chanNr + singleSelectData[0][%CHANNELTYPE] = chanType + singleSelectData[0][%SWEEPMAPINDEX] = mapIndex + + 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) + + if(!WaveExists(resolvedRanges)) + continue + endif + + PSX_CheckResolvedRanges(resolvedRanges) - WAVE singleSelectData = SFH_NewSelectDataWave(1, 1) + numRanges = DimSize(resolvedRanges, COLS) + for(k = 0; k < numRanges; k += 1) + Duplicate/FREE/RMD=[*][k] resolvedRanges, range - singleSelectData[0][%SWEEP] = sweepNo - singleSelectData[0][%CHANNELNUMBER] = chanNr - singleSelectData[0][%CHANNELTYPE] = chanType - singleSelectData[0][%SWEEPMAPINDEX] = mapIndex + if(WaveExists(epochRangeNames)) + Make/T/FREE rangeText = {epochRangeNames[k]} + WAVE rangeAlt = rangeText + else + WAVE rangeAlt = range + endif - comboKey = PSX_GenerateComboKey(graph, singleSelectData, range) + comboKey = PSX_GenerateComboKey(graph, singleSelectData, rangeAlt) WAVE/Z events = PSX_FilterEventContainer(eventContainer, comboKey) @@ -1246,203 +1223,198 @@ 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 "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 - if(!cmpstr(stateAsStr, "every")) - WAVE allStates = PSX_GetStates() - else - Make/FREE allStates = {PSX_ParseState(stateAsStr)} + 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) + + 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 diff --git a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index e789231741..8594f2b8af 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -464,6 +464,189 @@ 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 @@ -1018,7 +1201,7 @@ End static Function StatsComplainsAboutIntersectingRanges() - string browser, device, formulaGraph, comboKey, id + string browser, device, formulaGraph, comboKey, id, error [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() @@ -1032,6 +1215,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,10 +1225,11 @@ 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 From 540f83ad9461e089ed1e340ffa4bc58ccbce8b9a Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 1 Mar 2024 19:04:55 +0100 Subject: [PATCH 09/31] Documentation: Update it for psxstats --- Packages/MIES/SweepFormulaHelp.ifn | Bin 367650 -> 367648 bytes Packages/doc/SweepFormula.rst | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Packages/MIES/SweepFormulaHelp.ifn b/Packages/MIES/SweepFormulaHelp.ifn index 7c5f49404ffae064846dba989e1a4c9f57d8fd8d..dfb8ceab4b8e5069ccc778deccb87223d54cd190 100644 GIT binary patch delta 4626 zcma*peOMJ$9>DQ)=HB57nNgCFOEmcw8K{-(s*6fW=9&>%8cT#gXlTA55|x=35XBG? zNICe1#6xIEXog7mPE=%u+7_{{A=|R#QX!HN5o+Ii=lZOF>>um%eD3e}n{(#OnR8|a zi>d|`Rt?C`4H%~j{`D6RYC;r}O(DKT{GZ2jj(#_%wqAr?)kUD=(EY2zwFBXr z%osD!%Q@7tm*>unH=+~f8qY6T6f=ME+}IH}SB{hArS_|1rEnW3MFjSt1wSBYycD^p z!)XlpvlRY_LLAai2d_XWd=Q846nzSFe0%QMX13!^qIjHV%iL8#1I!C z4+ZFe*W+v(>|y*wApzy6#K)*dpAabqAr>Vl50OS4@icld;0Y;O(T-uEOa{x5inJ%W zYk1G(*+MM7MZc$55yT+#DfYjTqzwa~mLdczP=Y25n8n^A8|UCVn+xFx+Ti_+6cZ7H zOdLZe{KD8qB%=x)82(pQ0hQ>62xm3J+5a`qN|A+Dv}5{n>?eA#FOo^j;jWO1tEi5W zq8X#2nJm)KCx-1p?(;mr5V0J?41~^Q=}`ddJhl@T(19@f3pAhvC(wiNI4*)V1kI;L z6}%Vl>fr>&zQ`m|1>c2C8inY$h`YyHTtL)fwhhylFj3T^X^Awti6Wl;AI?v3yfm7K zqnGmfpbR2`Ex}|&APt#lfpwV_eNl$tiChG6sKB8_X*3X<;PDdQ4WuCxO=yKRiB}pC zN$h_z$qz5{M57l2U*XAol@k&F8gB*aAy%-Y7>{h^qYj?0voZ)l9t!X!F05pUG1JZ% z$i>)Xo*gtIE`u>$ANg_UVMGdPD93|h@TA_|RY z#v2U1MGr%M8B_ zJcP(bB~D{>wiJoTLL2;Z_=cbcBXXG-4xtO4Z?gYc{2W0eUfIYJZ=w@okcD07LS!B@ zM@61A>WK{yitWNY96>j3%a?|KJ`+I{mZJ{FX7(FNo28LW%ty^;_WvA7;#Mw(R)}pp zSlgsAWV~lv*&z+@x1^C-Bn`J>X=D_$obY;^{YFd)&%jRJ`<>E=M+SK@ zPNEgDyLhY6h-Ub`!#2Fb{+E+@moh^{Vhbutxl3XL#BS~q*~mvTBFngI6riL`8pnur z=tSRl`9p(5l%o<~VtP3bBjT|JS-4>5XW}0I7+@P3&;*~oJP&)N(MjwfdcDUnOhYJ& z@deJpXCHkLf<&yqK2+lbzJT#Qcl^FICKDsD68W$Xtl<4b5v==}9ompp$-d(%A`Z}w zQfO7Y%g{dH{YEm{(S} z`%iKKfgiHRXvO$i8c~9BoJJ#B(Fu=_c7&TsSO2`o;8p6D4jEwCze!UMShag?57AVm%))In#lg+yW&cQCv({!cVl>~J>gW65``CoeI4v9c2^Ti?F1Zy@b?JIz^7AYcEE^6Zd) zwu$5!yEXM*8KZ`FN-xX0cW*e)7DW4+JvSWDCvzl49q;5y%hg4KW!ZjB-P0rQwLL;p z+yU2M&J~!-k@+7uSHSitdCWoA`W*X7dTG&z&HJ3@IPa)4*A4O|>VeA)pQPpxwAVi} zdrhY$?GrPiisw~JxVd}B7;N<-s$XRdpapI5j3!mzDs5<&a%-)67D zv|Rqq%!iQw_8&7JO0NCj%$3p2uUUqRwIOLC~2g|^#-GJ2$+ZY8&=OTRL-rta<` z{GuKwXl*uU2lqa7IPY$8ovV)%d{@=ij*g?1{+kTYXDh3?$$W8U(KlK}b5zEu4FpT{ zcB_iMEbrBy;k-EYy`w2f-Py}|yGyNNt9syy9IE1brBzNFwa3ltN+G7A-Yjade(S=TtX`!?NqU$z(Nam`Ct zDVMlOcP`bX&eK6QY`R$su;{+7Zj0#F*Kie!Df$mGi%rKgt2S_m8fDe|Y)fglYnX1n zeU2AKPvD5Jx<_gOEYlMNi@(2lG21el29IEr>)#h!B1Z;|a$O{e;=TuU75WgLA4Ai; zEMrHznr@trLT{L& z`)ZDa&D4eN98G!ZToXmRBQOv(2F?Inp)1H!0Gi zbm8tC(S0LjcFgrsCA)Ef&9SZpbZmxuK0S8L)2~16sg!)e-MCJ*y2ZwIjxTgwCyS=K z#jau<#i@8#v4Nr?!7NmVjca_9=xWNPsU^uQ^bCsc)suY~yi?f;mS0!6`fZ{~*j+^) zg)PNZq*L@;Wfm&RoxyKk?P|J%CZBY((6>?yR>$2LJXl>MSmv)co7@X%ir;X3719$u OG+1Cgkm#Y8=ll+yy6rOn delta 4596 zcma*oe^^vi8o=>$?#!JLEh9J4C8MiR@Sqa5J+5nnXvVr^i01Z#brBKG2o;gckahe) zh=vG=90WC&B|=gc%YX=l6sgDz?Z>jL8M;N}gNjCmEaHA=?zrn8`^WM;pLx%F-!tc) zd(OGT?rN{%YOn0vvA?hi{%#XpQix<)7EOqki2w6?PTlu&8&62l>?1_}1u0VK7{wP7 zj!WTrQHr<`LfAK0#Ht)!4CngRt-1)J&rzcD@BfJE zBBo4~A`eYCg$EvyA`r2NM>?9|6)c4hLXeIu>_t1mAC+Pj5>bHD_!dJ#r0_;uh;)cT z8pY_r%1Kh}KnWVrkBCqyp2kY#V;2siAGXO-496@)AqAz_j}z#HHbsh2ScoOKiZzc( zk@1)`iXU@GQBHCStq7Vb#j}V(G0O1~+Tr;)H^X?O;UH=;AWVwcn1ci)qYSO+M#yhj z6*S-sJf|@}@=@X7qYq)fWA?~H19~tdT#9K}gmoxJEl%Sqyq;jfh`}b5paEwva5`Iv z@afWsBPO5#yKx0xPqJ-rMDY=eWK^IUAE6loBc$-fLX@E*LK;oPQ|QO=8B%nh3;vNz z2B}Cx`b?f0-m^GcScq@o`4lUHIAlG={#VoJ#E98aL}E3{(1zi^XK#^iR}Lv zKEe{E(MBADUTH+HVE@-U>8BOJzwBj9e6=2}AzG${-R2*p07n zel<&s*=%tN@-T4?X9ul_U(1BoaieTEGN9)V80Pp${Bc* z_x??3Bq5V_DNdjR3(I(`(28>i*uysLVgD;=c$YIn#9#+1%Xvy-3$(X*O5~yt=Mb}( zr^arS?Ulw6ViUSCcpv|0umTmR##flWpTmeGWFQ;o9ejlTm461t9h4UeUJAW>(GTB_}1`yfD*Kz4T0}-7Eq42(E+WNRf2!5bQn`; z>_9If4)Mc)2AqTSFgHOB!s>V{&{-!9TRp#eh(ahT?qVyB}G2GkF&R!h1F%@oDk7Guf(tT5Padd=2h_Z7dB3g+O%$rh7v)&lr2DuRyKbYV4&0D_D)N%FYL&0Kdf5Z19NMg@98L4n zA0(+&2QD$#yXqTfs8P3f$+4EIZJJv9gg#7#UXq^nU(u~b-EzhDuyd5{t`Svzm$X_M zip-nY$5VNKr=~7nlYaWINh;OI%M83v%^+Ax|KjfV2&J8GnEmX*Bn5Ap72BgETlT2I zUD96#U6EEj^DRwC*CN;_QQN%FJ$fifhRV6Z=<8J-K}&tdeEg|YUV2wkGp}jpBX~T{ zmH4Wg)}NYGXuHP`xHDvo1j zJDhg|xknDhEL`y3JlsQt`X$YTF}d z2lm{u;`SL_xv$rK1Y@o-x_6(euSX=6k^P$ZQQg_a!M2dzr9QaE4LsB(g2igJ+_H5x z>euLHcDLI}JMFi27{HaY9ydFv=3Z%)U#Ks88F0L^{EP6c8s`l2)m(xlzR0R(UY36L zr}^UiomMrjo3r|i;2*pC!P#%68rCPr>if#AqDaZ>%rT1MG_~A$RaX4x>Kv}_P@i#C z2CM4?t)^1-_epFH? zkfs(BECHXHQ?tLoJjb1MCyPiXd~PPnxWU<-^ria|;u$GSJ#~X2devHjCWoqu8*+^7 zQD2klEqCkULGw*YU>LiP?s|6nVv@mznQY6}td^mp+?7NsBYgG${ut=XxN`5d%i36J zsC%V0*5Vgn_O&gg5;(?rLx0k1!p5H2x387}95-m)9(iC?ol~UML_t2|J zo>V6-4E>C{L9j%J-||!*YpBnguHXEfSxXulp{qN(I3{T%b0c-vPnv4uEwMz+($(2Z zlro&9*=9d|Bgq^!S?3UC z9-`g zOAbokB%6tzOVX}J4q)&LY6ij5o#O6SNa Date: Fri, 8 Mar 2024 13:36:00 +0100 Subject: [PATCH 10/31] PSX_OperationImpl: Reorganize code for no event case This prepares for a future commit where we throw away single events and thus PSX_AnalyzePeaks can result in no events event if we found peaks in PSX_FindPeaks. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 37 +++++++++++++++++-------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 3f899b77dc..8594d19cb6 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -485,11 +485,15 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataFiltOff 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 PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFiltOff, WAVE/Z peakX, WAVE/Z peakY, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) 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 + if(!WaveExists(peakX) || !WaveExists(peakY)) + return 1 + endif + numCrossings = DimSize(peakX, ROWS) for(i = 0; i < numCrossings; i += 1) @@ -549,6 +553,8 @@ static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFilt psxEvent[][%$"Fit result"] = 0 psxEvent[][%tau] = PSX_FitEventDecay(sweepDataFiltOff, psxEvent, maxTauFactor, eventFit, p) + + return 0 End /// @brief Return the x-axis range useful for displaying and extracting a single event @@ -764,6 +770,7 @@ End static Function PSX_OperationImpl(string graph, variable parameterJSONID, string id, variable peakThresh, variable maxTauFactor, WAVE riseTimeParams, variable kernelAmp, variable index, WAVE/WAVE output) string comboKey, key, psxOperationKey, psxParametersEvents + variable ret key = PSX_GenerateKey("sweepData", index) WAVE sweepData = output[%$key] @@ -790,6 +797,23 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string else [WAVE peakX, WAVE peakY] = PSX_FindPeaks(sweepDataFiltOffDeconv, peakThresh) + if(WaveExists(peakX) && WaveExists(peakY)) + WAVE psxEvent = GetPSXEventWaveAsFree() + 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)) + + ret = PSX_AnalyzePeaks(sweepDataFiltOffDeconv, sweepDataFiltOff, peakX, peakY, maxTauFactor, kernelAmp, psxEvent, eventFit) + + if(ret) + WaveClear peakX, peakY + endif + endif + if(!WaveExists(peakX) || !WaveExists(peakY)) // clear entries from this combo key = PSX_GenerateKey("sweepData", index) @@ -807,17 +831,6 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string return 1 endif - WAVE psxEvent = GetPSXEventWaveAsFree() - JWN_SetWaveNoteFromJSON(psxEvent, parameterJsonID, release = 0) - - WAVE eventFit = GetPSXEventFitWaveAsFree() - - 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) - Make/FREE/WAVE/N=(4) psxOperation SetDimensionLabels(psxOperation, "peakX;peakY;psxEvent;eventFit", ROWS) psxOperation[%peakX] = peakX From 6eed925da52b1d12a133536a53635dcf81e6f552 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 31 Jul 2024 16:24:51 +0200 Subject: [PATCH 11/31] PSX_AnalyzePeaks: Factor out calculation of various event properties In a future commit we want to reuse these calculations for event filtering. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 86 ++++++++++++++----------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 8594d19cb6..76234948b4 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -484,11 +484,49 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataFiltOff return [peakX, peakY] End +static Function [variable post_min, variable post_min_t, variable pre_max, variable pre_max_t, variable rel_peak] PSX_CalculateEventProperties(WAVE peakX, WAVE peakY, WAVE sweepDataFiltOff, variable index, variable kernelAmp) + + variable numCrossings, i_time, peak, peak_end_search + + numCrossings = DimSize(peakX, ROWS) + + i_time = peakX[index] + peak = peakY[index] + + if(index < numCrossings - 1) + peak_end_search = min(i_time + PSX_DEFAULT_PEAK_SEARCH_RANGE_MS, peakX[index + 1]) + else + peak_end_search = i_time + PSX_DEFAULT_PEAK_SEARCH_RANGE_MS + endif + + WaveStats/M=1/Q/R=(i_time, peak_end_search) sweepDataFiltOff + + 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") + 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 + + rel_peak = post_min - pre_max + + return [post_min, post_min_t, pre_max, pre_max_t, rel_peak] +End + /// @brief Analyze the peaks static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFiltOff, WAVE/Z peakX, WAVE/Z peakY, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) - 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 i, i_time, peak, isi, post_min, post_min_t, pre_max, pre_max_t, numCrossings, rel_peak if(!WaveExists(peakX) || !WaveExists(peakY)) return 1 @@ -500,49 +538,25 @@ static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFilt i_time = peakX[i] peak = peakY[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 - - WaveStats/M=1/Q/R=(i_time, peak_end_search) sweepDataFiltOff - - 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") - endif + [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakX, peakY, sweepDataFiltOff, i, kernelAmp) EnsureLargeEnoughWave(psxEvent, indexShouldExist = i) - psxEvent[i][%post_min] = post_min - psxEvent[i][%post_min_t] = post_min_t - if(i == 0) isi = NaN else isi = i_time - 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][%peak_t] = i_time + psxEvent[i][%peak] = peak + psxEvent[i][%post_min] = post_min + psxEvent[i][%post_min_t] = post_min_t + psxEvent[i][%pre_max] = pre_max + psxEvent[i][%pre_max_t] = pre_max_t + psxEvent[i][%rel_peak] = rel_peak + psxEvent[i][%isi] = isi endfor Redimension/N=(i, -1) eventFit, psxEvent From eaaf57d50e4438fcfc8915f69ece4ca2aeac5a26 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 31 Jul 2024 17:11:54 +0200 Subject: [PATCH 12/31] PSX_AnalyzePeaks: Skip superfluous redimension calls We know how many entries in psxEvent and eventFit we have before starting the loop so we can just call Redimension before and are done. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 76234948b4..ccd2d3a493 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -533,6 +533,8 @@ static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFilt endif numCrossings = DimSize(peakX, ROWS) + Redimension/N=(numCrossings, -1) psxEvent, eventFit + for(i = 0; i < numCrossings; i += 1) i_time = peakX[i] @@ -540,8 +542,6 @@ static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFilt [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakX, peakY, sweepDataFiltOff, i, kernelAmp) - EnsureLargeEnoughWave(psxEvent, indexShouldExist = i) - if(i == 0) isi = NaN else @@ -559,8 +559,6 @@ static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFilt psxEvent[i][%isi] = isi endfor - Redimension/N=(i, -1) eventFit, psxEvent - // safe defaults psxEvent[][%$"Event manual QC call"] = PSX_UNDET psxEvent[][%$"Fit manual QC call"] = PSX_UNDET From c768a0b228f24cf8b630c78ebbc0c7e8c912eaac Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 8 Mar 2024 16:24:20 +0100 Subject: [PATCH 13/31] PSX_AnalyzePeaks: Throw away events with different sign as the kernel amplitude We need to filter that out first as we need the neighbouring distance to the passing events. And we also have to introduce an override setting as otherwise the tests don't pass. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 83 +++++++++++--- Packages/tests/Basic/UTF_SweepFormula_PSX.ipf | 105 +++++++++++++++--- 2 files changed, 159 insertions(+), 29 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index ccd2d3a493..cc9f378b9a 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -484,6 +484,58 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataFiltOff return [peakX, peakY] End +static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, WAVE sweepDataFiltOff, variable kernelAmp, WAVE psxEvent) + + variable numCrossings, idx, i + variable post_min, post_min_t, pre_max, pre_max_t, rel_peak + variable overrideSignQC = NaN + string comboKey + + if(!WaveExists(peakXUnfiltered) || !WaveExists(peakYUnfiltered)) + return [$"", $""] + endif + + numCrossings = DimSize(peakXUnfiltered, ROWS) + + Make/FREE/D/N=(numCrossings) peakX, peakY + + for(i = 0; i < numCrossings; i += 1) + + [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakXUnfiltered, peakYUnfiltered, sweepDataFiltOff, i, kernelAmp) + +#ifdef AUTOMATED_TESTING + WAVE/Z overrideResults = GetOverrideResults() + + if(WaveExists(overrideResults)) + comboKey = JWN_GetStringFromWaveNote(psxEvent, PSX_EVENTS_COMBO_KEY_WAVE_NOTE) + + overrideSignQC = overrideResults[i][%$comboKey][%KernelAmpSignQC] + endif +#endif + + if(IsNaN(overrideSignQC)) + if(sign(rel_peak) != 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 post_min, variable post_min_t, variable pre_max, variable pre_max_t, variable rel_peak] PSX_CalculateEventProperties(WAVE peakX, WAVE peakY, WAVE sweepDataFiltOff, variable index, variable kernelAmp) variable numCrossings, i_time, peak, peak_end_search @@ -524,12 +576,20 @@ static Function [variable post_min, variable post_min_t, variable pre_max, varia End /// @brief Analyze the peaks -static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFiltOff, WAVE/Z peakX, WAVE/Z peakY, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) +static Function [WAVE peakX, WAVE peakY] PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFiltOff, WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) variable i, i_time, peak, isi, post_min, post_min_t, pre_max, pre_max_t, numCrossings, rel_peak + // 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, sweepDataFiltOff, kernelAmp, psxEvent) + WaveClear peakXUnfiltered, peakYUnfiltered + if(!WaveExists(peakX) || !WaveExists(peakY)) - return 1 + Redimension/N=(0, -1) psxEvent, eventFit + + return [$"", $""] endif numCrossings = DimSize(peakX, ROWS) @@ -566,7 +626,7 @@ static Function PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFilt psxEvent[][%tau] = PSX_FitEventDecay(sweepDataFiltOff, psxEvent, maxTauFactor, eventFit, p) - return 0 + return [peakX, peakY] End /// @brief Return the x-axis range useful for displaying and extracting a single event @@ -700,7 +760,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 @@ -709,9 +770,9 @@ 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 @@ -807,9 +868,9 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string WAVE psxEvent = psxOperationFromCache[%psxEvent] WAVE eventFit = psxOperationFromCache[%eventFit] else - [WAVE peakX, WAVE peakY] = PSX_FindPeaks(sweepDataFiltOffDeconv, peakThresh) + [WAVE peakXUnfiltered, WAVE peakYUnfiltered] = PSX_FindPeaks(sweepDataFiltOffDeconv, peakThresh) - if(WaveExists(peakX) && WaveExists(peakY)) + if(WaveExists(peakXUnfiltered) && WaveExists(peakYUnfiltered)) WAVE psxEvent = GetPSXEventWaveAsFree() WAVE eventFit = GetPSXEventFitWaveAsFree() @@ -819,11 +880,7 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string JWN_SetStringInWaveNote(psxEvent, PSX_X_DATA_UNIT, WaveUnits(sweepData, ROWS)) JWN_SetStringInWaveNote(psxEvent, PSX_Y_DATA_UNIT, WaveUnits(sweepData, -1)) - ret = PSX_AnalyzePeaks(sweepDataFiltOffDeconv, sweepDataFiltOff, peakX, peakY, maxTauFactor, kernelAmp, psxEvent, eventFit) - - if(ret) - WaveClear peakX, peakY - endif + [WAVE peakX, WAVE peakY] = PSX_AnalyzePeaks(sweepDataFiltOffDeconv, sweepDataFiltOff, peakXUnfiltered, peakYUnfiltered, maxTauFactor, kernelAmp, psxEvent, eventFit) endif if(!WaveExists(peakX) || !WaveExists(peakY)) diff --git a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index 8594f2b8af..78d5d01f4d 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -1390,7 +1390,8 @@ 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[][][%$"KernelAmpSignQC"] = 1 [win, device] = CreateEmptyUnlockedDataBrowserWindow() @@ -1450,6 +1451,16 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) catch CHECK_NO_RTE() endtry + + // complains without events found due to kernelAmp sign + overrideResults[][][%$"KernelAmpSignQC"] = 0 + str = "psx(id, psxKernel([50, 150], select(channels(AD6), [0, 2], all), 1, 15, -4))" + try + WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) + FAIL() + catch + PASS() + endtry End static Function PSXHandlesPartialResults() @@ -1469,7 +1480,8 @@ static Function PSXHandlesPartialResults() WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) // all decay fits are successfull - overrideResults[][][%$"Fit Result"] = 1 + 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) @@ -1488,8 +1500,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() @@ -1585,8 +1598,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)) @@ -1746,8 +1760,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 @@ -1844,6 +1859,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") @@ -1988,6 +2005,14 @@ static Function AllEventGraph([STRUCT IUTF_mData &m]) string browser, code, extAllGraph, win, trace, info, rgbValue, mainWindow, specialEventPanel variable numEvents + Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ + "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = m.s0 @@ -2190,6 +2215,12 @@ static Function JumpToUndet() string browser, code, psxGraph, win, mainWindow + Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ + "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = GetTestCode("nothing") @@ -2249,6 +2280,12 @@ static Function JumpToSelectedEvents([STRUCT IUTF_mData &m]) string browser, code, psxGraph, win, mainWindow, postProc, psxStatsGraph variable logMode + Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ + "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 + postProc = m.s0 logMode = m.v0 @@ -2309,6 +2346,12 @@ static Function CursorMovement() string browser, code, psxGraph, win, mainWindow + Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ + "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = GetTestCode("nothing") @@ -2342,6 +2385,12 @@ static Function CursorMovementStats() string browser, code, psxGraph, win, mainWindow, psxStatsGraph, trace, tracenames + Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ + "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = GetTestCode("nothing") @@ -2401,8 +2450,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() @@ -2620,8 +2670,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() @@ -2850,8 +2901,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() @@ -2927,6 +2979,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") @@ -2992,6 +3046,12 @@ static Function CheckResultsWavesForAverageFitResult() string browser, code, psxGraph, win, mainWindow, specialEventPanel, name, entry + Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ + "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = GetTestCode("nothing") @@ -3028,6 +3088,12 @@ static Function TestBlockIndexLogic() string browser, code, psxGraph, win, mainWindow, specialEventPanel, extAllGraph + Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ + "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 + browser = SetupDatabrowserWithSomeData() code = GetTestCode("nothing") @@ -3241,6 +3307,12 @@ static Function TestOperationPrep() string win, device, code, psxCode + Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ + "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + WAVE overrideResults = MIES_PSX#PSX_CreateOverrideResults(4, combos) + + overrideResults[][][%$"KernelAmpSignQC"] = 1 + [win, device] = CreateEmptyUnlockedDataBrowserWindow() win = CreateFakeSweepData(win, device, sweepNo = 0, sweepGen = FakeSweepDataGeneratorPSX) @@ -3291,8 +3363,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() From 42f8ea00ccfbf5ba5bad12a599198f41b5a792ad Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 4 Sep 2024 18:23:24 +0200 Subject: [PATCH 14/31] PSX_CalculateRiseTime: Multithread the calculation --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index cc9f378b9a..84a723e6cb 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -1555,14 +1555,15 @@ static Function/WAVE PSX_CalculateRiseTime(WAVE psxEvent, WAVE sweepDataFiltOff, Make/D/FREE/N=(numEvents) riseTime - riseTime[] = PSX_CalculateRiseTimeImpl(psxEvent, sweepDataFiltOff, kernelAmp, psxEvent[p][%index], lowerThreshold, upperThreshold) + Multithread 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_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataFiltOff, variable kernelAmp, variable index, variable lowerThreshold, variable upperThreshold) variable dY, xStart, xEnd, yStart, yEnd, xlt, xupt, lowerLevel, upperLevel, riseTime variable printDebug @@ -1599,7 +1600,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 From 52076cbbc320e67138aaff466a577fff4972b786 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Thu, 6 Jun 2024 00:08:52 +0200 Subject: [PATCH 15/31] PSX_GetSingleEventRange: Make the offset dependent on tau We only use the fixed value in case tau is NaN. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 84a723e6cb..8ad971570f 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -64,6 +64,7 @@ static Constant PSX_NUM_PEAKS_MAX = 2000 static Constant PSX_PLOT_DEFAULT_X_RANGE = 200 static Constant PSX_DEFAULT_X_START_OFFSET = 2 +static Constant PSX_DEFAULT_RANGE_FACTOR = 3 static StrConstant USER_DATA_KEYBOARD_DIR = "keyboard_direction" @@ -632,17 +633,23 @@ 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) - variable numEvents + variable numEvents, offset numEvents = DimSize(psxEvent, ROWS) index = limit(index, 0, numEvents - 1) + offset = PSX_DEFAULT_RANGE_FACTOR * psxEvent[index][%tau] + + if(IsNaN(offset)) + offset = PSX_DEFAULT_X_START_OFFSET + 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 + first = psxEvent[index][%peak_t] - offset + last = psxEvent[index][%post_min_t] + offset else - first = psxEvent[index][%peak_t] - PSX_DEFAULT_X_START_OFFSET + first = psxEvent[index][%peak_t] - offset last = psxEvent[index + 1][%peak_t] - 0.5 endif From 3fcec4357b455a0eab9ff06562c1ad0df1d586c4 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 18 Jun 2024 21:01:15 +0200 Subject: [PATCH 16/31] PSX_UpdateSingleEventGraph: Check passed index We can be called from PSX_PlotInteractionHook where we don't know if the passed index is valid. Let's do nothing if the index is out of range. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 8ad971570f..9c2f178415 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -1746,6 +1746,12 @@ 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) From eb98115826971937ecf8c02867770f9b12745b9c Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 4 Sep 2024 15:25:55 +0200 Subject: [PATCH 17/31] SF_PreparePlotter: Remove controls/draw elements on existing panels In dc9ed87e4 (SF_PreparePlotter: Don't kill and recreate the main panel for SF_DM_SUBWINDOWS, 2024-06-19) we switched from killing the sweepformula plot to clearing it. But we forgot to remove additional controls and draw elements added by e.g. PSX. And now we also have to explicitly remove TraceUserData (TUD) as these are not cleaned up automatically anymore, as killing an embedded subwindow does not trigger the main window hook. --- Packages/MIES/MIES_SweepFormula.ipf | 5 +++++ Packages/MIES/MIES_Utilities_GUI.ipf | 24 +++++++++++++++++++++ Packages/tests/Basic/UTF_Utils_GUI.ipf | 30 ++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/Packages/MIES/MIES_SweepFormula.ipf b/Packages/MIES/MIES_SweepFormula.ipf index e951a0afcd..45b8f582e9 100644 --- a/Packages/MIES/MIES_SweepFormula.ipf +++ b/Packages/MIES/MIES_SweepFormula.ipf @@ -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 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/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 From 76bb9fb8085225e115ddb3afa449e977b894f1d8 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 4 Sep 2024 15:39:20 +0200 Subject: [PATCH 18/31] PSX_ApplyMacroToExistingPanel: Make it static --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 9c2f178415..90428480c0 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -5352,7 +5352,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 From 450c2747069bbc05fc904a9e9eb7fdb1766e38f2 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 4 Sep 2024 15:39:42 +0200 Subject: [PATCH 19/31] PSX_ApplyMacroToExistingPanel: Fix execution Due to the changed window handling in dc9ed87e4 (SF_PreparePlotter: Don't kill and recreate the main panel for SF_DM_SUBWINDOWS, 2024-06-19) we need to ensure that the host window of the SF panel is active. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 90428480c0..001eaa9f4f 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -5378,7 +5378,8 @@ static Function PSX_ApplyMacroToExistingPanel(string win, string mac) macroCode[Inf] = "" currWindow = GetCurrentWindow() - SetActiveSubwindow $win + DoWindow/F $win + SetActiveSubwindow ## for(line : macroCode) if(IsEmpty(line)) From a795222922887d27af0f25224af6e8229d5e82a0 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 4 Sep 2024 19:02:09 +0200 Subject: [PATCH 20/31] DeepCopyWaveRefWave: Fix assertion message --- Packages/MIES/MIES_Utilities_WaveHandling.ipf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_Utilities_WaveHandling.ipf b/Packages/MIES/MIES_Utilities_WaveHandling.ipf index f34d05100f..d065771a2e 100644 --- a/Packages/MIES/MIES_Utilities_WaveHandling.ipf +++ b/Packages/MIES/MIES_Utilities_WaveHandling.ipf @@ -544,7 +544,7 @@ 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)) + ASSERT_TS(WaveExists(srcWave), "Missing wave at linear index: " + num2str(i)) if(!ParamIsDefault(indexWave)) index = indexWave[i] From 2b8c2b1af6c6b4d79c845cb052e03ee9b2ad40a1 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 6 Sep 2024 16:48:53 +0200 Subject: [PATCH 21/31] DeepCopyWaveRefWave: Allow src to contain null waves This makes it easier to use and is more according to our philosopy that null wave refs should be preferred over empty waves. --- Packages/MIES/MIES_Utilities_WaveHandling.ipf | 7 +++++-- .../tests/Basic/UTF_Utils_WaveHandling.ipf | 18 ++++++------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Packages/MIES/MIES_Utilities_WaveHandling.ipf b/Packages/MIES/MIES_Utilities_WaveHandling.ipf index d065771a2e..2b2858e338 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,7 +544,10 @@ 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(!WaveExists(srcWave)) + continue + endif if(!ParamIsDefault(indexWave)) index = indexWave[i] 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 From db5632b32b332dee261495fca0433c96a95fc817 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 6 Sep 2024 16:50:03 +0200 Subject: [PATCH 22/31] DeepCopyWaveRefWave: Nicify the code We only need index in the else branch and some more spaces are nice. --- Packages/MIES/MIES_Utilities_WaveHandling.ipf | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Packages/MIES/MIES_Utilities_WaveHandling.ipf b/Packages/MIES/MIES_Utilities_WaveHandling.ipf index 2b2858e338..e220801862 100644 --- a/Packages/MIES/MIES_Utilities_WaveHandling.ipf +++ b/Packages/MIES/MIES_Utilities_WaveHandling.ipf @@ -549,13 +549,13 @@ threadsafe Function/WAVE DeepCopyWaveRefWave(WAVE/WAVE src, [variable dimension, continue endif - if(!ParamIsDefault(indexWave)) - index = indexWave[i] - 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 @@ -570,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 From 61b0cdc35a318193239eb4747a34c5add5d5567f Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 4 Sep 2024 21:25:50 +0200 Subject: [PATCH 23/31] PSX_OperationImpl: Always return a result Using psxPrep requires sweep data from psx. But we used to only return sweep data if we have found events. We now always return sweep data so that psxPrep always works. --- Packages/MIES/MIES_SweepFormula_PSX.ipf | 87 ++++++------------- Packages/tests/Basic/UTF_SweepFormula_PSX.ipf | 24 +++-- 2 files changed, 38 insertions(+), 73 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 001eaa9f4f..66952d3e81 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -577,7 +577,7 @@ static Function [variable post_min, variable post_min_t, variable pre_max, varia End /// @brief Analyze the peaks -static Function [WAVE peakX, WAVE peakY] PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFiltOff, WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) +static Function [WAVE/D peakX, WAVE/D peakY] PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFiltOff, WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) variable i, i_time, peak, isi, post_min, post_min_t, pre_max, pre_max_t, numCrossings, rel_peak @@ -845,12 +845,9 @@ static Function PSX_OperationSweepGathering(string graph, WAVE/WAVE psxKernelDat 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) string comboKey, key, psxOperationKey, psxParametersEvents - variable ret key = PSX_GenerateKey("sweepData", index) WAVE sweepData = output[%$key] @@ -870,42 +867,23 @@ 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 peakXUnfiltered, WAVE peakYUnfiltered] = PSX_FindPeaks(sweepDataFiltOffDeconv, peakThresh) - if(WaveExists(peakXUnfiltered) && WaveExists(peakYUnfiltered)) - WAVE psxEvent = GetPSXEventWaveAsFree() - WAVE eventFit = GetPSXEventFitWaveAsFree() - - JWN_SetWaveNoteFromJSON(psxEvent, parameterJsonID, release = 0) + WAVE psxEvent = GetPSXEventWaveAsFree() + WAVE eventFit = GetPSXEventFitWaveAsFree() - 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)) - - [WAVE peakX, WAVE peakY] = PSX_AnalyzePeaks(sweepDataFiltOffDeconv, sweepDataFiltOff, peakXUnfiltered, peakYUnfiltered, maxTauFactor, kernelAmp, psxEvent, eventFit) - endif + JWN_SetWaveNoteFromJSON(psxEvent, parameterJsonID, release = 0) - if(!WaveExists(peakX) || !WaveExists(peakY)) - // clear entries from this combo - key = PSX_GenerateKey("sweepData", index) - output[%$key] = $"" + 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)) - 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 peakX, WAVE peakY] = PSX_AnalyzePeaks(sweepDataFiltOffDeconv, sweepDataFiltOff, peakXUnfiltered, peakYUnfiltered, maxTauFactor, kernelAmp, psxEvent, eventFit) Make/FREE/WAVE/N=(4) psxOperation SetDimensionLabels(psxOperation, "peakX;peakY;psxEvent;eventFit", ROWS) @@ -917,6 +895,13 @@ 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)) @@ -932,12 +917,14 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string endif endif - UpgradePSXEventWave(psxEvent) + if(WaveExists(psxEvent)) + 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 + 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 + endif key = PSX_GenerateKey("peakX", index) output[%$key] = peakX @@ -950,8 +937,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 @@ -4361,7 +4346,7 @@ End Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) variable numberOfSDs, sweepFilterLow, sweepFilterHigh, parameterJsonID, numCombos, i, addedData, kernelAmp - variable maxTauFactor, peakThresh, numFailures, idx, success + variable maxTauFactor, peakThresh, idx, success string parameterPath, id, psxParameters, dataUnit id = SFH_GetArgumentAsText(jsonID, jsonPath, graph, SF_OP_PSX, 0, checkFunc = IsValidObjectName) @@ -4426,24 +4411,8 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) 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, i, output) endfor - - if(numFailures > 0) - // remove null waves - WAVE/Z outputClean = ZapNullRefs(output) - - if(!WaveExists(outputClean)) - Abort - endif - - WAVE outputNew = MoveWaveWithOverwrite(output, outputClean) - WAVE output = outputNew - WaveClear outputClean, outputNew - - numCombos = DimSize(output, ROWS) / PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY - PSX_OperationSetDimensionLabels(output, numCombos, labels, labelsTemplate) - endif catch if(WaveExists(output)) SFH_CleanUpInput(output) diff --git a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index 78d5d01f4d..9c1d90ebd1 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -1434,14 +1434,12 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) CHECK_NO_RTE() CHECK_WAVE(dataWref, WAVE_WAVE) - // complains without events found + // without events found we get empty waves str = "psx(myID, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([0, 2]), selvis(all)), 5000, 15, -5), 25, 100, 0)" - try - WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) - FAIL() - catch - PASS() - endtry + 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 @@ -1452,15 +1450,13 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) CHECK_NO_RTE() endtry - // complains without events found due to kernelAmp sign + // returns empty waves without events found due to kernelAmp sign overrideResults[][][%$"KernelAmpSignQC"] = 0 str = "psx(id, psxKernel([50, 150], select(channels(AD6), [0, 2], all), 1, 15, -4))" - try - WAVE/WAVE dataWref = SF_ExecuteFormula(str, win, useVariables = 0) - FAIL() - catch - PASS() - endtry + 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() From ea1bb49a2c51d2791b02e38246a2cc8b952dcdf8 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 4 Sep 2024 22:31:53 +0200 Subject: [PATCH 24/31] PSX: Change order of offsetting and filtering We now first offset and then filter. This requires that we also rename all variables, constants and dimension labels. Change requested by Tim Jarsky. --- Packages/MIES/MIES_Cache.ipf | 10 +- Packages/MIES/MIES_SweepFormula_PSX.ipf | 186 +++++++++--------- Packages/MIES/MIES_WaveDataFolderGetters.ipf | 8 +- Packages/tests/Basic/UTF_SweepFormula_PSX.ipf | 16 +- 4 files changed, 110 insertions(+), 110 deletions(-) diff --git a/Packages/MIES/MIES_Cache.ipf b/Packages/MIES/MIES_Cache.ipf index 4e54e79c87..8264c05d8a 100644 --- a/Packages/MIES/MIES_Cache.ipf +++ b/Packages/MIES/MIES_Cache.ipf @@ -415,7 +415,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 +433,22 @@ 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" + return CA_PSXBaseKey(comboKey, psxParameters) + " Operation " + ":Version 2" End Function/S CA_PSXRiseTimeKey(string comboKey, string psxParameters) - return CA_PSXBaseKey(comboKey, psxParameters) + " PSX Rise time " + ":Version 1" + return CA_PSXBaseKey(comboKey, psxParameters) + " PSX Rise time " + ":Version 2" 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_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 66952d3e81..473f9e5d00 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -73,7 +73,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 @@ -416,26 +416,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 +443,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 +452,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,7 +485,7 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataFiltOff return [peakX, peakY] End -static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, WAVE sweepDataFiltOff, variable kernelAmp, WAVE psxEvent) +static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, WAVE sweepDataOffFilt, variable kernelAmp, WAVE psxEvent) variable numCrossings, idx, i variable post_min, post_min_t, pre_max, pre_max_t, rel_peak @@ -502,7 +502,7 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/ for(i = 0; i < numCrossings; i += 1) - [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakXUnfiltered, peakYUnfiltered, sweepDataFiltOff, i, kernelAmp) + [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakXUnfiltered, peakYUnfiltered, sweepDataOffFilt, i, kernelAmp) #ifdef AUTOMATED_TESTING WAVE/Z overrideResults = GetOverrideResults() @@ -537,7 +537,7 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/ return [peakX, peakY] End -static Function [variable post_min, variable post_min_t, variable pre_max, variable pre_max_t, variable rel_peak] PSX_CalculateEventProperties(WAVE peakX, WAVE peakY, WAVE sweepDataFiltOff, variable index, variable kernelAmp) +static Function [variable post_min, variable post_min_t, variable pre_max, variable pre_max_t, variable rel_peak] PSX_CalculateEventProperties(WAVE peakX, WAVE peakY, WAVE sweepDataOffFilt, variable index, variable kernelAmp) variable numCrossings, i_time, peak, peak_end_search @@ -552,7 +552,7 @@ static Function [variable post_min, variable post_min_t, variable pre_max, varia peak_end_search = i_time + PSX_DEFAULT_PEAK_SEARCH_RANGE_MS endif - WaveStats/M=1/Q/R=(i_time, peak_end_search) sweepDataFiltOff + WaveStats/M=1/Q/R=(i_time, peak_end_search) sweepDataOffFilt if(kernelAmp > 0) post_min = V_max @@ -564,11 +564,11 @@ static Function [variable post_min, variable post_min_t, variable pre_max, varia ASSERT(0, "Can't handle kernelAmp of zero") endif - WaveStats/Q/R=(i_time - 2, i_time) sweepDataFiltOff + WaveStats/Q/R=(i_time - 2, i_time) sweepDataOffFilt pre_max = V_max pre_max_t = V_maxloc - WaveStats/Q/R=(pre_max_t - 0.1, pre_max_t + 0.1) sweepDataFiltOff + WaveStats/Q/R=(pre_max_t - 0.1, pre_max_t + 0.1) sweepDataOffFilt pre_max = V_avg rel_peak = post_min - pre_max @@ -577,14 +577,14 @@ static Function [variable post_min, variable post_min_t, variable pre_max, varia End /// @brief Analyze the peaks -static Function [WAVE/D peakX, WAVE/D peakY] PSX_AnalyzePeaks(WAVE sweepDataFiltOffDeconv, WAVE sweepDataFiltOff, WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) +static Function [WAVE/D peakX, WAVE/D peakY] PSX_AnalyzePeaks(WAVE sweepDataOffFiltDeconv, WAVE sweepDataOffFilt, WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) variable i, i_time, peak, isi, post_min, post_min_t, pre_max, pre_max_t, numCrossings, rel_peak // 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, sweepDataFiltOff, kernelAmp, psxEvent) + [WAVE peakX, WAVE peakY] = PSX_FilterEventsKernelAmpSign(peakXUnfiltered, peakYUnfiltered, sweepDataOffFilt, kernelAmp, psxEvent) WaveClear peakXUnfiltered, peakYUnfiltered if(!WaveExists(peakX) || !WaveExists(peakY)) @@ -601,7 +601,7 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_AnalyzePeaks(WAVE sweepDataFilt i_time = peakX[i] peak = peakY[i] - [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakX, peakY, sweepDataFiltOff, i, kernelAmp) + [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakX, peakY, sweepDataOffFilt, i, kernelAmp) if(i == 0) isi = NaN @@ -625,7 +625,7 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_AnalyzePeaks(WAVE sweepDataFilt psxEvent[][%$"Fit manual QC call"] = PSX_UNDET psxEvent[][%$"Fit result"] = 0 - psxEvent[][%tau] = PSX_FitEventDecay(sweepDataFiltOff, psxEvent, maxTauFactor, eventFit, p) + psxEvent[][%tau] = PSX_FitEventDecay(sweepDataOffFilt, psxEvent, maxTauFactor, eventFit, p) return [peakX, peakY] End @@ -659,7 +659,7 @@ 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 @@ -677,7 +677,7 @@ static Function [variable start, variable stop] PSX_GetEventFitRange(WAVE sweepD 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") @@ -692,12 +692,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 string comboKey - [post_min_t, n_min_t] = PSX_GetEventFitRange(sweepDataFiltOff, psxEvent, eventIndex) + [post_min_t, n_min_t] = PSX_GetEventFitRange(sweepDataOffFilt, psxEvent, eventIndex) DFREF currDFR = GetDataFolderDFR() SetDataFolder NewFreeDataFolder() @@ -708,7 +708,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(post_min_t, n_min_t)/D/C=constraints; err = GetRTError(1) WAVE fit = MakeWaveFree($"fit__free_") @@ -811,18 +811,18 @@ static Function PSX_OperationSweepGathering(string graph, WAVE/WAVE psxKernelDat return 1 endif - WAVE sweepDataFiltOff = psxAnalyzePeaksFromCache[%sweepDataFiltOff] - WAVE sweepDataFiltOffDeconv = psxAnalyzePeaksFromCache[%sweepDataFiltOffDeconv] + 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) - if(!WaveExists(sweepDataFiltOff) || !WaveExists(sweepDataFiltOffDeconv)) + if(!WaveExists(sweepDataOffFilt) || !WaveExists(sweepDataOffFiltDeconv)) Make/FREE/WAVE/N=(0) psxAnalyzePeaks else Make/FREE/WAVE/N=(2) psxAnalyzePeaks - SetDimensionLabels(psxAnalyzePeaks, "sweepDataFiltOff;sweepDataFiltOffDeconv", ROWS) - psxAnalyzePeaks[%sweepDataFiltOff] = sweepDataFiltOff - psxAnalyzePeaks[%sweepDataFiltOffDeconv] = sweepDataFiltOffDeconv + SetDimensionLabels(psxAnalyzePeaks, "sweepDataOffFilt;sweepDataOffFiltDeconv", ROWS) + psxAnalyzePeaks[%sweepDataOffFilt] = sweepDataOffFilt + psxAnalyzePeaks[%sweepDataOffFiltDeconv] = sweepDataOffFiltDeconv endif CA_StoreEntryIntoCache(cacheKey, psxAnalyzePeaks) @@ -835,11 +835,11 @@ static Function PSX_OperationSweepGathering(string graph, WAVE/WAVE psxKernelDat 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("sweepDataFiltOffDeconv", index) - output[%$key] = sweepDataFiltOffDeconv + key = PSX_GenerateKey("sweepDataOffFiltDeconv", index) + output[%$key] = sweepDataOffFiltDeconv return 0 End @@ -852,11 +852,11 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string key = PSX_GenerateKey("sweepData", index) WAVE sweepData = output[%$key] - key = PSX_GenerateKey("sweepDataFiltOff", index) - WAVE sweepDataFiltOff = output[%$key] + key = PSX_GenerateKey("sweepDataOffFilt", index) + WAVE sweepDataOffFilt = output[%$key] - key = PSX_GenerateKey("sweepDataFiltOffDeconv", index) - WAVE sweepDataFiltOffDeconv = output[%$key] + 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") @@ -872,7 +872,7 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string WAVE/Z psxEvent = psxOperationFromCache[%psxEvent] WAVE/Z eventFit = psxOperationFromCache[%eventFit] else - [WAVE peakXUnfiltered, WAVE peakYUnfiltered] = PSX_FindPeaks(sweepDataFiltOffDeconv, peakThresh) + [WAVE peakXUnfiltered, WAVE peakYUnfiltered] = PSX_FindPeaks(sweepDataOffFiltDeconv, peakThresh) WAVE psxEvent = GetPSXEventWaveAsFree() WAVE eventFit = GetPSXEventFitWaveAsFree() @@ -883,7 +883,7 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string JWN_SetStringInWaveNote(psxEvent, PSX_X_DATA_UNIT, WaveUnits(sweepData, ROWS)) JWN_SetStringInWaveNote(psxEvent, PSX_Y_DATA_UNIT, WaveUnits(sweepData, -1)) - [WAVE peakX, WAVE peakY] = PSX_AnalyzePeaks(sweepDataFiltOffDeconv, sweepDataFiltOff, peakXUnfiltered, peakYUnfiltered, maxTauFactor, kernelAmp, psxEvent, eventFit) + [WAVE peakX, WAVE peakY] = PSX_AnalyzePeaks(sweepDataOffFiltDeconv, sweepDataOffFilt, peakXUnfiltered, peakYUnfiltered, maxTauFactor, kernelAmp, psxEvent, eventFit) Make/FREE/WAVE/N=(4) psxOperation SetDimensionLabels(psxOperation, "peakX;peakY;psxEvent;eventFit", ROWS) @@ -920,7 +920,7 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string if(WaveExists(psxEvent)) UpgradePSXEventWave(psxEvent) - WAVE riseTime = PSX_CalculateRiseTime(psxEvent, sweepDataFiltOff, parameterJsonID, kernelAmp, riseTimeParams[%$"Lower Threshold"], riseTimeParams[%$"Upper Threshold"]) + WAVE riseTime = PSX_CalculateRiseTime(psxEvent, sweepDataOffFilt, 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 @@ -1528,7 +1528,7 @@ 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) +static Function/WAVE PSX_CalculateRiseTime(WAVE psxEvent, WAVE sweepDataOffFilt, variable parameterJsonID, variable kernelAmp, variable lowerThreshold, variable upperThreshold) string psxParameters, comboKey, cacheKey variable numEvents @@ -1547,7 +1547,7 @@ static Function/WAVE PSX_CalculateRiseTime(WAVE psxEvent, WAVE sweepDataFiltOff, Make/D/FREE/N=(numEvents) riseTime - Multithread riseTime[] = PSX_CalculateRiseTimeImpl(psxEvent, sweepDataFiltOff, kernelAmp, psxEvent[p][%index], \ + Multithread riseTime[] = PSX_CalculateRiseTimeImpl(psxEvent, sweepDataOffFilt, kernelAmp, psxEvent[p][%index], \ lowerThreshold, upperThreshold) CA_StoreEntryIntoCache(cacheKey, riseTime) @@ -1555,14 +1555,14 @@ static Function/WAVE PSX_CalculateRiseTime(WAVE psxEvent, WAVE sweepDataFiltOff, return riseTime End -threadsafe static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataFiltOff, variable kernelAmp, variable index, variable lowerThreshold, variable upperThreshold) +threadsafe static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataOffFilt, variable kernelAmp, variable index, variable lowerThreshold, variable upperThreshold) variable dY, xStart, xEnd, yStart, yEnd, xlt, xupt, lowerLevel, upperLevel, riseTime variable printDebug string comboKey xStart = psxEvent[index][%peak_t] - yStart = sweepDataFiltOff(xStart) + yStart = sweepDataOffFilt(xStart) xEnd = psxEvent[index][%post_min_t] yEnd = psxEvent[index][%post_min] @@ -1576,7 +1576,7 @@ threadsafe static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDa xlt = NaN xupt = NaN - FindLevel/R=(xStart, xEnd)/Q sweepDataFiltOff, lowerLevel + FindLevel/R=(xStart, xEnd)/Q sweepDataOffFilt, lowerLevel if(!V_flag) xlt = V_levelX @@ -1584,7 +1584,7 @@ threadsafe static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDa printDebug = 1 endif - FindLevel/R=(xStart, xEnd)/Q sweepDataFiltOff, upperLevel + FindLevel/R=(xStart, xEnd)/Q sweepDataOffFilt, upperLevel if(!V_flag) xupt = V_levelX @@ -1809,7 +1809,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) @@ -1819,12 +1819,12 @@ static Function PSX_UpdateOffsetInAllEventGraph(string win) [first, last] = PSX_GetSingleEventRange(psxEvent, 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]) + yOffset = sweepDataOffFilt(psxEvent[i][%peak_t]) break case PSX_HORIZ_OFFSET_PEAK: xOffset = first - psxEvent[i][%post_min_t] @@ -2032,7 +2032,7 @@ 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 @@ -2717,8 +2717,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 @@ -3498,13 +3498,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") @@ -3526,7 +3526,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 @@ -3535,7 +3535,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) @@ -3565,8 +3565,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 @@ -3579,7 +3579,7 @@ static Function PSX_CreateSingleEventWaves(DFREF comboDFR, WAVE psxEvent, WAVE s [first, last] = PSX_GetSingleEventRange(psxEvent, i) - Duplicate/FREE/R=(first, last) sweepDataFiltOff, singleEvent + Duplicate/FREE/R=(first, last) sweepDataOffFilt, singleEvent Note/K singleEvent @@ -3660,21 +3660,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) @@ -3705,7 +3705,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 @@ -4017,9 +4017,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) @@ -4334,14 +4334,14 @@ End // 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) @@ -4651,16 +4651,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) + dataUnit = WaveUnits(sweepDataOffFiltDeconv, -1) return [hist, fit, peakThresh, dataUnit] endif @@ -4675,7 +4675,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) @@ -4709,20 +4709,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) diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index 4ef248ae38..bc87b11667 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -8347,14 +8347,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/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index 9c1d90ebd1..a10effa43e 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -1405,8 +1405,8 @@ 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) @@ -1620,7 +1620,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-3, 110, 5e-3 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_ACCEPT, PSX_STATE_EVENT) @@ -1634,7 +1634,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-3, 200, 5e-3 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_REJECT, PSX_STATE_EVENT) @@ -1647,7 +1647,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, 0, 200, 1 SetActiveSubwindow $psxPlot PSX_MouseEventSelection(PSX_REJECT, PSX_STATE_FIT | PSX_STATE_EVENT) @@ -1658,7 +1658,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) @@ -1669,7 +1669,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) @@ -1680,7 +1680,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) From 68b0ff662c30070ae63113c60b21506797637e2c Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 18 Dec 2024 14:22:59 +0100 Subject: [PATCH 25/31] Sweepbrowser: Avoid too old dialog on closing The added reference counting for the sweepbrowser folders in 76cbc803c (AB: Ref count based memory management of loaded DF, 2023-05-10) added a call to BSP_GetFolder with enabled version checking. This resulted in a too old panel dialog when trying to close the panel. Fix it. --- Packages/MIES/MIES_BrowserSettingsPanel.ipf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From bf6e81b02e286fdf8e1c9c4d58e875303fbe8117 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 18 Dec 2024 15:05:08 +0100 Subject: [PATCH 26/31] AB_WindowHook: Save list of files and folders on kill vote This makes closing the panel and reopening it due to an old version message less annoying. --- Packages/MIES/MIES_AnalysisBrowser.ipf | 3 +++ 1 file changed, 3 insertions(+) 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() From 0a8758f90efd39b0b7a0c83059dababc171aaa97 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 17 Dec 2024 22:15:56 +0100 Subject: [PATCH 27/31] PSX: Add panel version In that way we can warn users which have incompatible panels. Same approach as with other MIES panels. --- Packages/MIES/MIES_Constants.ipf | 1 + Packages/MIES/MIES_SweepFormula_PSX.ipf | 27 ++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index 885bd7624b..4671dd96b2 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 diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 473f9e5d00..99564c5037 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -3283,13 +3283,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)) @@ -3648,6 +3651,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) @@ -3914,6 +3919,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. @@ -3930,10 +3942,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) @@ -3962,6 +3976,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 @@ -4032,6 +4047,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") From c695b20a028680b7091706aff9a409df14a4060b Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 18 Dec 2024 23:01:03 +0100 Subject: [PATCH 28/31] SF_GetTraceColor: Add missing /Z --- Packages/MIES/MIES_SweepFormula.ipf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_SweepFormula.ipf b/Packages/MIES/MIES_SweepFormula.ipf index 45b8f582e9..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 From b7e3912b86563b2de598866600bd309e641ba065 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Thu, 19 Dec 2024 12:34:57 +0100 Subject: [PATCH 29/31] SFH_GetArgumentAsText: Don't try to find unique abbreviations for exact matches We need to first check for an exact match before we try unique abbreviations. --- Packages/MIES/MIES_SweepFormula_Helpers.ipf | 42 ++++++++++++--------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/Packages/MIES/MIES_SweepFormula_Helpers.ipf b/Packages/MIES/MIES_SweepFormula_Helpers.ipf index 26543e885c..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 From 7418adb31d90e00a7f36502a1bd98e9cb7a40b91 Mon Sep 17 00:00:00 2001 From: Tim Jarsky Date: Mon, 9 Sep 2024 12:58:07 -0700 Subject: [PATCH 30/31] PSX: Completely overhaul the psx detection algorithm This overhaul makes it impossible to reuse old data, either from the cache, or the results wave. We do warn the user about that. And as usual don't delete the old data. - Gather new values in psxEvent (e.g. Onset Time, Slew Rate and time, ...) and rename entries like post_minXX, pre_maxXX, rel_peak, etc. - Make the calculation clearer and explicitly document where we use the deconvoluated data and where the offsetted and filtered sweep data - Change how we apply the filtering for the deconvoluted and the sweep data - Make the histogram calculation more robust by using a fixed number of bins - To make the code easier to grasp we now also calculate the rise time as part of the other event properties - The extracted single event range now depends on the tau's of all events from that combination - Introduce more constants for magic numbers - Add more properties to display for psxstats - Rework the offsetting in the all events graph and add an entry for slew rate - Change how we calculate the fit range for the accept average fit - Enforce that the decay tau is larger than the rise tau for psxKernel - Add a third parameter to psxRiseTime - Don't round the peak threshold to three digits as this breaks for very small values --- Packages/MIES/MIES_Cache.ipf | 14 +- Packages/MIES/MIES_Constants.ipf | 8 +- Packages/MIES/MIES_SweepFormula_PSX.ipf | 585 ++++++++++----- Packages/MIES/MIES_SweepFormula_PSX_Macro.ipf | 2 +- Packages/MIES/MIES_WaveDataFolderGetters.ipf | 74 +- Packages/MIES/SweepFormulaHelp.ifn | Bin 367648 -> 367918 bytes Packages/doc/SweepFormula.rst | 26 +- Packages/doc/SweepFormula_PSX.rst | 2 +- Packages/tests/Basic/UTF_SweepFormula_PSX.ipf | 684 ++++++++++++------ 9 files changed, 934 insertions(+), 461 deletions(-) diff --git a/Packages/MIES/MIES_Cache.ipf b/Packages/MIES/MIES_Cache.ipf index 8264c05d8a..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. @@ -438,12 +445,7 @@ End Function/S CA_PSXOperationKey(string comboKey, string psxParameters) - return CA_PSXBaseKey(comboKey, psxParameters) + " Operation " + ":Version 2" -End - -Function/S CA_PSXRiseTimeKey(string comboKey, string psxParameters) - - return CA_PSXBaseKey(comboKey, psxParameters) + " PSX Rise time " + ":Version 2" + return CA_PSXBaseKey(comboKey, psxParameters) + " Operation " + ":Version 3" End Function/S CA_PSXAnalyzePeaks(string comboKey, string psxParameters) diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index 4671dd96b2..63d9ab4e95 100644 --- a/Packages/MIES/MIES_Constants.ipf +++ b/Packages/MIES/MIES_Constants.ipf @@ -2033,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 @@ -2348,11 +2349,12 @@ 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" diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 99564c5037..061415e4c8 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -59,12 +59,20 @@ 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 static Constant PSX_DEFAULT_X_START_OFFSET = 2 -static Constant PSX_DEFAULT_RANGE_FACTOR = 3 static StrConstant USER_DATA_KEYBOARD_DIR = "keyboard_direction" @@ -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 @@ -485,10 +496,10 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FindPeaks(WAVE sweepDataOffFilt return [peakX, peakY] End -static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, WAVE sweepDataOffFilt, variable kernelAmp, WAVE psxEvent) +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 numCrossings, idx, i - variable post_min, post_min_t, pre_max, pre_max_t, rel_peak + variable peak, peak_t, baseline, baseline_t, amplitude variable overrideSignQC = NaN string comboKey @@ -502,7 +513,7 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/ for(i = 0; i < numCrossings; i += 1) - [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakXUnfiltered, peakYUnfiltered, sweepDataOffFilt, i, kernelAmp) + [peak, peak_t, baseline, baseline_t, amplitude] = PSX_CalculateEventProperties(peakXUnfiltered, peakYUnfiltered, sweepDataOffFilt, kernelAmp, kernelRiseTau, kernelDecayTau, i) #ifdef AUTOMATED_TESTING WAVE/Z overrideResults = GetOverrideResults() @@ -515,7 +526,7 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/ #endif if(IsNaN(overrideSignQC)) - if(sign(rel_peak) != sign(kernelAmp)) + if(sign(amplitude) != sign(kernelAmp)) continue endif elseif(overrideSignQC == 0) @@ -537,54 +548,88 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_FilterEventsKernelAmpSign(WAVE/ return [peakX, peakY] End -static Function [variable post_min, variable post_min_t, variable pre_max, variable pre_max_t, variable rel_peak] PSX_CalculateEventProperties(WAVE peakX, WAVE peakY, WAVE sweepDataOffFilt, variable index, variable kernelAmp) +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, i_time, peak, peak_end_search + variable numCrossings, deconvPeak_t, prevDeconvPeak_t, nextDeconvPeak_t + variable peak_start_search, peak_end_search numCrossings = DimSize(peakX, ROWS) - i_time = peakX[index] - peak = peakY[index] + 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) + + // upper bound if(index < numCrossings - 1) - peak_end_search = min(i_time + PSX_DEFAULT_PEAK_SEARCH_RANGE_MS, peakX[index + 1]) + nextDeconvPeak_t = peakX[index + 1] else - peak_end_search = i_time + PSX_DEFAULT_PEAK_SEARCH_RANGE_MS + nextDeconvPeak_t = Inf endif - WaveStats/M=1/Q/R=(i_time, peak_end_search) sweepDataOffFilt + 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) - post_min = V_max - post_min_t = V_maxloc + peak = V_max + peak_t = V_maxloc elseif(kernelAmp < 0) - post_min = V_min - post_min_t = V_minloc + peak = V_min + peak_t = V_minloc else ASSERT(0, "Can't handle kernelAmp of zero") endif - WaveStats/Q/R=(i_time - 2, i_time) sweepDataOffFilt - pre_max = V_max - pre_max_t = V_maxloc + return [peak_t, peak] +End + +static Function [variable baseline_t, variable baseline] PSX_CalculateEventBaseline(WAVE sweepDataOffFilt, variable peak_t, variable kernelAmp, variable kernelRiseTau) - WaveStats/Q/R=(pre_max_t - 0.1, pre_max_t + 0.1) sweepDataOffFilt - pre_max = V_avg + variable range - rel_peak = post_min - pre_max + WaveStats/M=1/Q/R=(peak_t - PSX_BASELINE_RANGE_FACTOR * kernelRiseTau, peak_t) sweepDataOffFilt - return [post_min, post_min_t, pre_max, pre_max_t, rel_peak] + 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/Z peakXUnfiltered, WAVE/Z peakYUnfiltered, variable maxTauFactor, variable kernelAmp, WAVE psxEvent, WAVE eventFit) +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, i_time, peak, isi, post_min, post_min_t, pre_max, pre_max_t, numCrossings, rel_peak + 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, psxEvent) + [WAVE peakX, WAVE peakY] = PSX_FilterEventsKernelAmpSign(peakXUnfiltered, peakYUnfiltered, sweepDataOffFilt, kernelAmp, kernelRiseTau, kernelDecayTau, psxEvent) WaveClear peakXUnfiltered, peakYUnfiltered if(!WaveExists(peakX) || !WaveExists(peakY)) @@ -598,26 +643,27 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_AnalyzePeaks(WAVE sweepDataOffF for(i = 0; i < numCrossings; i += 1) - i_time = peakX[i] - peak = peakY[i] + deconvPeak_t = peakX[i] + deconvPeak = peakY[i] - [post_min, post_min_t, pre_max, pre_max_t, rel_peak] = PSX_CalculateEventProperties(peakX, peakY, sweepDataOffFilt, i, kernelAmp) + [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 - psxEvent[i][%index] = i - psxEvent[i][%peak_t] = i_time - psxEvent[i][%peak] = peak - psxEvent[i][%post_min] = post_min - psxEvent[i][%post_min_t] = post_min_t - psxEvent[i][%pre_max] = pre_max - psxEvent[i][%pre_max_t] = pre_max_t - psxEvent[i][%rel_peak] = rel_peak - 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 // safe defaults @@ -625,32 +671,84 @@ static Function [WAVE/D peakX, WAVE/D peakY] PSX_AnalyzePeaks(WAVE sweepDataOffF psxEvent[][%$"Fit manual QC call"] = PSX_UNDET psxEvent[][%$"Fit result"] = 0 + 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, offset + variable numEvents, offset, onset, baseline numEvents = DimSize(psxEvent, ROWS) index = limit(index, 0, numEvents - 1) - offset = PSX_DEFAULT_RANGE_FACTOR * psxEvent[index][%tau] + offset = PSX_GetGoodTau(psxEvent) + + onset = psxEvent[index][%$"Onset Time"] + baseline = psxEvent[index][%baseline_t] - if(IsNaN(offset)) - offset = PSX_DEFAULT_X_START_OFFSET + if(!IsNaN(onset)) + first = min(onset, baseline) + else + first = baseline endif if(index == numEvents - 1) - first = psxEvent[index][%peak_t] - offset - last = psxEvent[index][%post_min_t] + offset + last = min(first + offset, IndexToScale(sweepDataOffFilt, DimSize(sweepDataOffFilt, ROWS) - 1, ROWS)) else - first = psxEvent[index][%peak_t] - offset - last = psxEvent[index + 1][%peak_t] - 0.5 + last = min(first + offset, psxEvent[index + 1][%baseline_t]) endif return [first, last] @@ -663,14 +761,14 @@ static Function [variable start, variable stop] PSX_GetEventFitRange(WAVE sweepD 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) @@ -694,10 +792,10 @@ End /// \endrst 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(sweepDataOffFilt, psxEvent, eventIndex) + [startTime, endTime] = PSX_GetEventFitRange(sweepDataOffFilt, psxEvent, eventIndex) DFREF currDFR = GetDataFolderDFR() SetDataFolder NewFreeDataFolder() @@ -708,7 +806,7 @@ static Function PSX_FitEventDecay(WAVE sweepDataOffFilt, WAVE psxEvent, variable Make/FREE/D/N=3 coefWave AssertOnAndClearRTError() - CurveFit/Q/N=1/NTHR=1/M=0/W=2 exp_XOffset, kwCWave=coefWave, sweepDataOffFilt(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_") @@ -739,7 +837,7 @@ static Function PSX_FitEventDecay(WAVE sweepDataOffFilt, 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 @@ -845,7 +943,7 @@ static Function PSX_OperationSweepGathering(string graph, WAVE/WAVE psxKernelDat End /// @brief Implementation of psx operation -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 @@ -883,7 +981,12 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string JWN_SetStringInWaveNote(psxEvent, PSX_X_DATA_UNIT, WaveUnits(sweepData, ROWS)) JWN_SetStringInWaveNote(psxEvent, PSX_Y_DATA_UNIT, WaveUnits(sweepData, -1)) - [WAVE peakX, WAVE peakY] = PSX_AnalyzePeaks(sweepDataOffFiltDeconv, sweepDataOffFilt, peakXUnfiltered, peakYUnfiltered, 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) @@ -905,7 +1008,7 @@ static Function PSX_OperationImpl(string graph, variable parameterJSONID, string 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 @@ -913,17 +1016,14 @@ 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 - if(WaveExists(psxEvent)) - UpgradePSXEventWave(psxEvent) - - WAVE riseTime = PSX_CalculateRiseTime(psxEvent, sweepDataOffFilt, 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) @@ -1019,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" @@ -1039,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": @@ -1061,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 @@ -1083,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] @@ -1308,9 +1440,24 @@ static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE r case "amp": propLabelAxis = "Amplitude" + " (" + JWN_GetStringFromWaveNote(allEvents[0], PSX_Y_DATA_UNIT) + ")" break - case "xpos": + 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 @@ -1326,11 +1473,21 @@ static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE r 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 + default: - ASSERT(0, "Impossible prop") + ASSERT(0, "Impossible prop: " + prop) endswitch if(!cmpstr(stateAsStr, "every")) @@ -1469,6 +1626,7 @@ static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE r 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 @@ -1528,44 +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 sweepDataOffFilt, 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 - - Multithread riseTime[] = PSX_CalculateRiseTimeImpl(psxEvent, sweepDataOffFilt, kernelAmp, psxEvent[p][%index], \ - lowerThreshold, upperThreshold) - - CA_StoreEntryIntoCache(cacheKey, riseTime) - - return riseTime -End - -threadsafe static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDataOffFilt, 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] + // 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) @@ -1606,6 +1744,49 @@ threadsafe static Function PSX_CalculateRiseTimeImpl(WAVE psxEvent, WAVE sweepDa 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) @@ -1743,8 +1924,10 @@ static Function PSX_UpdateSingleEventGraph(string win, variable index) 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) @@ -1817,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) sweepDataOffFilt, singleEventRaw switch(offsetMode) case PSX_HORIZ_OFFSET_ONSET: - xOffset = 0 - yOffset = sweepDataOffFilt(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: @@ -2015,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]) @@ -2036,12 +2223,8 @@ static Function PSX_UpdateAverageTraces(string win, WAVE/T eventIndexFromTraces, 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 @@ -2067,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 @@ -2092,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) @@ -2120,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") @@ -2207,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: @@ -2252,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 @@ -2626,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) @@ -3172,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) @@ -3188,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) @@ -3580,7 +3783,7 @@ 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) sweepDataOffFilt, singleEvent @@ -4363,8 +4566,8 @@ End Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) variable numberOfSDs, sweepFilterLow, sweepFilterHigh, parameterJsonID, numCombos, i, addedData, kernelAmp - variable maxTauFactor, peakThresh, idx, success - 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) @@ -4391,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"]) @@ -4402,8 +4606,13 @@ 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") @@ -4428,7 +4637,7 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) WaveClear hist, fit for(i = 0; i < numCombos; i += 1) - 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 catch if(WaveExists(output)) @@ -4472,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] @@ -4544,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) @@ -4569,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) @@ -4581,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 @@ -4597,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) @@ -4676,7 +4903,7 @@ static Function [WAVE hist, WAVE fit, variable peakThresh, string dataUnit] PSX_ [WAVE coef, WAVE fit] = PSX_FitHistogram(hist) if(WaveExists(coef) && WaveExists(fit)) - peakThresh = RoundNumber(coef[3] * numSDs, 3) + peakThresh = coef[3] * numSDs dataUnit = WaveUnits(sweepDataOffFiltDeconv, -1) return [hist, fit, peakThresh, dataUnit] 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_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index bc87b11667..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) diff --git a/Packages/MIES/SweepFormulaHelp.ifn b/Packages/MIES/SweepFormulaHelp.ifn index dfb8ceab4b8e5069ccc778deccb87223d54cd190..857d84e64aa74572c8943681860b7fb5b7184bae 100644 GIT binary patch delta 5705 zcma*qdsJ1|oxt(E5BC8mmiQh^=<$tuML>KJH3kjw5fuqB#wOLmE|yu!!Vr`5e+eF49@r7b4mQ8f7G=;cmICB zz0YIsea>N7eRA~C)1ym9%M<&@{339nS@17HglIy{$5Jf7->>g)?tZQ9k`&kcg*enJ z#V(HB$msMxOW}7*ig-UEtb0Ag-cqv|OZ~UyW)Z}gOSH~^|3It0xGA6XaSoj5Da4(F zX0cEOkJ4tmxlwD}sLA|U*0ZitMXRc5a-4b;EH|&xV^ZVwtVD+%pOlc`$Z(`)CB-CD z$Z%vPrX|Pg327Ow?zGfQN0y$Il;Y6iVv^&wC&$HPC8ebX`UvSdr;k{owuQ*qPuN^% ziXJ?{tJBo&NpeJ4^h?K7L3TaBo}9KL zg0g*@YkjCXi-}2_6OF3+Y_9Y(IhU?tp7ir_Udeeyo0>XLPMqSb+h;9bVb>Ef(o%GL zgzLsutcbEdwp>rDlzDQj=lq}`n;sk#RJQ+xQBrr+yhEL}InH`nOz$X`&ad&_JQ*+L zI`!%TxzdN}I`rf;_Cfa%jr9v;h)3>v*DmP#(!{i+I3^O4;Rw_1F)8Ux)Sm8$**e%d zx6m2KJL1w(vj=;A%m({oV=^7dNvVwWdBJ^d`(SNw%+91#Ry;c<*{((`k~8LJCOdXy z#AG>-5z_|`8Y~VTl)WO0K$-tDjdc`eN50Jl%*)Eg%VcMf;M+ZWmmEsk|<1mim0=~k?2(E?PFn$Vg63rO;oD>^i zM>=+*4js6M@a0mJq7^qVas?N_0W?6YWaY3Mm1xC7j9$gwBN+uajOJDBe<#5MjC-Ct zMm&m9i&osgu+>sTV9jc&C(@?lAZl6j|%o_eLND+%I_$x+6vm!`DDVop+{Y5FFu?KbNg5P?! z78SUGNiT7oTz<}>5B?i?MUaS6oX0%`zRW(N0B3L)K^s{GG+_XipR=4OdWBaOJ?KZ| zCbkpeHMSUjb|!^Fm}1!fW`4RcHTkZ-`9i zM$v|@bg2)}TDGw&Sh-E=U9@2tygjIgC6g_|a>QaEO7T@D`|q74#c<);Ew zxQNlaSsFy+AZqX>db!cN*pSCbP>IEF@a&)ise8C#Tt)bse57y$!}GZ?N>G_E^?KUV zxPgbr&3}uB1~>2(0t(niB%lM`ShJUXM-$FrQz8ARL^bMu#Vfau<$as2!Gt1aj2v|0 zuSoqhTZbm}qN12d7qkD#@371WEa4$U1)9)~u>E}dQI0-@l=2ZlD?-b-F|^*+arz@BNqZfZ zIwpw_P*Y@FgOD&%=mp6rmiwSayuR1vrH3 z=)#2KJP*gEevekvOMP5DHLR&;|JM^7!8LSZ!XFrnXzaosoJ2D&;~J(kFyjWPFQ<(~ zKB}Pqk=GNo@IJxKp%3Ma>^n>+8IM{VgXbw;snSyfr+L3ofPOqgz`yc6KrODL3n5KB z3pk1s=z--=tP*U0l6nMfH3krMhVKGe(GAak;~F@FmCd{r=*w-Ey7wo1^{@#$(S`w7 zTBKNr4JgJDwBbsN)O%?AvEeM+b5`m_wB@*pUWA`xkI{oA|4tw3(13Pypa;44`0+i@ zgNFcw;&~*TmwFy;A&#IP;h!>dWVLcKG@uh9pK%P*u@ix9tQwBtIs!lE`+*FUpb|ak z|6E3ikP9p+4#5A<>@C(~53V}%i_8EesD%F|YA8VQC0;AqW3(o*CM_c+CV7VQzi~fR zCvVD)=DZ=An4)6(s_i zz&eBY^L?5+{zy($k+-BtYbkP#vIf%gS+S<}YuZ%HERxm|*CCc5;!jFd=PgcozFZCK zlQxgD6`Fcum3fR>a!dMJXEWk_s)$1t*>)oyMcj7Hh({8C@ue$P zd3QPawd+R5a6108!-$_C?(Q^VU*elLl<&8kyuZt+O`!H&w-HYy*8b0kClP!7%@wP@ zZ#lW|O`~Hf9b;}8aR9OZZ6lsWJo#&tcaM|XzA=?_m%vfw|FDn(I2ZUXW8fY59L=V z*Ve1cl(pq2)PS=+-{@=uEU(eG?3CL0J+;g;YRLev!LjeT&*9C+fLI2Ud}73L#KX?2 z;R6i5{i$=XO)L3KrP6xLy=>g0HHjNubj6({k}SJwBuan8Gry|cJ(n$&S{I#u+5whK;^0}TMAHJSS;RrX#-IvK zGnwbjHjAGaH?)Jkh&k@d4k1}R&+PgpS%#7n`F&PrHx& z1Se;QDI^tTUI?j<2*W2Ru9hD z`UYw0TC@5|AJ0@i$<}qojjB!)mrHoTtp4j3U4_oB7v1B2MUwcEkywgI951VMGZV`G zxw8$hmQdUKs{7{llN7&ZBwl4C@5Y#gmusC=q=j{>iW|(m6x|;>2A9#RlJvx8^WclH zhxC&q)oEc?ty|rvFQ9lS#hnzBw5Pd~w@LnEn~|tyE7R%9ba&;_^|$Trq?F{&4kNMb zBf0;&iuB|fBF8=A07dI=ck(XDusnBCK{9HOk*FXquHl#O?s}81i3RRt49WCDBeA?s z61-0}d$D9uMXHz9V@I*k=~YGN?vlY3X?&2WdCR>yLo|56)R;5G>`^fDf5m=LD$2xG p@!#TqM6q~B+!mvxNsgA^iZODmOcqk6h_}Rj!BgK@x8I!Q{r{Wn6VCtu delta 5367 zcma*oeOy#k8o=>$E;ECJV&q$VjM$s6)J}?uibQHkW@bdJ8Os_C$k1R2BM_;XpyEqv zh^QQV$;c%#Gx8OP)Rd^mjIgN`?5Ig*!N2}utR_S$(R9j}DgSr<=98^Y)HO(PHdu(Q-$}8Qp7GqV z;EWV~+oVVi62f<_k65zVECQ+Dyu~a+>2r$G{qO%M)v5m4ZT{|#LwgC)vePUg-Bo{F z6|YsrYchZImiTFYR=X=}ab{|kBU}A2Mn2tpl)vU^i3>~J~Kle6@UbUoYY@D~qx2FXfX=t@gX ze^O6P&vsL$veLsK#{7WxZ+W0o^g(-?Wi1F`l|{-S5y!OA~e2KtQ;4YlcGLPJCE*mC=j{wl^L zt!iMn4CoW)ZkXV{Od7N0T-%tc;&7QPWsLfDlAP6h4)aUPn9pSWt70SMSfASyJkQeg z>CTMQ`3`m>(-EQDS)1La+ZVesveZxa$Vn#m8K~sRvQbV~i>AoH(RWQYdX4sUvQzZz z1F<73J2Bfq;5oX~g$}z4pCZGnc2AKpWx39=Qn*lqT3p373>zoKWXwQ1)}au`(1y-& zQV$4|A`l5k!FgOl;CLx?%)vakun}9a7j-y;rtvaYTqU@Mm$F$gh; z!(xl97h1SUz2fHPfYDO1T$j(S%V^Qp`mHO0gI3qXm8M<5>v9O5`5m zQUl8jDPj?i1;|7>n$UsB``H!L;sW~42Ip~g z7Uw_UL1v5utivAE;sScj<_s}&w$zg-7oZrs(T)KRacqc#9hs;=CEiB^dPPey1j#5z zMYPoGDbM0sbS~TRuoSIm!-yCrgQZxB{6|;{`zLk;N!W-=T*2TuQbc1J z%5f2c9_46Jhzkgw%X4r7S8}-oKE|hpBy7YQRo<=tjJghu{jPrjnx?feZNba2nxHasIJS(SYDIW{pzxUC8RO4wqq1 z=iD$WgNdRJ7c->ZMJZhD3Zh(6zepLjh_46xAu>4ctVhu* zsqd#ef(z)x@_gPI z-sWAvUK~Ix#4&aWBaTUZD&-DzVfJx;7f_34XeW3EsuA@LUj?qbBX!eBe)Mv=#32)P z=z=&U#RSA+9m-ILGpD59O4)|kT8^hy>T4(q(16Q`e3vsuDLpdsN7ENeH2mIdS z{0DFuf>D?O`+HJfO1Tnc*pJBfSvk@_U@%nRJZ$ycg9XS$$cOA2_Ms6Wr#WY&VLgh_ ziZ<9jVn;ucQ^Zz+z%x?lh`};6xbu%$0oJ1kfeq9l59=EEtSI+2sM0o>XU_D~#0a(G zdpX>q2~CvrQ8C|3o7SDBmb=S=IcmSVJib~5{3JsxcM3mIw^p5Ommw;&U7EDx&#TZ5 z8f-Ki+2HA99Yy^13!1p05<3`oG-=Hy_dPc4@MhIU=~KN$Q;%4*k=C&^9^Ix1AI}`D z<4CJjPpV3P;1O?cH=aG7w%VP><0cTl^`a{Mkw;G?KJt>g-lo0&vS)6V2%(S3UJA;74ildEqrXsh%#J*9)Sw}T>u3L`uy^q9MWsIWot}^@7w>;gf_tTQ}_V1f=J89x^V_`GhH@)MI zZCb`DqwWFfa^5xKKM+6no)OO?&i}v@tM;E5f5V4HLl6x`9~tqj#M?hM;=#nFpQyY} z27mROQTHHq6`vV#Ao0;JjCdgNu`fNbvj5EB@BYnb=ugAxzZ-Es;&Wda@y*0dU#s?? z8T{*i7e>VH{^!Fvb;_GQr2Y!_%^Vinj+a?KqXM3xb zUzu!Jf7S0AsO{;_aBj0M4Bzb*i0YE=l5xMvLV!Zg;+Z;9q?RX0CsZrv zb$UCFtLPi7Cy_eSJ3U>jNu(=J_N12iq@q^oH@M@Q_uY5cw3YR08KqCiC*CEbGV9Uj zjAW~3@|p0Nx8X?|?)k#IoCORO_2srC&8Btr+g7OAd~OUdt1%tyua&0GLEFC7Z05#W z&0@6YyZ24wZga5NvrWn+8Mu#bWWMP%^&es+Ru{?OVP@~og=G=xZ6k^`9uOSj?f*1& z!|(Ja86-BF@n~xn$`>bsP5^km~k6=QO5(Nynbo}=lWY2IWRNmP{g0n14qoS~Xc z4E*R!qtbdWmGfr(zSca_CuXzO5X%Zed$fwNXd&vPnMXVxWA?ng*44Dc#hQiL_(@+! z`uH4AN6YiX@pIj=O?xa(EvGa)yg^jfEbu04NKU1BlLC_ZbnlZ&d$E>JT;8Tl zG&N>=lU$OovW>)2MADL@LajXGKa0IRwo}=$)SK)e`DK|m*+wFAjYI|b@eJP;-lnxQ z^ `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..2d5c6e9f56 100644 --- a/Packages/doc/SweepFormula_PSX.rst +++ b/Packages/doc/SweepFormula_PSX.rst @@ -144,7 +144,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 a10effa43e..1431cbb447 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -651,19 +651,25 @@ 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 @@ -766,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" @@ -782,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}) @@ -798,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 @@ -814,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" @@ -1090,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}) @@ -1233,6 +1240,37 @@ static Function StatsComplainsAboutIntersectingRanges() 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 @@ -1375,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 @@ -1391,6 +1430,7 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) // all decay fits are successfull overrideResults[][][%$"Fit Result"] = 1 + overrideResults[][][%$"Tau"] = 1 overrideResults[][][%$"KernelAmpSignQC"] = 1 [win, device] = CreateEmptyUnlockedDataBrowserWindow() @@ -1408,8 +1448,8 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) 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) @@ -1424,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) @@ -1435,7 +1475,7 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) CHECK_WAVE(dataWref, WAVE_WAVE) // without events found we get empty waves - str = "psx(myID, psxKernel(select(selrange([50, 150]), selchannels(AD6), selsweeps([0, 2]), selvis(all)), 5000, 15, -5), 25, 100, 0)" + 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 @@ -1452,7 +1492,7 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) // returns empty waves without events found due to kernelAmp sign overrideResults[][][%$"KernelAmpSignQC"] = 0 - str = "psx(id, psxKernel([50, 150], select(channels(AD6), [0, 2], all), 1, 15, -4))" + 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 @@ -1517,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 @@ -1546,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) @@ -1620,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=$"leftOffFiltDeconv" 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) @@ -1634,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=$"leftOffFiltDeconv" 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) @@ -1647,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=$"leftOffFilt" 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) @@ -1778,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 @@ -1794,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) @@ -1804,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) @@ -1812,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() @@ -1962,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)" @@ -1978,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 = "" @@ -1998,11 +2045,14 @@ 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 combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ - "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + 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 @@ -2042,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) @@ -2088,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) @@ -2098,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) @@ -2106,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) @@ -2141,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] @@ -2158,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 @@ -2176,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) @@ -2187,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) @@ -2203,16 +2232,19 @@ 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 combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ - "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + 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 @@ -2254,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) @@ -2273,11 +2305,14 @@ 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 combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ - "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + 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 @@ -2305,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() @@ -2314,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() @@ -2326,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) @@ -2335,15 +2371,22 @@ 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 combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ - "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + 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 @@ -2379,10 +2422,13 @@ 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 combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ - "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + 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 @@ -2420,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 @@ -2470,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) @@ -2482,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) @@ -2575,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) @@ -2591,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) @@ -2605,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) @@ -2620,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) @@ -2634,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) @@ -2648,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 @@ -2694,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(psxStatsGraph, LEFT_KEY) + 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(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 @@ -2774,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) @@ -2818,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) @@ -2832,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) @@ -2847,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) @@ -2861,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) @@ -2875,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 @@ -2915,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 @@ -2937,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) @@ -3001,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() @@ -3040,10 +3198,13 @@ 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 combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ - "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + 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 @@ -3082,10 +3243,13 @@ End static Function TestBlockIndexLogic() - string browser, code, psxGraph, win, mainWindow, specialEventPanel, extAllGraph + string browser, code, psxGraph, win, mainWindow, specialEventPanel, extAllGraph, comboKey - Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ - "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + 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 @@ -3108,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 @@ -3122,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 @@ -3133,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 @@ -3143,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") @@ -3171,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 @@ -3182,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 @@ -3196,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 @@ -3207,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") @@ -3238,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 @@ -3301,10 +3512,13 @@ End static Function TestOperationPrep() - string win, device, code, psxCode + string win, device, code, psxCode, comboKey - Make/FREE/T combos = {"Range[50, 150], Sweep [0], Channel [AD6], Device [ITC16_Dev_0]", \ - "Range[50, 150], Sweep [2], Channel [AD6], Device [ITC16_Dev_0]"} + 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 @@ -3534,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 From 9dc4e2068cb968f52b2d6c1d45c4d638b51ee444 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Thu, 19 Dec 2024 18:00:16 +0100 Subject: [PATCH 31/31] Packages/doc/SweepFormula_PSX.rst: Explain the algorithm a bit --- Packages/doc/SweepFormula_PSX.rst | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Packages/doc/SweepFormula_PSX.rst b/Packages/doc/SweepFormula_PSX.rst index 2d5c6e9f56..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