diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index a8fb0b502f..55d7fa43e4 100644 --- a/Packages/MIES/MIES_Constants.ipf +++ b/Packages/MIES/MIES_Constants.ipf @@ -2522,6 +2522,7 @@ StrConstant SF_OP_TPSS = "tpss" StrConstant SF_OP_TPINST = "tpinst" StrConstant SF_OP_TPBASE = "tpbase" StrConstant SF_OP_TPFIT = "tpfit" +StrConstant SF_OP_EXTRACT = "extract" ///@} /// @name SF operations shorts diff --git a/Packages/MIES/MIES_SweepFormula.ipf b/Packages/MIES/MIES_SweepFormula.ipf index 54d54b4ca7..1f3a4b2bcc 100644 --- a/Packages/MIES/MIES_SweepFormula.ipf +++ b/Packages/MIES/MIES_SweepFormula.ipf @@ -70,7 +70,7 @@ Function/WAVE SF_GetNamedOperations() SF_OP_MERGE, SF_OP_FIT, SF_OP_FITLINE, SF_OP_DATASET, SF_OP_SELECTVIS, SF_OP_SELECTCM, SF_OP_SELECTSTIMSET, \ SF_OP_SELECTIVSCCSWEEPQC, SF_OP_SELECTIVSCCSETQC, SF_OP_SELECTRANGE, SF_OP_SELECTEXP, SF_OP_SELECTDEV, \ SF_OP_SELECTEXPANDSCI, SF_OP_SELECTEXPANDRAC, SF_OP_SELECTSETCYCLECOUNT, SF_OP_SELECTSETSWEEPCOUNT, \ - SF_OP_SELECTSCIINDEX, SF_OP_SELECTRACINDEX, SF_OP_ANAFUNCPARAM, SF_OP_CONCAT} + SF_OP_SELECTSCIINDEX, SF_OP_SELECTRACINDEX, SF_OP_ANAFUNCPARAM, SF_OP_CONCAT, SF_OP_EXTRACT} return wt End diff --git a/Packages/MIES/MIES_SweepFormula_Executor.ipf b/Packages/MIES/MIES_SweepFormula_Executor.ipf index ca0583da6f..ebe1757c75 100644 --- a/Packages/MIES/MIES_SweepFormula_Executor.ipf +++ b/Packages/MIES/MIES_SweepFormula_Executor.ipf @@ -469,6 +469,9 @@ Function/WAVE SFE_FormulaExecutor(STRUCT SF_ExecutionData &exd, [variable srcLoc case SF_OP_DATASET: WAVE out = SFO_OperationDataset(exdop) break + case SF_OP_EXTRACT: + WAVE out = SFO_OperationExtract(exdop) + break case SF_OP_SELECTVIS: WAVE out = SFOS_OperationSelectVis(exdop) break diff --git a/Packages/MIES/MIES_SweepFormula_Helpers.ipf b/Packages/MIES/MIES_SweepFormula_Helpers.ipf index c27068f2fb..a1c1f3439d 100644 --- a/Packages/MIES/MIES_SweepFormula_Helpers.ipf +++ b/Packages/MIES/MIES_SweepFormula_Helpers.ipf @@ -248,7 +248,9 @@ End /// @param copy [optional, defaults to 0] If the returned data should be safe for modification (true) or is only read (false) /// @param[out] wvNote [optional, defaults to None] Wave note of the dataset, useful for single result cases where you still need /// to query JSON wave note entries -Function/WAVE SFH_GetArgumentAsWave(STRUCT SF_ExecutionData &exd, string opShort, variable argNum, [string defOp, WAVE/Z defWave, variable singleResult, variable expectedMinorType, variable expectedMajorType, variable copy, string &wvNote]) +/// @param resolveSelect [optional, defaults to 0] If set then argument of the select type are automatically converted to sweep data, effectively the data() operation is applied +/// As with data, if the argument is an array of selects, each sweep result gets concatenated to a wref wave +Function/WAVE SFH_GetArgumentAsWave(STRUCT SF_ExecutionData &exd, string opShort, variable argNum, [string defOp, WAVE/Z defWave, variable singleResult, variable expectedMinorType, variable expectedMajorType, variable copy, string &wvNote, variable resolveSelect]) variable checkExist, numArgs, checkMinorType, checkMajorType, result string msg @@ -273,12 +275,23 @@ Function/WAVE SFH_GetArgumentAsWave(STRUCT SF_ExecutionData &exd, string opShort else singleResult = !!singleResult endif - copy = ParamIsDefault(copy) ? 0 : !!copy + copy = ParamIsDefault(copy) ? 0 : !!copy + resolveSelect = ParamIsDefault(resolveSelect) ? 0 : !!resolveSelect numArgs = SFH_GetNumberOfArguments(exd) if(argNum < numArgs) - WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, argNum) + if(resolveSelect) + WAVE/Z/WAVE input = SFH_GetArgumentSelect(exd, argNum, doNotEnforce = 1) + if(WaveExists(input)) + WAVE/WAVE data = SFH_GetDataFromSelect(exd.graph, input) + WAVE input = data + else + WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, argNum) + endif + else + WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, argNum) + endif if(singleResult) sprintf msg, "Argument #%d of operation %s: Too many input values", argNum, opShort @@ -1067,16 +1080,24 @@ End /// There is also a quick path for argNum >= numArgs, which is the case for e.g. data() /// For that case numArgs is 0 and select is expected at argNum 0. Then the result of "select()" is /// returned (as selectArray with a single element) +/// If the doNotEnforce flag is set then a select type value at the arguments location is not enforced. +/// If the argument is neither a single select or an array of selects then a null wave is returned. /// /// selectArray is wave reference wave containing select composite wave reference waves with SELECTION, RANGE each. /// /// This allows operations with selects as arguments to iterate over different selections given by the user -Function/WAVE SFH_GetArgumentSelect(STRUCT SF_ExecutionData &exd, string opShort, variable argNum) +Function/WAVE SFH_GetArgumentSelect(STRUCT SF_ExecutionData &exd, variable argNum, [variable doNotEnforce]) - variable numArgs - string type + variable numArgs, cond + string type + + doNotEnforce = ParamIsDefault(doNotEnforce) ? 0 : !!doNotEnforce numArgs = SFH_GetNumberOfArguments(exd) + if(argNum >= numArgs && doNotEnforce) + return $"" + endif + if(argNum < numArgs) WAVE/WAVE selectComp = SF_ResolveDatasetFromJSON(exd, argNum) @@ -1087,15 +1108,31 @@ Function/WAVE SFH_GetArgumentSelect(STRUCT SF_ExecutionData &exd, string opShort return selectArray endif - SFH_ASSERT(DimSize(selectComp, ROWS) == 1, "Expected a single array") + cond = DimSize(selectComp, ROWS) == 1 + if(doNotEnforce && !cond) + return $"" + endif + SFH_ASSERT(cond, "Expected a single array") WAVE array = selectComp[0] - SFH_ASSERT(IsTextWave(array), "Expected a text wave") + cond = IsTextWave(array) + if(doNotEnforce && !cond) + return $"" + endif + SFH_ASSERT(cond, "Expected a text wave") Make/FREE/WAVE/N=(DimSize(array, ROWS)) selectArray = SFH_AttemptDatasetResolve(WaveText(array, row = p), checkWithSFHAssert = 1) for(WAVE/Z/WAVE selectComp : selectArray) - ASSERT(WaveExists(selectComp), "Expected select composite") + cond = WaveExists(selectComp) + if(doNotEnforce && !cond) + return $"" + endif + ASSERT(cond, "Expected select composite") type = JWN_GetStringFromWaveNote(selectComp, SF_META_DATATYPE) - SFH_ASSERT(!CmpStr(type, SF_DATATYPE_SELECTCOMP), "Expected select data as argument") + cond = !CmpStr(type, SF_DATATYPE_SELECTCOMP) + if(doNotEnforce && !cond) + return $"" + endif + SFH_ASSERT(cond, "Expected select data as argument") endfor return selectArray @@ -2070,3 +2107,53 @@ Function SFH_StoreAssertInfoExecutor(variable jsonId, variable srcLocId, string info[%JSONPATH] = jsonPath info[%STEP] = num2istr(SF_STEP_EXECUTOR) End + +Function/WAVE SFH_GetDataFromSelect(string graph, WAVE/WAVE selectData) + + WAVE/WAVE output = SFH_GetSweepsForFormula(graph, selectData, SF_OP_DATA) + if(!DimSize(output, ROWS)) + DebugPrint("Call to SFH_GetSweepsForFormula returned no results") + endif + + SFH_AddOpToOpStack(output, "", SF_OP_DATA) + SFH_ResetArgSetupStack(output, SF_OP_DATA) + + return output +End + +/// @brief Function returns a wave reference wave with one wave for each element of the dataset array +/// Each wave contains the resolved dataset (as wave references) +/// +/// @param exd Execution data structure +/// @param argNum Argument index +/// @param resolveSelect [optional, defaults to 0] If set then argument of the select type are automatically converted to sweep data, effectively the data() operation is applied +/// As with data, if the argument is an array of selects, each sweep result gets concatenated to a wref wave +/// @returns wref wave with one wave for each dataset array element. Each wave contains the resolved dataset as waveref wave. +Function/WAVE SFH_GetDatasetArrayAsResolvedWaverefs(STRUCT SF_ExecutionData &exd, variable argNum, [variable resolveSelect]) + + variable numGroups + + resolveSelect = ParamIsDefault(resolveSelect) ? 0 : !!resolveSelect + + SFH_ASSERT(argNum < SFH_GetNumberOfArguments(exd), "operation has no argument number " + num2istr(argNum)) + if(resolveSelect) + WAVE/Z/WAVE input = SFH_GetArgumentSelect(exd, argNum, doNotEnforce = 1) + if(WaveExists(input)) + // In contrast to SFH_GetArgumentAsWave, resolve all selects from the array separately + numGroups = DimSize(input, ROWS) + SFH_ASSERT(numGroups >= 2, "First argument must be an array with at least two elements") + Make/FREE/WAVE/N=(numGroups) dataFromEachGroup = SFH_GetDataFromSelect(exd.graph, {input[p]}) + endif + endif + + if(!WaveExists(dataFromEachGroup)) + WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, argNum) + SFH_ASSERT(IsTextWave(input[0]), "Expected a dataset") + WAVE/T elemRefs = input[0] + numGroups = DimSize(elemRefs, ROWS) + SFH_ASSERT(numGroups > 1, "First argument must be an array with at least two elements") + Make/FREE/WAVE/N=(numGroups) dataFromEachGroup = SFH_AttemptDatasetResolve(elemRefs[p], checkWithSFHAssert = 1) + endif + + return dataFromEachGroup +End diff --git a/Packages/MIES/MIES_SweepFormula_Operations.ipf b/Packages/MIES/MIES_SweepFormula_Operations.ipf index 982e74b947..54b8e9a7b7 100644 --- a/Packages/MIES/MIES_SweepFormula_Operations.ipf +++ b/Packages/MIES/MIES_SweepFormula_Operations.ipf @@ -32,6 +32,7 @@ static StrConstant SF_OP_APFREQUENCY_X_TIME = "time" static StrConstant SF_OP_AVG_INSWEEPS = "in" static StrConstant SF_OP_AVG_OVERSWEEPS = "over" +static StrConstant SF_OP_AVG_GROUPS = "group" static StrConstant SF_OP_EPOCHS_TYPE_RANGE = "range" static StrConstant SF_OP_EPOCHS_TYPE_NAME = "name" @@ -62,7 +63,7 @@ Function/WAVE SFO_OperationAnaFuncParam(STRUCT SF_ExecutionData &exd) SFH_CheckArgumentCount(exd, SF_OP_ANAFUNCPARAM, 0, maxArgs = 2) WAVE/T names = SFH_GetArgumentAsWave(exd, SF_OP_ANAFUNCPARAM, 0, singleResult = 1) - WAVE/Z selectData = SFH_GetArgumentSelect(exd, SF_OP_DATA, 1) + WAVE/Z selectData = SFH_GetArgumentSelect(exd, 1) WAVE/WAVE output = SFO_OperationAnaFuncParamIterate(exd.graph, names, selectData, SF_OP_ANAFUNCPARAM) @@ -487,29 +488,72 @@ End Function/WAVE SFO_OperationAvg(STRUCT SF_ExecutionData &exd) - variable numArgs - string mode + variable numArgs, numGroups + string mode string opShort = SF_OP_AVG numArgs = SFH_CheckArgumentCount(exd, opShort, 1, maxArgs = 2) - WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, 0) - mode = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_AVG_INSWEEPS, allowedValues = {SF_OP_AVG_INSWEEPS, SF_OP_AVG_OVERSWEEPS}) + mode = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_AVG_INSWEEPS, allowedValues = {SF_OP_AVG_INSWEEPS, SF_OP_AVG_OVERSWEEPS, SF_OP_AVG_GROUPS}) + // attempt to resolve as select type argument or array of it + WAVE/Z/WAVE input = SFH_GetArgumentSelect(exd, 0, doNotEnforce = 1) - strswitch(mode) - case SF_OP_AVG_INSWEEPS: - WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, DimSize(input, ROWS)) - output[] = SFO_OperationAvgImplIn(input[p]) - SFH_TransferFormulaDataWaveNoteAndMeta(input, output, opShort, SF_DATATYPE_AVG) - return SFH_GetOutputForExecutor(output, exd.graph, opShort, clear = input) + if(!CmpStr(mode, SF_OP_AVG_INSWEEPS) || !CmpStr(mode, SF_OP_AVG_OVERSWEEPS)) + WAVE/WAVE input = SFH_GetArgumentAsWave(exd, opShort, 0, resolveSelect = 1) + strswitch(mode) + case SF_OP_AVG_INSWEEPS: + WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, DimSize(input, ROWS)) + output[] = SFO_OperationAvgImplIn(input[p]) + SFH_TransferFormulaDataWaveNoteAndMeta(input, output, opShort, SF_DATATYPE_AVG) + return SFH_GetOutputForExecutor(output, exd.graph, opShort, clear = input) - case SF_OP_AVG_OVERSWEEPS: - return SFO_OperationAvgImplOver(input, exd.graph, opShort) + case SF_OP_AVG_OVERSWEEPS: + return SFO_OperationAvgImplOver(input, exd.graph, opShort) - default: - FATAL_ERROR("Unknown avg operation mode") - endswitch + default: + FATAL_ERROR("Unhandled avg operation mode") + endswitch + elseif(!CmpStr(mode, SF_OP_AVG_GROUPS)) + WAVE/WAVE dataFromEachGroup = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 0, resolveSelect = 1) + WAVE/WAVE averagedGroup = SFO_OperationAvgImplSweepGroups(dataFromEachGroup, exd.graph, opShort) + SFH_TransferFormulaDataWaveNoteAndMeta(dataFromEachGroup[0], averagedGroup, opShort, opShort) + return SFH_GetOutputForExecutor(averagedGroup, exd.graph, opShort) + else + FATAL_ERROR("Unhandled avg operation mode") + endif +End + +static Function/WAVE SFO_OperationAvgImplSweepGroups(WAVE/WAVE sweepsFromEachSelection, string graph, string opShort) + + variable numData, numMaxSweeps, numGroups, i, j + STRUCT RGBColor s + + [s] = GetTraceColorForAverage() + Make/FREE/W/U traceColor = {s.red, s.green, s.blue} + + numGroups = DimSize(sweepsFromEachSelection, ROWS) + Make/FREE/D/N=(numGroups) sweepCnts = DimSize(sweepsFromEachSelection[p], ROWS) + numMaxSweeps = WaveMax(sweepCnts) + WAVE/WAVE output = SFH_CreateSFRefWave(graph, opShort, numMaxSweeps) + for(i = 0; i < numMaxSweeps; i += 1) + Make/FREE/WAVE/N=(numGroups) avgSet + numData = 0 + for(j = 0; j < numGroups; j += 1) + if(DimSize(sweepsFromEachSelection[j], ROWS) > i) + avgSet[numData] = WaveRef(sweepsFromEachSelection[j], row = i) + numData += 1 + endif + endfor + Redimension/N=(numData) avgSet + WAVE/WAVE avg = MIES_fWaveAverage(avgSet, 1, IGOR_TYPE_64BIT_FLOAT) + output[i] = avg[0] + JWN_SetWaveInWaveNote(output[i], SF_META_TRACECOLOR, traceColor) + JWN_SetNumberInWaveNote(output[i], SF_META_TRACETOFRONT, 1) + JWN_SetNumberInWaveNote(output[i], SF_META_LINESTYLE, 0) + endfor + + return output End static Function/WAVE SFO_OperationAvgImplOver(WAVE/WAVE input, string graph, string opShort) @@ -677,15 +721,9 @@ Function/WAVE SFO_OperationData(STRUCT SF_ExecutionData &exd) variable i, numArgs SFH_CheckArgumentCount(exd, SF_OP_DATA, 0, maxArgs = 1) - WAVE/WAVE selectData = SFH_GetArgumentSelect(exd, SF_OP_DATA, 0) - - WAVE/WAVE output = SFH_GetSweepsForFormula(exd.graph, selectData, SF_OP_DATA) - if(!DimSize(output, ROWS)) - DebugPrint("Call to SFH_GetSweepsForFormula returned no results") - endif + WAVE/WAVE selectData = SFH_GetArgumentSelect(exd, 0) - SFH_AddOpToOpStack(output, "", SF_OP_DATA) - SFH_ResetArgSetupStack(output, SF_OP_DATA) + WAVE output = SFH_GetDataFromSelect(exd.graph, selectData) return SFH_GetOutputForExecutor(output, exd.graph, SF_OP_DATA) End @@ -704,6 +742,24 @@ Function/WAVE SFO_OperationDataset(STRUCT SF_ExecutionData &exd) return SFH_GetOutputForExecutor(output, exd.graph, SF_OP_DATASET) End +// extract(, index) +Function/WAVE SFO_OperationExtract(STRUCT SF_ExecutionData &exd) + + variable idx + string opShort = SF_OP_EXTRACT + + SFH_CheckArgumentCount(exd, opShort, 2, maxArgs = 2) + + WAVE/WAVE datasets = SFH_GetArgumentAsWave(exd, opShort, 0) + idx = SFH_GetArgumentAsNumeric(exd, opShort, 1) + SFH_ASSERT(idx < DimSize(datasets, ROWS), "index out of range") + + WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, 1) + output[0] = datasets[idx] + + return SFH_GetOutputForExecutor(output, exd.graph, opShort) +End + Function/WAVE SFO_OperationDerivative(STRUCT SF_ExecutionData &exd) variable numArgs @@ -808,7 +864,7 @@ Function/WAVE SFO_OperationEpochs(STRUCT SF_ExecutionData &exd) endif WAVE/Z/WAVE selectData = $"" - WAVE/Z/WAVE selectDataArray = SFH_GetArgumentSelect(exd, SF_OP_EPOCHS, 1) + WAVE/Z/WAVE selectDataArray = SFH_GetArgumentSelect(exd, 1) if(WaveExists(selectDataArray)) SFH_ASSERT(DimSize(selectDataArray, ROWS) == 1, "Expected a single select specification") WAVE/Z/WAVE selectDataComp = selectDataArray[0] @@ -1090,7 +1146,7 @@ Function/WAVE SFO_OperationLabnotebook(STRUCT SF_ExecutionData &exd) modeTxt = SFH_GetArgumentAsText(exd, SF_OP_LABNOTEBOOK, 2, allowedValues = allowedValuesMode, defValue = "DATA_ACQUISITION_MODE") mode = ParseLogbookMode(modeTxt) - WAVE/Z selectData = SFH_GetArgumentSelect(exd, SF_OP_LABNOTEBOOK, 1) + WAVE/Z selectData = SFH_GetArgumentSelect(exd, 1) WAVE/T lbnKeys = SFH_GetArgumentAsWave(exd, SF_OP_LABNOTEBOOK, 0, expectedMajorType = IGOR_TYPE_TEXT_WAVE, singleResult = 1) diff --git a/Packages/MIES/MIES_SweepFormula_Operations_TP.ipf b/Packages/MIES/MIES_SweepFormula_Operations_TP.ipf index b686e91106..645b73eac3 100644 --- a/Packages/MIES/MIES_SweepFormula_Operations_TP.ipf +++ b/Packages/MIES/MIES_SweepFormula_Operations_TP.ipf @@ -42,7 +42,7 @@ Function/WAVE SFOTP_OperationTP(STRUCT SF_ExecutionData &exd) WAVE/Z ignoreTPs endif - WAVE/Z selectData = SFH_GetArgumentSelect(exd, SF_OP_TP, 1) + WAVE/Z selectData = SFH_GetArgumentSelect(exd, 1) WAVE/WAVE wMode = SF_ResolveDatasetFromJSON(exd, 0) dataType = JWN_GetStringFromWaveNote(wMode, SF_META_DATATYPE) diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index b569b76824..159c4ccadb 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -4760,7 +4760,7 @@ Function/WAVE PSX_OperationKernel(STRUCT SF_ExecutionData &exd) SFH_CheckArgumentCount(exd, SF_OP_PSX_KERNEL, 0, maxArgs = 4) - WAVE/Z/WAVE selectDataCompArray = SFH_GetArgumentSelect(exd, SF_OP_PSX_KERNEL, 0) + WAVE/Z/WAVE selectDataCompArray = SFH_GetArgumentSelect(exd, 0) SFH_ASSERT(WaveExists(selectDataCompArray), "Could not gather sweep data from select statement") riseTau = SFH_GetArgumentAsNumeric(exd, SF_OP_PSX_KERNEL, 1, defValue = 1, checkFunc = IsStrictlyPositiveAndFinite) @@ -4910,7 +4910,7 @@ Function/WAVE PSX_OperationStats(STRUCT SF_ExecutionData &exd) id = SFH_GetArgumentAsText(exd, SF_OP_PSX, 0, checkFunc = IsValidObjectName) - WAVE/Z/WAVE selectDataCompArray = SFH_GetArgumentSelect(exd, SF_OP_PSX_STATS, 1) + WAVE/Z/WAVE selectDataCompArray = SFH_GetArgumentSelect(exd, 1) SFH_Assert(WaveExists(selectDataCompArray), "Missing select data") WAVE allProps = PSX_GetAllStatsProperties() diff --git a/Packages/MIES/SweepFormulaHelp.ifn b/Packages/MIES/SweepFormulaHelp.ifn index 3291873892..4c8703ecf8 100644 Binary files a/Packages/MIES/SweepFormulaHelp.ifn and b/Packages/MIES/SweepFormulaHelp.ifn differ diff --git a/Packages/doc/SweepFormula.rst b/Packages/doc/SweepFormula.rst index b956b07613..7ee9e269d1 100644 --- a/Packages/doc/SweepFormula.rst +++ b/Packages/doc/SweepFormula.rst @@ -332,11 +332,15 @@ avg and mean `avg` and `mean` are synonyms for the same operation. They calculate the arithmetic average :math:`\frac{1}{n}\sum_i{x_i}`. -data: input data wave(s) +data: input data wave(s) or array of datasets mode: optional parameter that defines in which direction the average is applied. - `in` default, applies the average over each input data wave. In this mode the operation returns the same number of waves as input waves were specified. Each output wave contains a single data point. If input data type is `SF_DATATYPE_SWEEP` from the data operation the sweep meta data is transferred to the returned data waves. The default suggested x-axis values for the formula plotter are sweep numbers. - `over` averages over all input data waves. In this mode the operation returns a single wave. `NaN` values in input waves are ignored in the average calculation. A trace generated from the returned wave will be shown as topmost trace in the default color for averaged data. + - `group` accepts an array of datasets as the first argument where each dataset must have the same number of elements. The average calculation is performed over the n-th elements of each dataset. Example: Lets say one has three datasets of sweep data with sweep 1, 2, 3; 4, 5, 6 and 7, 8, 9. Each prepared in an own variable `sweepset0`, `sweepset1` and `sweepset2`. When `avg([$sweepset0, $sweepset1, $sweepset2], group)` is called the averaging works on sweep 1, 4, 7, then 2, 5, 8 and finally 3, 6, 9. The result is a new dataset of the same size (three) as the input datasets. The input datasets can be of any type and do not need to be sweep data. The first argument must contain at least two datasets. Meta data (if present) is transferred from the first element datasets in the array to the result. + +When an argument is of the select type then automatically data is applied to implicitly convert to sweep data. +This conversion is also applied in the `group` mode for array element that are of select type. The returned data type is `SF_DATATYPE_AVG`. @@ -348,6 +352,21 @@ The returned data type is `SF_DATATYPE_AVG`. avg(data(select(selrange(ST))), in) + avg([select(selrange(E1)), select(selrange(E2))], group) + +extract +""""""" + +.. code-block:: bash + + extract(datasets, index) + +`extract` takes datasets as first argument and an index number as second argument. It returns the dataset from position index. + +.. code-block:: bash + + sweep2DA = extract(data(select(selsweeps(1, 2, 3), selvis(all), selchannels(DA))), 1) + root mean square """""""""""""""" diff --git a/Packages/tests/Basic/UTF_SweepFormula_Operations.ipf b/Packages/tests/Basic/UTF_SweepFormula_Operations.ipf index 8ce6c68b23..e192749993 100644 --- a/Packages/tests/Basic/UTF_SweepFormula_Operations.ipf +++ b/Packages/tests/Basic/UTF_SweepFormula_Operations.ipf @@ -1218,6 +1218,90 @@ static Function TestOperationAverage() CHECK_EQUAL_VAR(JWN_GetNumberFromWaveNote(data, SF_META_LINESTYLE), 0) WAVE/Z tColor = JWN_GetNumericWaveFromWaveNote(data, SF_META_TRACECOLOR) CHECK_EQUAL_WAVES(tColor, {s.red, s.green, s.blue}, mode = WAVE_DATA) + + str = "ds0 = dataset(1, 2, 3)\rds1 = dataset(2, 3, 4)\r\ravg([$ds0, $ds1], group)" + WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win) + CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 3) + WAVE wv0 = dataRef[0] + CHECK_EQUAL_WAVES(wv0, {1.5}, mode = WAVE_DATA) + WAVE wv1 = dataRef[1] + CHECK_EQUAL_WAVES(wv1, {2.5}, mode = WAVE_DATA) + WAVE wv2 = dataRef[2] + CHECK_EQUAL_WAVES(wv2, {3.5}, mode = WAVE_DATA) + + str = "ds0 = dataset(1, 2, 3)\rds1 = dataset(2, 3, 4)\rds2 = dataset(6, 10, 14)\r\ravg([$ds0, $ds1, $ds2], group)" + WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win) + CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 3) + WAVE wv0 = dataRef[0] + CHECK_EQUAL_WAVES(wv0, {3}, mode = WAVE_DATA) + WAVE wv1 = dataRef[1] + CHECK_EQUAL_WAVES(wv1, {5}, mode = WAVE_DATA) + WAVE wv2 = dataRef[2] + CHECK_EQUAL_WAVES(wv2, {7}, mode = WAVE_DATA) + + try + str = "ds0 = dataset(1, 2, 3)\r\ravg([$ds0], group)" + WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win) + FAIL() + catch + PASS() + endtry + + try + str = "avg(1, group)" + WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win) + FAIL() + catch + PASS() + endtry +End + +static Function TestOperationAverage2() + + string win, device + string str + variable sweepNo, numResults, i + + [win, device] = CreateEmptyUnlockedDataBrowserWindow() + + sweepNo = 0 + + win = CreateFakeSweepData(win, device, sweepNo = sweepNo) + win = CreateFakeSweepData(win, device, sweepNo = sweepNo + 1) + + // Meta Data Transfer from first group + str = "ds0 = data(select(selsweeps(0), selvis(all)))\rds1 = data(select(selsweeps(1), selvis(all)))\r\ravg([$ds0, $ds1], group)" + WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win) + CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 4) + WAVE wv0 = dataRef[0] + sweepNo = JWN_GetNumberFromWaveNote(wv0, SF_META_SWEEPNO) + CHECK_EQUAL_VAR(sweepNo, 0) + + // Use implicit select resolve instead + str = "avg([select(selsweeps(0), selvis(all)), select(selsweeps(1), selvis(all))], group)" + WAVE/WAVE dataRef2 = SFE_ExecuteFormula(str, win) + CHECK_EQUAL_VAR(DimSize(dataRef2, ROWS), 4) + + numResults = DimSize(dataRef2, ROWS) + for(i = 0; i < numResults; i += 1) + WAVE wv0 = dataRef[i] + WAVE wv1 = dataRef2[i] + JWN_SetNumberInWaveNote(wv0, SF_META_COLOR_GROUP, 0) + JWN_SetNumberInWaveNote(wv1, SF_META_COLOR_GROUP, 0) + CHECK_EQUAL_WAVES(wv0, wv1) + endfor + + str = "avg(select(selsweeps(0, 1), selvis(all)))" + WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win) + CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 8) + WAVE wv0 = dataref[0] + CHECK_EQUAL_WAVES(wv0, {4.5}, mode = WAVE_DATA) + + str = "avg(select(selsweeps(0, 1), selvis(all)), over)" + WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win) + CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 1) + WAVE wv0 = dataref[0] + CHECK_EQUAL_WAVES(wv0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, mode = WAVE_DATA) End static Function CheckSweepsFromData(WAVE/WAVE dataWref, WAVE sweepRef, variable numResults, WAVE chanIndex, [WAVE ranges]) @@ -3547,3 +3631,56 @@ static Function TestOperationAnaFuncParam() idx += 1 endfor End + +static Function TestOperationExtract() + + string str, wavePath + string win + + win = GetDataBrowserWithData() + + str = "extract(1)" + try + WAVE data = SFE_ExecuteFormula(str, win, singleResult = 1, useVariables = 0) + FAIL() + catch + PASS() + endtry + + str = "extract(1,1,1)" + try + WAVE data = SFE_ExecuteFormula(str, win, singleResult = 1, useVariables = 0) + FAIL() + catch + PASS() + endtry + + str = "extract(1,a)" + try + WAVE data = SFE_ExecuteFormula(str, win, singleResult = 1, useVariables = 0) + FAIL() + catch + PASS() + endtry + + str = "extract(1,0)" + WAVE data = SFE_ExecuteFormula(str, win, singleResult = 1, useVariables = 0) + CHECK_EQUAL_WAVES(data, {1}, mode = WAVE_DATA) + + str = "extract(a,0)" + WAVE data = SFE_ExecuteFormula(str, win, singleResult = 1, useVariables = 0) + Make/FREE/T ref = {"a"} + CHECK_EQUAL_WAVES(data, ref, mode = WAVE_DATA) + + str = "extract([1,2],0)" + WAVE data = SFE_ExecuteFormula(str, win, singleResult = 1, useVariables = 0) + CHECK_EQUAL_WAVES(data, {1, 2}, mode = WAVE_DATA) + + str = "extract(dataset(1,2),0)" + WAVE data = SFE_ExecuteFormula(str, win, singleResult = 1, useVariables = 0) + CHECK_EQUAL_WAVES(data, {1}, mode = WAVE_DATA) + + str = "extract(dataset(1,2),1)" + WAVE data = SFE_ExecuteFormula(str, win, singleResult = 1, useVariables = 0) + CHECK_EQUAL_WAVES(data, {2}, mode = WAVE_DATA) +End