diff --git a/Packages/MIES/MIES_Cache.ipf b/Packages/MIES/MIES_Cache.ipf index 174edc5143..0b923511c4 100644 --- a/Packages/MIES/MIES_Cache.ipf +++ b/Packages/MIES/MIES_Cache.ipf @@ -308,6 +308,8 @@ static Function/S CA_WaveCRCs(WAVE/WAVE waveRefs, [variable crcMode, variable in variable rows + ASSERT(IsWaveRefWave(waveRefs), "Expected a wave reference wave") + if(ParamIsDefault(crcMode)) crcMode = 0 endif diff --git a/Packages/MIES/MIES_SweepFormula_Helpers.ipf b/Packages/MIES/MIES_SweepFormula_Helpers.ipf index 55f1d4cca4..5647888863 100644 --- a/Packages/MIES/MIES_SweepFormula_Helpers.ipf +++ b/Packages/MIES/MIES_SweepFormula_Helpers.ipf @@ -1122,8 +1122,8 @@ Function/WAVE SFH_NewSelectDataWave(variable numSweeps, variable numChannels) return selectData End -/// @brief Recreate a **single** select data wave and range stored in the JSON wavenote from SFH_GetSweepsForFormula() -Function [WAVE selectData, WAVE range] SFH_ParseToSelectDataWaveAndRange(WAVE sweepData) +/// @brief Parse the range stored in the JSON wavenote from SFH_GetSweepsForFormula() +Function/WAVE SFH_ParseSweepDataRange(WAVE sweepData) WAVE/Z range = JWN_GetNumericWaveFromWaveNote(sweepData, SF_META_RANGE) @@ -1132,6 +1132,18 @@ Function [WAVE selectData, WAVE range] SFH_ParseToSelectDataWaveAndRange(WAVE sw endif if(!WaveExists(range) || !HasOneValidEntry(range)) + return $"" + endif + + return range +End + +/// @brief Recreate a **single** select data wave and range stored in the JSON wavenote from SFH_GetSweepsForFormula() +Function [WAVE selectData, WAVE range] SFH_ParseToSelectDataWaveAndRange(WAVE sweepData) + + WAVE/Z range = SFH_ParseSweepDataRange(sweepData) + + if(!WaveExists(range)) return [$"", $""] endif @@ -1478,6 +1490,24 @@ Function/WAVE SFH_GetStimsetRange(string graph, WAVE data, WAVE selectData) return range End +Function [WAVE adaptedRange, WAVE/T epochRangeNames] SFH_GetNumericRangeFromEpochFromSingleSelect(string graph, WAVE singleSelectData, WAVE range) + + variable sweepNo, chanNr, chanType, mapIndex + + sweepNo = singleSelectData[0][%SWEEP] + chanNr = singleSelectData[0][%CHANNELNUMBER] + chanType = singleSelectData[0][%CHANNELTYPE] + mapIndex = singleSelectData[0][%SWEEPMAPINDEX] + + 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, range, sweepNo, chanType, chanNr, mapIndex) + + return [resolvedRanges, epochRangeNames] +End + /// @brief From a single numeric/textual range wave we return a 2xN numeric range /// /// Supports numeric ranges, epochs, and epochs with wildcards. @@ -1691,27 +1721,34 @@ Function/WAVE SFH_MoveDatasetHigherIfCompatible(WAVE/WAVE data) return data End -Function/WAVE SFH_GetSingleSelect(string graph, string opShort, variable sweepNo, variable channelType, variable channelNumber, variable mapIndex) - - WAVE/WAVE range = SFH_AsDataSet(SFH_GetFullRange()) - WAVE singleSelect = SFH_NewSelectDataWave(1, 1) - singleSelect[0][%SWEEP] = sweepNo - singleSelect[0][%CHANNELTYPE] = channelType - singleSelect[0][%CHANNELNUMBER] = channelNumber - singleSelect[0][%SWEEPMAPINDEX] = mapIndex +Function/WAVE SFH_CreateSelectDataComp(string graph, string opShort, WAVE singleSelect, WAVE range) WAVE/WAVE selectDataComp = GetSFSelectDataComp(graph, opShort) JWN_SetStringInWaveNote(selectDataComp, SF_META_DATATYPE, SF_DATATYPE_SELECTCOMP) JWN_SetStringInWaveNote(singleSelect, SF_META_DATATYPE, SF_DATATYPE_SELECT) JWN_SetStringInWaveNote(range, SF_META_DATATYPE, SF_DATATYPE_SELECTRANGE) selectDataComp[%SELECTION] = singleSelect - selectDataComp[%RANGE] = range + selectDataComp[%RANGE] = SFH_AsDataSet(range) Make/FREE/WAVE selectDataArray = {selectDataComp} return selectDataArray End +Function/WAVE SFH_GetSingleSelect(string graph, string opShort, variable sweepNo, variable channelType, variable channelNumber, variable mapIndex) + + WAVE range = SFH_GetFullRange() + WAVE singleSelect = SFH_NewSelectDataWave(1, 1) + singleSelect[0][%SWEEP] = sweepNo + singleSelect[0][%CHANNELTYPE] = channelType + singleSelect[0][%CHANNELNUMBER] = channelNumber + singleSelect[0][%SWEEPMAPINDEX] = mapIndex + + WAVE selectDataArray = SFH_CreateSelectDataComp(graph, opShort, singleSelect, range) + + return selectDataArray +End + Function/S SFH_GetStimsetName(WAVE numericalValues, WAVE textualValues, variable sweepNo, variable channelNumber, variable channelType) variable index diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index 5bf87e0bb4..d13e181b07 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -1290,44 +1290,77 @@ static Function/S PSX_BuildSweepEquivValue(variable sweepNo, variable mapIndex) return str End + /// @brief Generate the equivalence classes of selectData /// /// All selections which have the same channel number and type are in one equivalence class. /// /// The returned 2D wave has row labels from PSX_BuildSweepEquivKey() for the /// channel type/number and the sweep numbers in the columns. -static Function/WAVE PSX_GenerateSweepEquiv(WAVE selectData) +static Function [WAVE/T sweepEquiv, WAVE/WAVE sweepEquivRanges] PSX_GenerateSweepEquiv(WAVE/WAVE selectDataCompArray) - variable numSelect, idx, i, nextFreeRow, maxCol + variable numSelectComp, numSelected, idx, i, j, nextFreeRow, maxCol, col, isSingleRange string key - numSelect = DimSize(selectData, ROWS) - ASSERT(numSelect > 0, "Expected at least one entry in sweepData") + ASSERT(IsWaveRefWave(selectDataCompArray), "Expected a wave reference wave for selectDataCompArray") + + numSelectComp = DimSize(selectDataCompArray, ROWS) + ASSERT(numSelectComp > 0, "Expected at least one entry in selectDataCompArray") + + Make/N=(MINIMUM_WAVE_SIZE, MINIMUM_WAVE_SIZE)/FREE=1/T sweepEquiv + Make/N=(MINIMUM_WAVE_SIZE, MINIMUM_WAVE_SIZE)/FREE=1/WAVE sweepEquivRanges + + for(i = 0; i < numSelectComp; i += 1) + WAVE/WAVE selectDataComp = selectDataCompArray[i] + ASSERT(IsWaveRefWave(selectDataComp), "Expected a wave reference wave for selectDataComp") - Make/N=(numSelect, numSelect)/FREE=1/T sweepEquiv + WAVE selectData = selectDataComp[%SELECTION] + WAVE/WAVE range = selectDataComp[%RANGE] + ASSERT(IsWaveRefWave(range), "Range must be a wave reference wave") - for(i = 0; i < numSelect; i += 1) - key = PSX_BuildSweepEquivKey(selectData[i][%CHANNELTYPE], selectData[i][%CHANNELNUMBER]) - idx = FindDimLabel(sweepEquiv, ROWS, key) + isSingleRange = DimSize(range, ROWS) == 1 - if(idx == -2) - SetDimLabel ROWS, nextFreeRow, $key, sweepEquiv - idx = nextFreeRow - nextFreeRow += 1 + if(!isSingleRange) + SFH_ASSERT(DimSize(range, ROWS) == numSelected, "Number of ranges is not equal number of selections.") endif - FindValue/TXOP=4/TEXT=""/RMD=[idx][] sweepEquiv - ASSERT(V_col >= 0, "Not enough space") - maxCol = max(maxCol, V_col) + numSelected = DimSize(selectData, ROWS) + for(j = 0; j < numSelected; j += 1) + key = PSX_BuildSweepEquivKey(selectData[j][%CHANNELTYPE], selectData[j][%CHANNELNUMBER]) + idx = FindDimLabel(sweepEquiv, ROWS, key) - sweepEquiv[idx][V_col] = PSX_BuildSweepEquivValue(selectData[i][%SWEEP], selectData[i][%SWEEPMAPINDEX]) + if(idx == -2) + EnsureLargeEnoughWave(sweepEquiv, dimension = ROWS, indexShouldExist = nextFreeRow) + + SetDimLabel ROWS, nextFreeRow, $key, sweepEquiv + idx = nextFreeRow + nextFreeRow += 1 + endif + + FindValue/TXOP=4/TEXT=""/RMD=[idx][] sweepEquiv + if(V_col >= 0) + col = V_col + else + col = DimSize(sweepEquiv, COLS) + EnsureLargeEnoughWave(sweepEquiv, dimension = COLS, indexShouldExist = col) + endif + + maxCol = max(maxCol, col) + sweepEquiv[idx][col] = PSX_BuildSweepEquivValue(selectData[j][%SWEEP], selectData[j][%SWEEPMAPINDEX]) + + EnsureLargeEnoughWave(sweepEquivRanges, dimension = ROWS, indexShouldExist = idx) + EnsureLargeEnoughWave(sweepEquivRanges, dimension = COLS, indexShouldExist = col) + + WAVE/Z setRange = range[isSingleRange ? 0 : i] + sweepEquivRanges[idx][col] = setRange + endfor endfor ASSERT(nextFreeRow > 0, "Could not build sweep equivalence classes") - Redimension/N=(nextFreeRow, maxCol + 1) sweepEquiv + Redimension/N=(nextFreeRow, maxCol + 1) sweepEquiv, sweepEquivRanges - return sweepEquiv + return [sweepEquiv, sweepEquivRanges] End /// @brief Check that the 2xN wave allResolvedRanges has only @@ -1344,29 +1377,21 @@ static Function PSX_CheckResolvedRanges(WAVE allResolvedRanges) End /// @brief Helper function of the `psxStats` operation -static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE ranges, WAVE selectData, string prop, string stateAsStr, string postProc) +static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE selectDataCompArray, string prop, string stateAsStr, string postProc) string propLabelAxis, comboKey variable numEquivChannelNumberTypes, numEquivSweeps, i, j, k, index, sweepNo, chanNr, chanType - variable state, numRanges, lowerBoundary, upperBoundary, temp, err, mapIndex, singleRange + variable state, numRanges, lowerBoundary, upperBoundary, temp, err, mapIndex 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) + [WAVE/T selectDataEquiv, WAVE/WAVE selectDataEquivRanges] = PSX_GenerateSweepEquiv(selectDataCompArray) numEquivChannelNumberTypes = DimSize(selectDataEquiv, ROWS) numEquivSweeps = DimSize(selectDataEquiv, COLS) - numRanges = DimSize(ranges, ROWS) - SFH_ASSERT(numRanges > 0, "Expected at least one range") - singleRange = (numRanges == 1) - - 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) @@ -1389,13 +1414,9 @@ static Function/WAVE PSX_OperationStatsImpl(string graph, string id, WAVE/WAVE r 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 ranges = selectDataEquivRanges[i][j] - [WAVE resolvedRanges, WAVE/T epochRangeNames] = SFH_GetNumericRangeFromEpoch(graph, numericalValues, textualValues, rangesForSweep, sweepNo, chanType, chanNr, mapIndex) + [WAVE resolvedRanges, WAVE/T epochRangeNames] = SFH_GetNumericRangeFromEpochFromSingleSelect(graph, singleSelectData, ranges) if(!WaveExists(resolvedRanges)) continue @@ -4555,6 +4576,55 @@ static Function PSX_OperationSetDimensionLabels(WAVE/WAVE output, variable numCo endfor 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 numRows + + [WAVE resolvedRanges, WAVE/T epochRangeNames] = SFH_GetNumericRangeFromEpochFromSingleSelect(graph, singleSelectData, range) + + numRows = DimSize(allSelectHashes, ROWS) + Redimension/N=(numRows + 1) allSelectHashes + allSelectHashes[numRows] = WaveHash(singleSelectData, HASH_SHA2_256) + + Concatenate/NP/FREE {resolvedRanges}, allResolvedRanges + + if(DimSize(allResolvedRanges, COLS) == 0) + Redimension/N=(-1, 1) allResolvedRanges + endif +End + +/// @brief Check that the 2xN wave allResolvedRanges has only +/// non-intersecting ranges for the same select data hash +static Function PSX_CheckResolvedRangesWithSelectHashes(WAVE allResolvedRanges, WAVE/T allSelectHashes) + + string selectHash + variable numRows, numColumns, i, idx + + numRows = DimSize(allResolvedRanges, ROWS) + numColumns = DimSize(allResolvedRanges, COLS) + + 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 +End + /// @brief Implementation of the `psx` operation /// // Returns a SweepFormula dataset with n * PSX_OPERATION_OUTPUT_WAVES_PER_ENTRY @@ -4682,7 +4752,8 @@ Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph 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) + WAVE/Z/WAVE selectDataCompArray = SFH_GetArgumentSelect(jsonID, jsonPath, graph, SF_OP_PSX_KERNEL, 0) + SFH_ASSERT(WaveExists(selectDataCompArray), "Could not gather sweep data from select statement") riseTau = SFH_GetArgumentAsNumeric(jsonID, jsonPath, graph, SF_OP_PSX_KERNEL, 1, defValue = 1, checkFunc = IsStrictlyPositiveAndFinite) decayTau = SFH_GetArgumentAsNumeric(jsonID, jsonPath, graph, SF_OP_PSX_KERNEL, 2, defValue = 15, checkFunc = IsStrictlyPositiveAndFinite) @@ -4690,15 +4761,6 @@ Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph 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] - - WAVE/Z selectData = selectDataComp[%SELECTION] - WAVE/WAVE range = selectDataComp[%RANGE] - - SFH_ASSERT(WaveExists(selectData), "Could not gather sweep data from select statement") - WAVE/WAVE sweepDataRef = SFH_GetSweepsForFormula(graph, selectDataCompArray, SF_OP_PSX_KERNEL) numCombos = DimSize(sweepDataRef, ROWS) @@ -4709,8 +4771,21 @@ Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph Make/FREE/T rawLabels = {"psxKernel", "psxKernelFFT", "sweepData"} ASSERT(DimSize(rawLabels, ROWS) == PSX_KERNEL_OUTPUTWAVES_PER_ENTRY, "Mismatched rawLabels wave") + Make/FREE/N=(0) allResolvedRanges + Make/FREE/N=(0)/T allSelectHashes + for(i = 0; i < numCombos; i += 1) - WAVE sweepData = sweepDataRef[i] + WAVE/Z sweepData = sweepDataRef[i] + ASSERT(WaveExists(sweepData), "Can't handle invalid sweepData waves") + + [WAVE singleSelectData, WAVE range] = SFH_ParseToSelectDataWaveAndRange(sweepData) + + [WAVE resolvedRanges, WAVE/T epochRangeNames] = SFH_GetNumericRangeFromEpochFromSingleSelect(graph, singleSelectData, range) + + if(!WaveExists(resolvedRanges)) + continue + endif + numPoints = DimSize(sweepData, ROWS) dt = DimDelta(sweepData, ROWS) @@ -4725,6 +4800,8 @@ Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph continue endif + PSX_CollectResolvedRanges(graph, resolvedRanges, singleSelectData, allResolvedRanges, allSelectHashes) + Duplicate/FREE/T rawLabels, labels labels[] = PSX_GenerateKey(rawLabels[p], idx) SetDimensionLabels(output, TextWaveToList(labels, ";"), ROWS, startPos = idx * PSX_KERNEL_OUTPUTWAVES_PER_ENTRY) @@ -4743,14 +4820,13 @@ Function/WAVE PSX_OperationKernel(variable jsonId, string jsonPath, string graph SFH_ASSERT(numCombos > 0, "Could not create psxKernel") + PSX_CheckResolvedRangesWithSelectHashes(allResolvedRanges, allSelectHashes) + 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", 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) @@ -4824,13 +4900,6 @@ Function/WAVE PSX_OperationStats(variable jsonId, string jsonPath, string graph) WAVE/Z/WAVE selectDataCompArray = SFH_GetArgumentSelect(jsonID, jsonPath, graph, SF_OP_PSX_STATS, 1) SFH_Assert(WaveExists(selectDataCompArray), "Missing select data") - SFH_ASSERT(DimSize(selectDataCompArray, ROWS) == 1, "Only supports a single selection at the moment") - - WAVE/WAVE selectDataComp = selectDataCompArray[0] - - WAVE/Z selectData = selectDataComp[%SELECTION] - WAVE/WAVE range = selectDataComp[%RANGE] - 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"} @@ -4838,7 +4907,7 @@ Function/WAVE PSX_OperationStats(variable jsonId, string jsonPath, string graph) Make/FREE/T allPostProc = {"nothing", "stats", "count", "hist", "log10", "nonfinite"} postProc = SFH_GetArgumentAsText(jsonID, jsonPath, graph, SF_OP_PSX_STATS, 4, defValue = "nothing", allowedValues = allPostProc) - WAVE/WAVE output = PSX_OperationStatsImpl(graph, id, range, selectData, prop, stateAsStr, postProc) + WAVE/WAVE output = PSX_OperationStatsImpl(graph, id, selectDataCompArray, prop, stateAsStr, postProc) JWN_SetStringInWaveNote(output, SF_META_OPSTACK, AddListItem(SF_OP_PSX_STATS, "")) diff --git a/Packages/tests/Basic/Basic.pxp b/Packages/tests/Basic/Basic.pxp index 30d75dbc87..6a9d77e62c 100644 Binary files a/Packages/tests/Basic/Basic.pxp and b/Packages/tests/Basic/Basic.pxp differ diff --git a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf index 3c802015e0..3bd6bdd0a3 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_PSX.ipf @@ -359,6 +359,14 @@ static Function EWUIndizesWorksWithBoth() CheckEvent({1, 4}, PSX_UNDET, PSX_UNDET) End +static Function/WAVE CreateSelectDataComp() + + Make/FREE/N=(2)/WAVE selectDataComp + SetDimensionLabels(selectDataComp, "SELECTION;RANGE;", ROWS) + + return selectDataComp +End + static Function CheckSweepEquiv() variable sweepNo, chanType, chanNr, mapIndex @@ -389,15 +397,27 @@ static Function CheckSweepEquiv() selectData[0][%CHANNELTYPE] = XOP_CHANNEL_TYPE_ADC selectData[1][%CHANNELTYPE] = XOP_CHANNEL_TYPE_ADC - selectData[2][%CHANNELTYPE] = XOP_CHANNEL_TYPE_TTL // same sweep bug different channel type + selectData[2][%CHANNELTYPE] = XOP_CHANNEL_TYPE_TTL // same sweep but different channel type selectData[3][%CHANNELTYPE] = XOP_CHANNEL_TYPE_ADC selectData[4][%CHANNELTYPE] = XOP_CHANNEL_TYPE_ADC selectData[5][%CHANNELTYPE] = XOP_CHANNEL_TYPE_ADC // sweep 1 and 5 are a group the rest is separate - WAVE/Z selectDataEquiv = MIES_PSX#PSX_GenerateSweepEquiv(selectData) + WAVE/WAVE selectDataComp = CreateSelectDataComp() + + selectDataComp[%SELECTION] = selectData + + WAVE singleRange = SFH_GetFullRange() + selectDataComp[%RANGE] = SFH_AsDataSet(singleRange) + + Make/FREE/WAVE selectDataCompArray = {selectDataComp} + + [WAVE/T selectDataEquiv, WAVE/WAVE selectDataEquivRange] = MIES_PSX#PSX_GenerateSweepEquiv(selectDataCompArray) CHECK_WAVE(selectDataEquiv, TEXT_WAVE | FREE_WAVE) + CHECK_WAVE(selectDataEquivRange, WAVE_WAVE | FREE_WAVE) + Make/FREE/N=(numpnts(selectDataEquivRange)) equalRange = WaveExists(selectDataEquivRange[p]) ? WaveRefsEqual(selectDataEquivRange[p], singleRange) : 1 + CHECK(IsConstant(equalRange, 1)) Make/FREE/T ref = {{"SweepNo1_MapIndex0", "SweepNo2_MapIndex1", "SweepNo3_MapIndex2", "SweepNo4_MapIndex3"}, \ {"SweepNo5_MapIndex4", "", "", ""}, \ @@ -415,7 +435,7 @@ static Function CheckSweepEquiv() CHECK_EQUAL_VAR(mapIndex, 4) End -Function [WAVE range, WAVE selectData] GetFakeRangeAndSelectData() +Function [WAVE range, WAVE selectData, WAVE/WAVE selectDataCompArray] GetFakeRangeAndSelectData(string browser) WAVE range = SFH_GetEmptyRange() WAVE selectData = SFH_NewSelectDataWave(1, 1) @@ -426,7 +446,9 @@ Function [WAVE range, WAVE selectData] GetFakeRangeAndSelectData() selectData[0][%CHANNELNUMBER] = 3 selectData[0][%SWEEPMAPINDEX] = NaN - return [range, selectData] + WAVE/WAVE selectDataCompArray = SFH_CreateSelectDataComp(browser, "FakeOpForTesting", selectData, range) + + return [range, selectData, selectDataCompArray] End static Function StatsComplainsWithoutEvents() @@ -436,7 +458,7 @@ static Function StatsComplainsWithoutEvents() [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() - [WAVE range, WAVE selectData] = GetFakeRangeAndSelectData() + [WAVE range, WAVE selectData, WAVE/WAVE selectDataCompArray] = GetFakeRangeAndSelectData(browser) prop = "tau" stateAsStr = MIES_PSX#PSX_StateToString(PSX_ACCEPT) @@ -445,7 +467,7 @@ static Function StatsComplainsWithoutEvents() // matching id but no events try - MIES_PSX#PSX_OperationStatsImpl(browser, id, {range}, selectData, prop, stateAsStr, postProc) + MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArray, prop, stateAsStr, postProc) FAIL() catch error = ROStr(GetSweepFormulaParseErrorMessage()) @@ -456,7 +478,7 @@ static Function StatsComplainsWithoutEvents() // mismatched id try - MIES_PSX#PSX_OperationStatsImpl(browser, id, {range}, selectData, prop, stateAsStr, postProc) + MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArray, prop, stateAsStr, postProc) FAIL() catch error = ROStr(GetSweepFormulaParseErrorMessage()) @@ -473,8 +495,9 @@ static Function StatsRangeTesting() [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() // events A - [WAVE rangeA, WAVE selectDataA] = GetFakeRangeAndSelectData() - selectDataA[0][%CHANNELNUMBER] = 0 + [WAVE rangeA, WAVE selectDataA, WAVE/WAVE selectDataCompArrayA] = GetFakeRangeAndSelectData(browser) + + selectDataA[0][%CHANNELNUMBER] = 0 WAVE psxEventA = GetPSXEventWaveAsFree() Redimension/N=(10, -1) psxEventA @@ -487,10 +510,10 @@ static Function StatsRangeTesting() FillEventWave_IGNORE(psxEventA, id, comboKeyA) // events B - [WAVE rangeB, WAVE selectDataB] = GetFakeRangeAndSelectData() - rangeB = {101, 201} - selectDataB[0][%SWEEP] = 2 - selectDataB[0][%CHANNELNUMBER] = 0 + [WAVE rangeB, WAVE selectDataB, WAVE/WAVE selectDataCompArrayB] = GetFakeRangeAndSelectData(browser) + 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() @@ -503,9 +526,15 @@ static Function StatsRangeTesting() FillEventWave_IGNORE(psxEventB, id, comboKeyB) // events C + [WAVE rangeNumericC, WAVE selectDataC, WAVE/WAVE selectDataCompArrayC] = GetFakeRangeAndSelectData(browser) + WaveClear rangeNumericC + selectDataB[0][%SWEEP] = 2 + selectDataB[0][%CHANNELNUMBER] = 0 + [key, keyTxt] = PrepareLBN_IGNORE(device) - Duplicate/FREE selectDataB, selectDataC Make/T/FREE rangeC = {"E0"} + WAVE/WAVE selectDataCompArray0 = selectDataCompArrayC[0] + selectDataCompArray0[%RANGE] = SFH_AsDataSet(rangeC) selectDataC[0][%SWEEP] = 3 selectDataC[0][%CHANNELNUMBER] = 0 @@ -543,8 +572,15 @@ static Function StatsRangeTesting() FillEventWave_IGNORE(psxEventC, id, comboKeyC) // events D - Duplicate/FREE selectDataC, selectDataD + [WAVE rangeNumericD, WAVE selectDataD, WAVE/WAVE selectDataCompArrayD] = GetFakeRangeAndSelectData(browser) + WaveClear rangeNumericD + + selectDataD[0][%SWEEP] = 3 + selectDataD[0][%CHANNELNUMBER] = 0 + Make/T/FREE rangeD = {"E1"} + WAVE/WAVE selectDataCompArray0 = selectDataCompArrayD[0] + selectDataCompArray0[%RANGE] = SFH_AsDataSet(rangeD) comboKeyD = MIES_PSX#PSX_GenerateComboKey(browser, selectDataD, rangeD) sprintf ref, "Range[E1], Sweep [3], Channel [AD0], Device [ITC16_Dev_0], Experiment [%s]", GetExperimentName() @@ -563,16 +599,22 @@ static Function StatsRangeTesting() stateAsStr = MIES_PSX#PSX_StateToString(PSX_ACCEPT) postProc = "nothing" + [WAVE rangeNumericE, WAVE selectDataE, WAVE/WAVE selectDataCompArrayE] = GetFakeRangeAndSelectData(browser) + + WAVE/WAVE selectDataCompArray0 = selectDataCompArrayE[0] + Make/WAVE/FREE rangeE = {rangeA, rangeB} + selectDataCompArray0[%RANGE] = rangeE + // non-matching range number with sweeps try - WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeA, rangeB}, selectDataA, prop, stateAsStr, postProc) + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArrayE, prop, stateAsStr, postProc) FAIL() catch error = ROStr(GetSweepFormulaParseErrorMessage()) - CHECK_EQUAL_STR(error, "The number of sweeps and ranges differ") + CHECK_EQUAL_STR(error, "Number of ranges is not equal number of selections.") endtry - WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeA}, selectDataA, prop, stateAsStr, postProc) + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArrayA, prop, stateAsStr, postProc) CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) numComboKeys = 3 CHECK_EQUAL_VAR(DimSize(results[0], ROWS), numComboKeys) @@ -584,8 +626,9 @@ static Function StatsRangeTesting() 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) + Make/FREE/N=(0)/WAVE selectDataCompArray + Concatenate/NP=(ROWS)/FREE/WAVE {selectDataCompArrayA, selectDataCompArrayB}, selectDataCompArray + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArray, prop, stateAsStr, postProc) CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) // -> twice as many events numComboKeys = 6 @@ -601,7 +644,7 @@ static Function StatsRangeTesting() CHECK_EQUAL_TEXTWAVES(comboKeys, comboKeysRef) // epoch name - WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeC}, selectDataC, prop, stateAsStr, postProc) + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArrayC, prop, stateAsStr, postProc) CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) numComboKeys = 3 CHECK_EQUAL_VAR(DimSize(results[0], ROWS), numComboKeys) @@ -616,7 +659,10 @@ static Function StatsRangeTesting() 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) + WAVE/WAVE selectDataCompArray0 = selectDataCompArrayD[0] + selectDataCompArray0[%RANGE] = SFH_AsDataSet(rangeEpochs) + + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArrayD, prop, stateAsStr, postProc) CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) numComboKeys = 6 CHECK_EQUAL_VAR(DimSize(results[0], ROWS), numComboKeys) @@ -632,7 +678,10 @@ static Function StatsRangeTesting() // epoch wildcards Make/FREE/T rangeEpochs = {"E*"} - WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, {rangeEpochs}, selectDataD, prop, stateAsStr, postProc) + WAVE/WAVE selectDataCompArray0 = selectDataCompArrayD[0] + selectDataCompArray0[%RANGE] = SFH_AsDataSet(rangeEpochs) + + WAVE/WAVE results = MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArrayD, prop, stateAsStr, postProc) CHECK_EQUAL_VAR(DimSize(results, ROWS), 1) numComboKeys = 6 CHECK_EQUAL_VAR(DimSize(results[0], ROWS), numComboKeys) @@ -863,7 +912,7 @@ static Function StatsWorksWithResults([STRUCT IUTF_mData &m]) [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() - [WAVE range, WAVE selectData] = GetFakeRangeAndSelectData() + [WAVE range, WAVE selectData, WAVE/WAVE selectDataCompArray] = GetFakeRangeAndSelectData(browser) WAVE psxEvent = GetPSXEventWaveAsFree() Redimension/N=(10, -1) psxEvent @@ -883,7 +932,7 @@ static Function StatsWorksWithResults([STRUCT IUTF_mData &m]) MIES_PSX#PSX_StoreIntoResultsWave(browser, SFH_RESULT_TYPE_PSX_EVENTS, psxEvent, id) - WAVE/WAVE output = MIES_PSX#PSX_OperationStatsImpl(browser, id, {range}, selectData, prop, stateAsStr, postProc) + WAVE/WAVE output = MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArray, prop, stateAsStr, postProc) CHECK_WAVE(output, WAVE_WAVE) Make/FREE/N=4 dims = DimSize(output, p) @@ -1126,7 +1175,7 @@ static Function StatsWorksWithResultsSpecialCases([STRUCT IUTF_mData &m]) [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() - [WAVE range, WAVE selectData] = GetFakeRangeAndSelectData() + [WAVE range, WAVE selectData, WAVE/WAVE selectDataCompArray] = GetFakeRangeAndSelectData(browser) Duplicate/FREE selectData, selectDataComboIndex0 @@ -1165,7 +1214,14 @@ static Function StatsWorksWithResultsSpecialCases([STRUCT IUTF_mData &m]) refNum = NaN endif - WAVE/WAVE output = MIES_PSX#PSX_OperationStatsImpl(browser, id, {range}, allSelectData, prop, stateAsStr, postProc) + WAVE/WAVE selectDataComp = CreateselectDataComp() + + selectDataComp[%RANGE] = SFH_AsDataSet(range) + selectDataComp[%SELECTION] = allSelectData + + Make/FREE/WAVE/N=(1) selectDataCompArray = {selectDataComp} + + WAVE/WAVE output = MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArray, prop, stateAsStr, postProc) CHECK_WAVE(output, WAVE_WAVE) if(outOfRange) @@ -1212,7 +1268,7 @@ static Function StatsComplainsAboutIntersectingRanges() [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() - [WAVE range0, WAVE selectData] = GetFakeRangeAndSelectData() + [WAVE range0, WAVE selectData, WAVE/WAVE selectDataCompArray] = GetFakeRangeAndSelectData(browser) // 1st event wave WAVE/Z psxEvent = GetEventWave(comboIndex = 0) @@ -1223,6 +1279,8 @@ static Function StatsComplainsAboutIntersectingRanges() Duplicate/FREE range0, range1 Concatenate/FREE/NP=(COLS) {range0, range1}, ranges + WAVE/WAVE selectDataComp0 = selectDataCompArray[0] + selectDataComp0[%RANGE] = SFH_AsDataSet(ranges) // 2nd event wave where we shift the range WAVE/Z psxEvent = CreateEventWaveInComboFolder_IGNORE(comboIndex = 1) @@ -1232,7 +1290,7 @@ static Function StatsComplainsAboutIntersectingRanges() FillEventWave_IGNORE(psxEvent, id, comboKey) try - MIES_PSX#PSX_OperationStatsImpl(browser, id, {ranges}, selectData, "amp", "all", "nothing") + MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArray, "amp", "all", "nothing") FAIL() catch error = ROStr(GetSweepFormulaParseErrorMessage()) @@ -1259,7 +1317,7 @@ static Function StatsAllProperties([STRUCT IUTF_mData &m]) [browser, device, formulaGraph] = CreateFakeDataBrowserWithSweepFormulaGraph() - [WAVE range, WAVE selectData] = GetFakeRangeAndSelectData() + [WAVE range, WAVE selectData, WAVE/WAVE selectDataCompArray] = GetFakeRangeAndSelectData(browser) // 1st event wave WAVE/Z psxEvent = GetEventWave(comboIndex = 0) @@ -1267,7 +1325,7 @@ static Function StatsAllProperties([STRUCT IUTF_mData &m]) id = "myID" FillEventWave_IGNORE(psxEvent, id, comboKey) - MIES_PSX#PSX_OperationStatsImpl(browser, id, {range}, selectData, prop, "all", "nothing") + MIES_PSX#PSX_OperationStatsImpl(browser, id, selectDataCompArray, prop, "all", "nothing") CHECK_NO_RTE() End @@ -1316,7 +1374,7 @@ static Function TestOperationPSXKernel() CHECK_GE_VAR(jsonID, 0) WAVE/Z params = JSON_GetKeys(jsonID, SF_META_USER_GROUP + "Parameters/" + SF_OP_PSX_KERNEL) CHECK_WAVE(params, TEXT_WAVE) - CHECK_EQUAL_VAR(DimSize(params, ROWS), 4) + CHECK_EQUAL_VAR(DimSize(params, ROWS), 3) JSON_Release(jsonID) // offset for sweep data is 50 due to the range above @@ -1327,6 +1385,15 @@ static Function TestOperationPSXKernel() CheckDimensionScaleHelper(dataWref[4], 0, 0.01) CheckDimensionScaleHelper(dataWref[5], 50, 0.2) + str = "psxKernel([select(selRange([50, 150]), selchannels(AD6), selsweeps(0), selvis(all)), select(selRange([50, 150]), selchannels(AD6), selsweeps(2), 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), 6) + + actual = MIES_CA#CA_WaveCRCs(dataWref, includeWaveScalingAndUnits = 1) + // same hashes as above with only a single select + CHECK_EQUAL_STR(expected, actual) + // three waves from first range, none from second Make/FREE/T/N=(3, 1, 1) epochKeys epochKeys[0][0][0] = EPOCHS_ENTRY_KEY @@ -1339,6 +1406,11 @@ static Function TestOperationPSXKernel() 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] = "0.075" + epochsWave[1][EPOCH_COL_ENDTIME][DAC][XOP_CHANNEL_TYPE_DAC] = "0.175" + epochsWave[1][EPOCH_COL_TAGS][DAC][XOP_CHANNEL_TYPE_DAC] = "ShortName=E1;apples" + 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, 0, device, DATA_ACQUISITION_MODE) @@ -1376,6 +1448,15 @@ static Function TestOperationPSXKernel() catch PASS() endtry + + // overlapping intervals in one select statement + str = "psxKernel(select(selrange([E0, E1]), selchannels(AD6), selsweeps([0]), selvis(all)), 1, 15, -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) @@ -1456,7 +1537,7 @@ static Function TestOperationPSX([STRUCT IUTF_mData &m]) CHECK_GE_VAR(jsonID, 0) WAVE/Z params = JSON_GetKeys(jsonID, SF_META_USER_GROUP + "Parameters/" + SF_OP_PSX_KERNEL) CHECK_WAVE(params, TEXT_WAVE) - CHECK_EQUAL_VAR(DimSize(params, ROWS), 4) + CHECK_EQUAL_VAR(DimSize(params, ROWS), 3) WAVE/Z params = JSON_GetKeys(jsonID, SF_META_USER_GROUP + "Parameters/" + SF_OP_PSX) CHECK_WAVE(params, TEXT_WAVE) @@ -2025,7 +2106,7 @@ static Function/WAVE GetCodeVariations() string code - Make/T/N=(2)/FREE wv + Make/T/N=(3)/FREE wv wv[0] = GetTestCode("nothing") code = "" @@ -2039,6 +2120,15 @@ static Function/WAVE GetCodeVariations() wv[1] = code code = "" + // same as code[1] but with a select array for stats + 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))), 1.5, 100, 0)" + code += "\r and \r" + code += "psxStats(myId, [select(selrange([50, 150]), selchannels(AD6), selsweeps([0]), selvis(all)), select(selrange([50, 150]), selchannels(AD6), selsweeps([2]), selvis(all))], peak, all, nothing)" + wv[2] = code + code = "" + return wv End