diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index 5cee83a1eb..84e14984ac 100644 --- a/Packages/MIES/MIES_Constants.ipf +++ b/Packages/MIES/MIES_Constants.ipf @@ -2116,37 +2116,56 @@ StrConstant CO_DAP_DIFF_FALLBACK_NI = "DiffFallbackNI" /// @name Constants for SweepFormula Meta data in JSON format /// @anchor SFMetaDataConstants ///@{ -StrConstant SF_META_DATATYPE = "/DataType" // string -StrConstant SF_META_SWEEPNO = "/SweepNumber" // number -StrConstant SF_META_RANGE = "/Range" // numeric wave -StrConstant SF_META_CHANNELTYPE = "/ChannelType" // number -StrConstant SF_META_CHANNELNUMBER = "/ChannelNumber" // number -StrConstant SF_META_DEVICE = "/Device" // string -StrConstant SF_META_EXPERIMENT = "/Experiment" // string -StrConstant SF_META_SWEEPMAPINDEX = "/SweepMapIndex" // number -StrConstant SF_META_ISAVERAGED = "/IsAveraged" // number -StrConstant SF_META_XVALUES = "/XValues" // numeric wave -StrConstant SF_META_XTICKLABELS = "/XTickLabels" // text wave -StrConstant SF_META_XTICKPOSITIONS = "/XTickPositions" // numeric wave -StrConstant SF_META_YTICKLABELS = "/YTickLabels" // text wave -StrConstant SF_META_YTICKPOSITIONS = "/YTickPositions" // numeric wave -StrConstant SF_META_XAXISLABEL = "/XAxisLabel" // string -StrConstant SF_META_YAXISLABEL = "/YAxisLabel" // string -StrConstant SF_META_LEGEND_LINE_PREFIX = "/LegendLinePrefix" // string -StrConstant SF_META_TAG_TEXT = "/TagText" // string -StrConstant SF_META_OPSTACK = "/OperationStack" // string -StrConstant SF_META_MOD_MARKER = "/Marker" // numeric wave (per point) or number (all points) -StrConstant SF_META_SHOW_LEGEND = "/ShowLegend" // numeric, boolean, defaults to true (1) -StrConstant SF_META_CUSTOM_LEGEND = "/CustomLegend" // string with custom legend text, honours /ShowLegend -StrConstant SF_META_ARGSETUPSTACK = "/ArgSetupStack" // string -StrConstant SF_META_TRACECOLOR = "/TraceColor" // numeric wave, applies to markers and lines -StrConstant SF_META_LINESTYLE = "/LineStyle" // number -StrConstant SF_META_TRACE_MODE = "/TraceMode" // number, one of @ref TraceDisplayTypes -StrConstant SF_META_TRACETOFRONT = "/TraceToFront" // number, boolean, defaults to false (0) -StrConstant SF_META_DONOTPLOT = "/DoNotPlot" // number, boolean, defaults to false (0) -StrConstant SF_META_WINDOW_HOOK = "/WindowHook" // string -StrConstant SF_META_FORMULA = "/Formula" // string -StrConstant SF_META_PLOT = "/Plot" // number, boolean, defaults to false (0) +StrConstant SF_META_DATATYPE = "/DataType" // string +StrConstant SF_META_SWEEPNO = "/SweepNumber" // number +StrConstant SF_META_RANGE = "/Range" // numeric wave +StrConstant SF_META_CHANNELTYPE = "/ChannelType" // number +StrConstant SF_META_CHANNELNUMBER = "/ChannelNumber" // number +StrConstant SF_META_DEVICE = "/Device" // string +StrConstant SF_META_EXPERIMENT = "/Experiment" // string +StrConstant SF_META_SWEEPMAPINDEX = "/SweepMapIndex" // number +StrConstant SF_META_ISAVERAGED = "/IsAveraged" // number +StrConstant SF_META_XVALUES = "/XValues" // numeric wave +StrConstant SF_META_XTICKLABELS = "/XTickLabels" // text wave +StrConstant SF_META_XTICKPOSITIONS = "/XTickPositions" // numeric wave +StrConstant SF_META_YTICKLABELS = "/YTickLabels" // text wave +StrConstant SF_META_YTICKPOSITIONS = "/YTickPositions" // numeric wave +StrConstant SF_META_XAXISLABEL = "/XAxisLabel" // string +StrConstant SF_META_YAXISLABEL = "/YAxisLabel" // string +StrConstant SF_META_LEGEND_LINE_PREFIX = "/LegendLinePrefix" // string +StrConstant SF_META_TAG_TEXT = "/TagText" // string +StrConstant SF_META_OPSTACK = "/OperationStack" // string +StrConstant SF_META_MOD_MARKER = "/Marker" // numeric wave (per point) or number (all points) +StrConstant SF_META_SHOW_LEGEND = "/ShowLegend" // numeric, boolean, defaults to true (1) +StrConstant SF_META_CUSTOM_LEGEND = "/CustomLegend" // string with custom legend text, honours /ShowLegend +StrConstant SF_META_ARGSETUPSTACK = "/ArgSetupStack" // string +StrConstant SF_META_TRACECOLOR = "/TraceColor" // numeric wave, applies to markers and lines +StrConstant SF_META_LINESTYLE = "/LineStyle" // number +StrConstant SF_META_TRACE_MODE = "/TraceMode" // number, one of @ref TraceDisplayTypes +StrConstant SF_META_TRACETOFRONT = "/TraceToFront" // number, boolean, defaults to false (0) +StrConstant SF_META_DONOTPLOT = "/DoNotPlot" // number, boolean, defaults to false (0) +StrConstant SF_META_WINDOW_HOOK = "/WindowHook" // string +StrConstant SF_META_FORMULA = "/Formula" // string +StrConstant SF_META_PLOT = "/Plot" // number, boolean, defaults to false (0) +StrConstant SF_META_XAXISOFFSET = "/XAxisOffset" // number +StrConstant SF_META_YAXISOFFSET = "/YAxisOffset" // number +StrConstant SF_META_XAXISPERCENT = "/XAxisPercent" // number +StrConstant SF_META_YAXISPERCENT = "/YAxisPercent" // number +StrConstant SF_META_ERRORBARYPLUS = "/ErrorYPlus" // numeric wave +StrConstant SF_META_ERRORBARYMINUS = "/ErrorYMinus" // numeric wave +StrConstant SF_META_ERRORBARXPLUS = "/ErrorXPlus" // numeric wave +StrConstant SF_META_ERRORBARXMINUS = "/ErrorXMinus" // numeric wave +StrConstant SF_META_FITCOEFS = "/FitCoefs" // numeric wave +StrConstant SF_META_FITERROR = "/FitError" // number +StrConstant SF_META_FITQUITREASON = "/FitQuitReason" // number +StrConstant SF_META_FITNUMITERS = "/FitNumIters" // number +StrConstant SF_META_FITSTATUSMESSAGE = "/FitStatusMessage" // string +StrConstant SF_META_FITWSIGMA = "/FitWSigma" // numeric wave +StrConstant SF_META_FITMCOVAR = "/FitMCovar" // numeric wave +StrConstant SF_META_FITMFITCONSTRAINT = "/FitMFitConstraint" // numeric wave +StrConstant SF_META_FITWFITCONSTRAINT = "/FitWFitConstraint" // numeric wave +StrConstant SF_META_FITCHISQUARE = "/FitChiSquare" // number +StrConstant SF_META_FITFUNC = "/FitFunc" // string /// A color group allows to have matching colors for sweep data with the same channel type/number and sweep. /// It is applied before the matching headstage/average colors in #SF_GetTraceColor(). @@ -2205,12 +2224,14 @@ StrConstant SF_DATATYPE_SELECTSETSWEEPCOUNT = "SelectSetSweepCount" StrConstant SF_DATATYPE_SELECTSCIINDEX = "SelectSCIIndex" StrConstant SF_DATATYPE_SELECTRACINDEX = "SelectRACIndex" StrConstant SF_DATATYPE_ANAFUNCPARAM = "AnaFunc" +StrConstant SF_DATATYPE_PREPAREFIT = "PrepareFit" StrConstant SF_WREF_MARKER = "\"WREF@\":" StrConstant SF_VARIABLE_MARKER = "/SF_IsVariable" // numeric StrConstant SF_ANNOTATION_NAME = "metadata" StrConstant SF_VARNAME_REGEXP = "[A-Z]{1}[A-Z0-9_]*" +StrConstant SF_SERIALIZE = "/serial" // path prefix ///@} /// @name Constants for SweepFormula Clampmode codes returned by operation selcm() @@ -2442,11 +2463,6 @@ Constant PSX_DECONV_FILTER_DEF_ORDER = 4 StrConstant PSX_JWN_COMBO_KEYS_NAME = "ComboKeys" -StrConstant SF_OP_MERGE = "merge" -StrConstant SF_OP_FIT = "fit" -StrConstant SF_OP_FITLINE = "fitline" -StrConstant SF_OP_DATASET = "dataset" - StrConstant SWEEP_NOTE_KEY_ORIGCREATIONTIME_UTC = "OriginalCreationTimeInUTC" StrConstant DF_NAME_FREE = "freeroot" @@ -2552,6 +2568,14 @@ StrConstant SF_OP_TPINST = "tpinst" StrConstant SF_OP_TPBASE = "tpbase" StrConstant SF_OP_TPFIT = "tpfit" StrConstant SF_OP_EXTRACT = "extract" +StrConstant SF_OP_IVSCCAPFREQUENCY = "ivscc_apfrequency" +StrConstant SF_OP_PREPAREFIT = "preparefit" +StrConstant SF_OP_MERGE = "merge" +StrConstant SF_OP_FIT = "fit" +StrConstant SF_OP_FITLINE = "fitline" +StrConstant SF_OP_DATASET = "dataset" +StrConstant SF_OP_FIT2 = "fit2" +StrConstant SF_OP_GETMETA = "getmeta" #ifdef AUTOMATED_TESTING StrConstant SF_OP_TESTOP = "testop" @@ -2614,3 +2638,38 @@ StrConstant SF_WINNAME_SUFFIX_TABLE = "table" Constant SF_DISPLAYTYPE_GRAPH = 0 Constant SF_DISPLAYTYPE_TABLE = 1 ///@} + +/// @name Maximum number of colors for traces defined +/// +/// @anchor TraceColorMax +///@{ +Constant TRACECOLORMAX = 21 +///@} + +/// @name Characters allowed in the SF PrepareFit operation to hold a coefficient +/// +/// @anchor SFPrepareFitHoldStringCharacters +///@{ +StrConstant SF_PREPAREFIT_HOLDCHAR_HOLD = "X" +StrConstant SF_PREPAREFIT_HOLDCHAR_FREE = "O" +///@} + +/// @name Bits for Fit Errors +/// @anchor FitErrors +///@{ +Constant FIT_ERROR_ANY = 1 +Constant FIT_ERROR_SINGULARMATRIX = 2 +Constant FIT_ERROR_OUTOFMEMORY = 4 +Constant FIT_ERROR_RETURNEDNANORINF = 8 +Constant FIT_ERROR_FUNCREQUESTEDSTOP = 16 +Constant FIT_ERROR_REENTRANT_FIT = 32 +///@} + +/// @name Codes for Fit Quit Reasons +/// @anchor FitQuitReason +///@{ +Constant FIT_QUITREASON_OK = 0 +Constant FIT_QUITREASON_ITERATIONLIMITREACHED = 1 +Constant FIT_QUITREASON_STOPPEDBYUSER = 2 +Constant FIT_QUITREASON_NOCHISQUAREDECREASE = 3 +///@} diff --git a/Packages/MIES/MIES_GuiUtilities.ipf b/Packages/MIES/MIES_GuiUtilities.ipf index cab833cefc..28bf71b9fc 100644 --- a/Packages/MIES/MIES_GuiUtilities.ipf +++ b/Packages/MIES/MIES_GuiUtilities.ipf @@ -650,7 +650,7 @@ End /// where the color white has been removed. Function [STRUCT RGBColor s] GetTraceColor(variable index) - index = mod(index, 21) + index = mod(index, TRACECOLORMAX) switch(index) case 0: s.red = 7967; s.green = 7710; s.blue = 7710 @@ -742,11 +742,21 @@ Function [STRUCT RGBColor s] GetTraceColor(variable index) endswitch End -/// @brief Returns the trace color used for avergae type traces +/// @brief Returns the trace color used for average type traces Function [STRUCT RGBColor s] GetTraceColorForAverage() [s] = GetTraceColor(NUM_HEADSTAGES + 1) +End + +/// @brief Returns a color that is not attributed to a headstage and not the average color +Function [STRUCT RGBColor s] GetTraceColorNonHeadstage(variable idx) + + variable range + + range = TRACECOLORMAX - (NUM_HEADSTAGES + 2) + idx = mod(idx, range) + [s] = GetTraceColor(idx + NUM_HEADSTAGES + 2) End /// @brief Get colors from alternative color scheme diff --git a/Packages/MIES/MIES_JSONWaveNotes.ipf b/Packages/MIES/MIES_JSONWaveNotes.ipf index 57a3442359..282f808a80 100644 --- a/Packages/MIES/MIES_JSONWaveNotes.ipf +++ b/Packages/MIES/MIES_JSONWaveNotes.ipf @@ -318,3 +318,18 @@ threadsafe Function/WAVE JWN_CreatePath(WAVE wv, string jsonPath) JSON_AddTreeObject(jsonID, jsonPath) JWN_WriteWaveNote(wv, JWN_GetWaveNoteHeader(wv), jsonID) End + +/// @brief Returns a text wave with the json keys available at path, null wave if path does not exist +/// +/// @param wv wave reference where the WaveNote is taken from +/// @param jsonPath path to create as object +threadsafe Function/WAVE JWN_GetKeysAt(WAVE wv, string jsonPath) + + variable jsonID + + jsonID = JWN_GetWaveNoteAsJSON(wv) + WAVE/Z keys = JSON_GetKeys(jsonID, jsonPath, ignoreErr = 1) + JSON_Release(jsonID) + + return keys +End diff --git a/Packages/MIES/MIES_SweepFormula.ipf b/Packages/MIES/MIES_SweepFormula.ipf index c6c8ed7408..63dac59d89 100644 --- a/Packages/MIES/MIES_SweepFormula.ipf +++ b/Packages/MIES/MIES_SweepFormula.ipf @@ -129,7 +129,8 @@ 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_TABLE, SF_OP_EXTRACT} + SF_OP_SELECTSCIINDEX, SF_OP_SELECTRACINDEX, SF_OP_ANAFUNCPARAM, SF_OP_CONCAT, SF_OP_TABLE, SF_OP_EXTRACT, \ + SF_OP_IVSCCAPFREQUENCY, SF_OP_PREPAREFIT, SF_OP_FIT2, SF_OP_GETMETA} #ifdef AUTOMATED_TESTING Make/FREE/T wtTest = {SF_OP_TESTOP} Concatenate/NP/T {wtTest}, wt @@ -152,19 +153,6 @@ Function/S SF_EscapeJsonPath(string str) return ReplaceString("/", str, "~1") End -/// @brief Retrieves the plot meta data from the JSON wave note or other sources and stores it in the plotMetaData wave -static Function/WAVE SF_FillPlotMetaData(WAVE wvYRef, variable useXLabel, string dataUnits) - - WAVE/T plotMetaData = GetSFPlotMetaData() - plotMetaData[%DATATYPE] = JWN_GetStringFromWaveNote(wvYRef, SF_META_DATATYPE) - plotMetaData[%OPSTACK] = JWN_GetStringFromWaveNote(wvYRef, SF_META_OPSTACK) - plotMetaData[%ARGSETUPSTACK] = JWN_GetStringFromWaveNote(wvYRef, SF_META_ARGSETUPSTACK) - plotMetaData[%XAXISLABEL] = SelectString(useXLabel, SF_XLABEL_USER, JWN_GetStringFromWaveNote(wvYRef, SF_META_XAXISLABEL)) - plotMetaData[%YAXISLABEL] = JWN_GetStringFromWaveNote(wvYRef, SF_META_YAXISLABEL) + dataUnits - - return plotMetaData -End - /// @brief transfer the wave scaling from one wave to another /// /// Note: wave scale transfer requires wave units for the first wave or second wave @@ -212,6 +200,23 @@ Function SF_FormulaWaveScaleTransfer(WAVE source, WAVE dest, variable dimSource, endswitch End +/// @brief Retrieves the plot meta data from the JSON wave note or other sources and stores it in the plotMetaData wave +static Function/WAVE SF_FillPlotMetaData(WAVE wvYRef, variable useXLabel, string dataUnits) + + WAVE/T plotMetaData = GetSFPlotMetaData() + plotMetaData[%DATATYPE] = JWN_GetStringFromWaveNote(wvYRef, SF_META_DATATYPE) + plotMetaData[%OPSTACK] = JWN_GetStringFromWaveNote(wvYRef, SF_META_OPSTACK) + plotMetaData[%ARGSETUPSTACK] = JWN_GetStringFromWaveNote(wvYRef, SF_META_ARGSETUPSTACK) + plotMetaData[%XAXISLABEL] = SelectString(useXLabel, SF_XLABEL_USER, JWN_GetStringFromWaveNote(wvYRef, SF_META_XAXISLABEL)) + plotMetaData[%YAXISLABEL] = JWN_GetStringFromWaveNote(wvYRef, SF_META_YAXISLABEL) + dataUnits + plotMetaData[%XAXISOFFSET] = num2str(JWN_GetNumberFromWaveNote(wvYRef, SF_META_XAXISOFFSET), "%f") + plotMetaData[%YAXISOFFSET] = num2str(JWN_GetNumberFromWaveNote(wvYRef, SF_META_YAXISOFFSET), "%f") + plotMetaData[%XAXISPERCENT] = num2str(JWN_GetNumberFromWaveNote(wvYRef, SF_META_XAXISPERCENT), "%f") + plotMetaData[%YAXISPERCENT] = num2str(JWN_GetNumberFromWaveNote(wvYRef, SF_META_YAXISPERCENT), "%f") + + return plotMetaData +End + static Function [WAVE/WAVE formulaResults, WAVE/T plotMetaData] SF_FillFormulaResults(WAVE/Z/WAVE wvYRef, WAVE/Z/WAVE wvXRef, string yFormula) variable i, numResultsY, numResultsX @@ -968,6 +973,7 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable STRUCT RGBColor color variable numTraces, yPoints, xPoints, yMxN, xMxN, idx, splitTraces variable i, isCategoryAxis, splitX, splitY + variable rangeBeginX, rangeEndX, rangeBeginY, rangeEndY string info WAVE/Z wvX = $"" @@ -1035,6 +1041,7 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) + SF_AddErrorBars(pg.graph, pg.win, wvY, traces[i]) endfor elseif((xMxN == 1) && (yMxN == 1)) // 1D if(yPoints == 1) // 0D vs 1D @@ -1046,6 +1053,7 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][0]/TN=$traces[i] vs wvX[i][] annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) + SF_AddErrorBars(pg.graph, pg.win, wvY, traces[i], rangeBeginX = i, rangeEndX = i) endfor elseif(xPoints == 1) // 1D vs 0D numTraces = yPoints @@ -1056,8 +1064,10 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[i][]/TN=$traces[i] vs wvX[][0] annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) + SF_AddErrorBars(pg.graph, pg.win, wvY, traces[i], rangeBeginY = i, rangeEndY = i) endfor else // 1D vs 1D + splitTraces = min(yPoints, xPoints) numTraces = floor(max(yPoints, xPoints) / splitTraces) SF_CheckNumTraces(pg.graph, numTraces) @@ -1086,10 +1096,16 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable endif SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) - splitY = SF_SplitPlotting(wvY, ROWS, i, splitTraces) - splitX = SF_SplitPlotting(wvX, ROWS, i, splitTraces) - AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[splitY, splitY + splitTraces - 1][0]/TN=$traces[i] vs wvX[splitX, splitX + splitTraces - 1][0] + splitY = SF_SplitPlotting(wvY, ROWS, i, splitTraces) + splitX = SF_SplitPlotting(wvX, ROWS, i, splitTraces) + rangeBeginX = splitX + rangeEndX = splitX + splitTraces - 1 + rangeBeginY = splitY + rangeEndY = splitY + splitTraces - 1 + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[rangeBeginY, rangeEndY][0]/TN=$traces[i] vs wvX[rangeBeginX, rangeEndX][0] annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) + + SF_AddErrorBars(pg.graph, pg.win, wvY, traces[i], rangeBeginX = rangeBeginX, rangeEndX = rangeEndX, rangeBeginY = rangeBeginY, rangeEndY = rangeEndY) endfor endif elseif(yMxN == 1) // 1D vs 2D @@ -1101,6 +1117,7 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][0]/TN=$traces[i] vs wvX[][i] annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) + SF_AddErrorBars(pg.graph, pg.win, wvY, traces[i]) endfor elseif(xMxN == 1) // 2D vs 1D or 0D if(xPoints == 1) // 2D vs 0D -> extend X to 1D with constant value @@ -1116,6 +1133,7 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] vs wvX annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) + SF_AddErrorBars(pg.graph, pg.win, wvY, traces[i]) endfor else // 2D vs 2D numTraces = WaveExists(wvX) ? max(1, max(yMxN, xMxN)) : max(1, yMxN) @@ -1136,6 +1154,7 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] endif annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) + SF_AddErrorBars(pg.graph, pg.win, wvY, traces[i]) endfor endif @@ -1146,6 +1165,69 @@ static Function [variable dataCnt, variable gdIndex, string annotation, variable return [dataCnt, gdIndex, annotation, formulaAddedOncePerDataset] End +static Function SF_AddErrorBars(string graph, string win, WAVE wvY, string traceName, [variable rangeBeginX, variable rangeEndX, variable rangeBeginY, variable rangeEndY]) + + rangeBeginX = ParamIsDefault(rangeBeginX) ? 0 : rangeBeginX + rangeEndX = ParamIsDefault(rangeEndX) ? Inf : rangeEndX + rangeBeginY = ParamIsDefault(rangeBeginY) ? 0 : rangeBeginY + rangeEndY = ParamIsDefault(rangeEndY) ? Inf : rangeEndY + + DFREF dfr = SF_GetBrowserDF(graph) + + WAVE/Z errorbarYPlus = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_ERRORBARYPLUS) + if(WaveExists(errorbarYPlus)) + WAVE wvYplusPermanent = GetSweepFormulaErrorbar(dfr, traceName, SF_META_ERRORBARYPLUS) + Duplicate/O errorbarYPlus, wvYplusPermanent + endif + WAVE/Z errorbarYMinus = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_ERRORBARYMINUS) + if(WaveExists(errorbarYMinus)) + WAVE wvYminusPermanent = GetSweepFormulaErrorbar(dfr, traceName, SF_META_ERRORBARYMINUS) + Duplicate/O errorbarYMinus, wvYminusPermanent + endif + WAVE/Z errorbarXPlus = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_ERRORBARXPLUS) + if(WaveExists(errorbarXPlus)) + WAVE wvXplusPermanent = GetSweepFormulaErrorbar(dfr, traceName, SF_META_ERRORBARXPLUS) + Duplicate/O errorbarXPlus, wvXplusPermanent + endif + WAVE/Z errorbarXMinus = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_ERRORBARXMINUS) + if(WaveExists(errorbarXMinus)) + WAVE wvXminusPermanent = GetSweepFormulaErrorbar(dfr, traceName, SF_META_ERRORBARXMINUS) + Duplicate/O errorbarXMinus, wvXminusPermanent + endif + + if(!WaveExists(errorbarYPlus) && !WaveExists(errorbarYMinus) && !WaveExists(errorbarXPlus) && !WaveExists(errorbarXMinus)) + return NaN + endif + + if(WaveExists(errorbarYPlus) && WaveExists(errorbarYMinus) && WaveExists(errorbarXPlus) && WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, XY, wave=(wvXplusPermanent[rangeBeginX, rangeEndX], wvXminusPermanent[rangeBeginX, rangeEndX]), wave=(wvYplusPermanent[rangeBeginY, rangeEndY], wvYminusPermanent[rangeBeginY, rangeEndY]) + elseif(WaveExists(errorbarYPlus) && WaveExists(errorbarYMinus) && WaveExists(errorbarXPlus) && !WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, XY, wave=(wvXplusPermanent[rangeBeginX, rangeEndX],), wave=(wvYplusPermanent[rangeBeginY, rangeEndY], wvYminusPermanent[rangeBeginY, rangeEndY]) + elseif(WaveExists(errorbarYPlus) && WaveExists(errorbarYMinus) && !WaveExists(errorbarXPlus) && WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, XY, wave=(, wvXminusPermanent[rangeBeginX, rangeEndX]), wave=(wvYplusPermanent[rangeBeginY, rangeEndY], wvYminusPermanent[rangeBeginY, rangeEndY]) + elseif(WaveExists(errorbarYPlus) && WaveExists(errorbarYMinus) && !WaveExists(errorbarXPlus) && !WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, Y, wave=(wvYplusPermanent[rangeBeginY, rangeEndY], wvYminusPermanent[rangeBeginY, rangeEndY]) + elseif(WaveExists(errorbarYPlus) && !WaveExists(errorbarYMinus) && WaveExists(errorbarXPlus) && WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, XY, wave=(wvXplusPermanent[rangeBeginX, rangeEndX], wvXminusPermanent[rangeBeginX, rangeEndX]), wave=(wvYplusPermanent[rangeBeginY, rangeEndY],) + elseif(WaveExists(errorbarYPlus) && !WaveExists(errorbarYMinus) && WaveExists(errorbarXPlus) && !WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, XY, wave=(wvXplusPermanent[rangeBeginX, rangeEndX],), wave=(wvYplusPermanent[rangeBeginY, rangeEndY],) + elseif(WaveExists(errorbarYPlus) && !WaveExists(errorbarYMinus) && !WaveExists(errorbarXPlus) && !WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, Y, wave=(wvYplusPermanent[rangeBeginY, rangeEndY],) + elseif(!WaveExists(errorbarYPlus) && WaveExists(errorbarYMinus) && WaveExists(errorbarXPlus) && WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, XY, wave=(wvXplusPermanent[rangeBeginX, rangeEndX], wvXminusPermanent[rangeBeginX, rangeEndX]), wave=(, wvYminusPermanent[rangeBeginY, rangeEndY]) + elseif(!WaveExists(errorbarYPlus) && WaveExists(errorbarYMinus) && WaveExists(errorbarXPlus) && !WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, XY, wave=(wvXplusPermanent[rangeBeginX, rangeEndX],), wave=(, wvYminusPermanent[rangeBeginY, rangeEndY]) + elseif(!WaveExists(errorbarYPlus) && WaveExists(errorbarYMinus) && !WaveExists(errorbarXPlus) && !WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, Y, wave=(wvYminusPermanent[rangeBeginY, rangeEndY],) + elseif(!WaveExists(errorbarYPlus) && !WaveExists(errorbarYMinus) && WaveExists(errorbarXPlus) && WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, X, wave=(wvXplusPermanent[rangeBeginX, rangeEndX], wvXminusPermanent[rangeBeginX, rangeEndX]) + elseif(!WaveExists(errorbarYPlus) && !WaveExists(errorbarYMinus) && WaveExists(errorbarXPlus) && !WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, X, wave=(wvXplusPermanent[rangeBeginX, rangeEndX],) + elseif(!WaveExists(errorbarYPlus) && !WaveExists(errorbarYMinus) && !WaveExists(errorbarXPlus) && WaveExists(errorbarXMinus)) + ErrorBars/W=$win $traceName, X, wave=(, wvXminusPermanent[rangeBeginX, rangeEndX]) + endif +End + static Function [variable dataCnt] SF_CreateTracesForResults(STRUCT SF_PlotterGraphStruct &pg) variable i, idx, showInTable, numData, formulaAddedOncePerDataset @@ -1499,6 +1581,29 @@ static Function SF_FormulaPlotter(string graph, string formula, [variable dmMode SF_KillOldDataDisplayWindows(graph, winDisplayMode, wList, outputWindows) End +/// @brief Sets axis properties for plots of the SF formula plotter. The properties are stored in the plotMetaData wave. +static Function SF_SetAxisProperties(STRUCT SF_PlotterGraphStruct &pg) + + variable xaxisOffset, yaxisOffset, xaxisPercent, yaxisPercent + + xaxisOffset = str2num(pg.plotMetaData[%XAXISOFFSET]) + if(!IsNaN(xaxisOffset)) + ModifyGraph/W=$pg.win axOffset(bottom)=xaxisOffset + endif + yaxisOffset = str2num(pg.plotMetaData[%YAXISOFFSET]) + if(!IsNaN(yaxisOffset)) + ModifyGraph/W=$pg.win axOffset(left)=yaxisOffset + endif + xaxisPercent = str2num(pg.plotMetaData[%XAXISPERCENT]) + if(!IsNaN(xaxisPercent)) + ModifyGraph/W=$pg.win axisEnab(bottom)={0, xaxisPercent * PERCENT_TO_ONE} + endif + yaxisPercent = str2num(pg.plotMetaData[%YAXISPERCENT]) + if(!IsNaN(yaxisPercent)) + ModifyGraph/W=$pg.win axisEnab(left)={0, yaxisPercent * PERCENT_TO_ONE} + endif +End + static Function SF_FinishPlotWindow(STRUCT SF_PlotterGraphStruct &pg, WAVE/T winGraphs) variable formulasAreDifferent, numTableFormulas @@ -1511,7 +1616,11 @@ static Function SF_FinishPlotWindow(STRUCT SF_PlotterGraphStruct &pg, WAVE/T win endif if(pg.panelsCreated[%GRAPH]) + pg.win = winGraphs[GetNumberFromWaveNote(winGraphs, NOTE_INDEX) - 1] + + SF_SetAxisProperties(pg) + if(pg.showLegend) formulasAreDifferent = SF_AddPlotLegend(pg) endif @@ -2827,3 +2936,9 @@ Function SF_TableWindowHook(STRUCT WMWinHookStruct &s) return 0 End + +/// @brief Adds an expression to a formula string with the proper termination character +Function/S SF_AddExpressionToFormula(string formula, string expr) + + return formula + expr + SF_CHAR_CR +End diff --git a/Packages/MIES/MIES_SweepFormula_Executor.ipf b/Packages/MIES/MIES_SweepFormula_Executor.ipf index 241aad4c5f..8526b9a05d 100644 --- a/Packages/MIES/MIES_SweepFormula_Executor.ipf +++ b/Packages/MIES/MIES_SweepFormula_Executor.ipf @@ -547,6 +547,18 @@ Function/WAVE SFE_FormulaExecutor(STRUCT SF_ExecutionData &exd, [variable srcLoc case SF_OP_TABLE: WAVE out = SFO_OperationTable(exdop) break + case SF_OP_IVSCCAPFREQUENCY: + WAVE out = SFO_OperationIVSCCApFrequency(exdop) + break + case SF_OP_PREPAREFIT: + WAVE out = SFO_OperationPrepareFit(exdop) + break + case SF_OP_FIT2: + WAVE out = SFO_OperationFit2(exdop) + break + case SF_OP_GETMETA: + WAVE out = SFO_OperationGetMeta(exdop) + break #ifdef AUTOMATED_TESTING case SF_OP_TESTOP: WAVE out = SFO_OperationTestop(exdop) diff --git a/Packages/MIES/MIES_SweepFormula_Helpers.ipf b/Packages/MIES/MIES_SweepFormula_Helpers.ipf index 846dcc62e0..77b5a4ecaf 100644 --- a/Packages/MIES/MIES_SweepFormula_Helpers.ipf +++ b/Packages/MIES/MIES_SweepFormula_Helpers.ipf @@ -2178,27 +2178,6 @@ Function/WAVE SFH_GetDatasetArrayAsResolvedWaverefs(STRUCT SF_ExecutionData &exd return dataFromEachGroup End -/// @brief Executes a formula from within an operation with low overhead -/// - the currently active variable storage is used -/// - the formula string is not preprocessed -Function/WAVE SFH_ExecuteFormulaInternal(string graph, string formula) - - STRUCT SF_ExecutionData exd - variable jsonId, srcLocId - - exd.graph = graph - [jsonId, srcLocId] = SFP_ParseFormulaToJSON(formula) - exd.jsonId = jsonId - WAVE dataRef = SFE_FormulaExecutor(exd, srcLocId = srcLocId) - - JSON_Release(exd.jsonId) - JSON_Release(srcLocId) - - WAVE resolved = SF_ResolveDataset(dataRef) - - return resolved -End - /// @brief Adds a variable to the variable storage. If the variable already exists it is overwritten. Function SFH_AddVariableToStorage(string graph, string name, WAVE result) @@ -2220,3 +2199,29 @@ Function SFH_AddVariableToStorage(string graph, string name, WAVE result) JWN_SetNumberInWaveNote(result, SF_VARIABLE_MARKER, 1) varStorage[idx] = result End + +/// @brief Adds a variable to the variable storage from a given formula. If the variable already exists it is overwritten. +Function/WAVE SFH_AddVariableToStorageByFormula(string graph, string name, string formula, string opShort) + + WAVE/WAVE result = SFE_ExecuteFormula(formula, graph, preProcess = 0) + SFH_AddVariableToStorage(graph, name, SFH_GetOutputForExecutor(result, graph, opShort)) + + return result +End + +/// @brief Copy plot meta data JSON properties from a source to a target wave +Function SFH_CopyPlotMetaData(WAVE input, WAVE output) + + WAVE/Z wv = JWN_GetNumericWaveFromWaveNote(input, SF_META_TRACECOLOR) + if(WaveExists(wv)) + JWN_SetWaveInWaveNote(output, SF_META_TRACECOLOR, wv) + endif + JWN_SetNumberInWaveNote(output, SF_META_TRACETOFRONT, JWN_GetNumberFromWaveNote(input, SF_META_TRACETOFRONT)) + JWN_SetNumberInWaveNote(output, SF_META_LINESTYLE, JWN_GetNumberFromWaveNote(input, SF_META_LINESTYLE)) +End + +Function SFH_SetTraceStyleForFit(WAVE fitData) + + JWN_SetWaveInWaveNote(fitData, SF_META_TRACECOLOR, {0, 0, 0}) // black + JWN_SetNumberInWaveNote(fitData, SF_META_TRACE_MODE, TRACE_DISPLAY_MODE_LINES) +End diff --git a/Packages/MIES/MIES_SweepFormula_Operations.ipf b/Packages/MIES/MIES_SweepFormula_Operations.ipf index e4dfdf22ff..a1794b9adf 100644 --- a/Packages/MIES/MIES_SweepFormula_Operations.ipf +++ b/Packages/MIES/MIES_SweepFormula_Operations.ipf @@ -30,9 +30,16 @@ static StrConstant SF_OP_APFREQUENCY_NONORM = "nonorm" static StrConstant SF_OP_APFREQUENCY_X_COUNT = "count" static StrConstant SF_OP_APFREQUENCY_X_TIME = "time" +static StrConstant SF_OP_IVSCCAPFREQUENCY_FIRST = "first" +static StrConstant SF_OP_IVSCCAPFREQUENCY_MIN = "min" +static StrConstant SF_OP_IVSCCAPFREQUENCY_MAX = "max" +static StrConstant SF_OP_IVSCCAPFREQUENCY_NONE = "none" + 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_AVG_BINS = "bins" +static StrConstant SF_OP_AVG_BINS2 = "bins2" static StrConstant SF_OP_EPOCHS_TYPE_RANGE = "range" static StrConstant SF_OP_EPOCHS_TYPE_NAME = "name" @@ -58,6 +65,12 @@ static Constant SF_POWERSPECTRUM_RATIO_GAUSS_NUMCOEFS = 4 static StrConstant SF_AVERAGING_NONSWEEPDATA_LBL = "NOSWEEPDATA" +static Constant SF_IVSCC_APFREQUENCY_OPACITY = 13107 // 0.2 * 65535 + +static StrConstant SF_PREPAREFIT_NOFUNC = "none" + +static Constant SF_FIT2_MAX_ITERATIONS = 40 + Function/WAVE SFO_OperationAnaFuncParam(STRUCT SF_ExecutionData &exd) SFH_CheckArgumentCount(exd, SF_OP_ANAFUNCPARAM, 0, maxArgs = 2) @@ -235,6 +248,25 @@ static Function/WAVE SFO_OperationAnaFuncParamImplAllNames(WAVE/T names, WAVE/WA return GetUniqueEntries(allNames) End +static Function [variable method, variable level, string timeFreq, string normalize, string xAxisType] SFO_GetApFrequencyArguments(STRUCT SF_ExecutionData &exd, string opShort, variable offset) + + method = SFH_GetArgumentAsNumeric(exd, opShort, offset, defValue = SF_APFREQUENCY_FULL, allowedValues = {SF_APFREQUENCY_FULL, SF_APFREQUENCY_INSTANTANEOUS, SF_APFREQUENCY_APCOUNT, SF_APFREQUENCY_INSTANTANEOUS_PAIR}) + level = SFH_GetArgumentAsNumeric(exd, opShort, offset + 1, defValue = 0) + timeFreq = SFH_GetArgumentAsText(exd, opShort, offset + 2, defValue = SF_OP_APFREQUENCY_Y_FREQ, allowedValues = {SF_OP_APFREQUENCY_Y_TIME, SF_OP_APFREQUENCY_Y_FREQ}) + normalize = SFH_GetArgumentAsText(exd, opShort, offset + 3, defValue = SF_OP_APFREQUENCY_NONORM, allowedValues = { \ + SF_OP_APFREQUENCY_NONORM, \ + SF_OP_APFREQUENCY_NORMOVERSWEEPSMIN, \ + SF_OP_APFREQUENCY_NORMOVERSWEEPSMAX, \ + SF_OP_APFREQUENCY_NORMOVERSWEEPSAVG, \ + SF_OP_APFREQUENCY_NORMWITHINSWEEPMIN, \ + SF_OP_APFREQUENCY_NORMWITHINSWEEPMAX, \ + SF_OP_APFREQUENCY_NORMWITHINSWEEPAVG \ + }) + xAxisType = SFH_GetArgumentAsText(exd, opShort, offset + 4, defValue = SF_OP_APFREQUENCY_X_TIME, allowedValues = {SF_OP_APFREQUENCY_X_TIME, SF_OP_APFREQUENCY_X_COUNT}) + + return [method, level, timeFreq, normalize, xAxisType] +End + // apfrequency(data, [frequency calculation method], [spike detection crossing level], [result value type], [normalize], [x-axis type]) Function/WAVE SFO_OperationApFrequency(STRUCT SF_ExecutionData &exd) @@ -249,19 +281,7 @@ Function/WAVE SFO_OperationApFrequency(STRUCT SF_ExecutionData &exd) SFH_ASSERT(numArgs >= numArgsMin, "ApFrequency needs at least " + num2istr(numArgsMin) + " argument(s).") WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, 0) - method = SFH_GetArgumentAsNumeric(exd, opShort, 1, defValue = SF_APFREQUENCY_FULL, allowedValues = {SF_APFREQUENCY_FULL, SF_APFREQUENCY_INSTANTANEOUS, SF_APFREQUENCY_APCOUNT, SF_APFREQUENCY_INSTANTANEOUS_PAIR}) - level = SFH_GetArgumentAsNumeric(exd, opShort, 2, defValue = 0) - timeFreq = SFH_GetArgumentAsText(exd, opShort, 3, defValue = SF_OP_APFREQUENCY_Y_FREQ, allowedValues = {SF_OP_APFREQUENCY_Y_TIME, SF_OP_APFREQUENCY_Y_FREQ}) - normalize = SFH_GetArgumentAsText(exd, opShort, 4, defValue = SF_OP_APFREQUENCY_NONORM, allowedValues = { \ - SF_OP_APFREQUENCY_NONORM, \ - SF_OP_APFREQUENCY_NORMOVERSWEEPSMIN, \ - SF_OP_APFREQUENCY_NORMOVERSWEEPSMAX, \ - SF_OP_APFREQUENCY_NORMOVERSWEEPSAVG, \ - SF_OP_APFREQUENCY_NORMWITHINSWEEPMIN, \ - SF_OP_APFREQUENCY_NORMWITHINSWEEPMAX, \ - SF_OP_APFREQUENCY_NORMWITHINSWEEPAVG \ - }) - xAxisType = SFH_GetArgumentAsText(exd, opShort, 5, defValue = SF_OP_APFREQUENCY_X_TIME, allowedValues = {SF_OP_APFREQUENCY_X_TIME, SF_OP_APFREQUENCY_X_COUNT}) + [method, level, timeFreq, normalize, xAxisType] = SFO_GetApFrequencyArguments(exd, opShort, 1) WAVE/T argSetup = SFH_GetNewArgSetupWave(numArgsMax - 1) @@ -488,13 +508,13 @@ End Function/WAVE SFO_OperationAvg(STRUCT SF_ExecutionData &exd) - variable numArgs - string mode + variable numArgs, binWidth + string mode string opShort = SF_OP_AVG - numArgs = SFH_CheckArgumentCount(exd, opShort, 1, maxArgs = 2) + numArgs = SFH_CheckArgumentCount(exd, opShort, 1, maxArgs = 5) - mode = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_AVG_INSWEEPS, allowedValues = {SF_OP_AVG_INSWEEPS, SF_OP_AVG_OVERSWEEPS, SF_OP_AVG_GROUPS}) + mode = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_AVG_INSWEEPS, allowedValues = {SF_OP_AVG_INSWEEPS, SF_OP_AVG_OVERSWEEPS, SF_OP_AVG_GROUPS, SF_OP_AVG_BINS, SF_OP_AVG_BINS2}) 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) @@ -513,17 +533,276 @@ Function/WAVE SFO_OperationAvg(STRUCT SF_ExecutionData &exd) 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, SF_DATATYPE_AVG) return SFH_GetOutputForExecutor(averagedGroup, exd.graph, opShort) - else - FATAL_ERROR("Unhandled avg operation mode") + elseif(!CmpStr(mode, SF_OP_AVG_BINS)) + WAVE/WAVE dataFromEachGroup = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 0, resolveSelect = 1) + WAVE/WAVE wTmp = SFH_GetArgumentAsWave(exd, opShort, 2) + WAVE binRange = wTmp[0] + SFH_ASSERT(DimSize(binRange, ROWS) == 2, "Expected range in the form of [start, end]") + SFH_ASSERT(binRange[1] > binRange[0], "The end of the bin range must be greater than the start") + binWidth = SFH_GetArgumentAsNumeric(exd, opShort, 3, checkFunc = IsStrictlyPositiveAndFinite) + WAVE/WAVE binData = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 4, resolveSelect = 1) + SFH_ASSERT(DimSize(dataFromEachGroup, ROWS) == DimSize(binData, ROWS), "input data and bin data must have the same number of groups") + WAVE/WAVE averagedBins = SFO_OperationAvgImplBins(dataFromEachGroup, exd.graph, opShort, binData, binRange, binWidth) + return SFH_GetOutputForExecutor(averagedBins, exd.graph, opShort) + elseif(!CmpStr(mode, SF_OP_AVG_BINS2)) + WAVE/WAVE dataFromEachGroup = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 0, resolveSelect = 1) + WAVE/WAVE binData = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 2, resolveSelect = 1) + SFH_ASSERT(DimSize(dataFromEachGroup, ROWS) == DimSize(binData, ROWS), "input data and bin data must have the same number of groups") + WAVE/WAVE averagedBins = SFO_OperationAvgImplBins2(dataFromEachGroup, exd.graph, opShort, binData) + return SFH_GetOutputForExecutor(averagedBins, exd.graph, opShort) endif End +static Function/WAVE SFO_OperationAvgImplBins2(WAVE/WAVE input, string graph, string opShort, WAVE/WAVE binData) + + variable i, j, maxBins, numGroups, numDataSets, idx, numBins, numEntries, size, xValue, xSdev, ySdev + string unit + STRUCT RGBColor s + + printf "avg in bins2 mode:\r" + + [s] = GetTraceColorForAverage() + Make/FREE/W/U traceColor = {s.red, s.green, s.blue} + + numGroups = DimSize(input, ROWS) + + // Sort + Make/FREE/WAVE/N=(numGroups) sortedDatasetGroups, sortedBinDatasets + for(i = 0; i < numGroups; i += 1) + WAVE/WAVE dataSets = input[i] + WAVE/WAVE binDataSets = binData[i] + + numDataSets = DimSize(dataSets, ROWS) + printf "Group %d, num datasets %d\r", i, numDataSets + SFH_ASSERT(numDataSets == DimSize(binDataSets, ROWS), "The number of datasets of the input and bins are not the same for group " + num2istr(i)) + Make/FREE/D/N=(numDataSets) sortedKey + for(j = 0; j < numDataSets; j += 1) + SFH_ASSERT(WaveExists(binDataSets[j]), "A bin dataset is null") + SFH_ASSERT(IsNumericWave(binDataSets[j]), "A bin dataset must be numeric") + SFH_ASSERT(DimSize(binDataSets[j], ROWS) == 1, "A bin dataset must have exactly one value") + sortedKey[j] = WaveRef(binDataSets, row = j)[0] + if(IsNull(unit)) + unit = WaveUnits(binDataSets[j], ROWS) + endif + endfor + + Duplicate/FREE/WAVE dataSets, sortedDatasets + Sort sortedKey, sortedKey, sortedDatasets + sortedDatasetGroups[i] = sortedDatasets + sortedBinDatasets[i] = sortedKey + maxBins = max(maxBins, numDataSets) + endfor + + // Gather + Make/FREE/WAVE/N=(maxBins) filledBins, xValuesBin + for(i = 0; i < numGroups; i += 1) + WAVE/WAVE sortedDatasets = sortedDatasetGroups[i] + WAVE binXValues = sortedBinDatasets[i] + numDataSets = DimSize(sortedDatasets, ROWS) + for(j = 0; j < numDataSets; j += 1) + if(!WaveExists(sortedDatasets[j])) + continue + endif + // Add to bin + WAVE/Z/WAVE wavesInBin = filledBins[j] + if(!WaveExists(wavesInBin)) + Make/FREE/WAVE wavesInBin = {sortedDatasets[j]} + SetNumberInWaveNote(wavesInBin, NOTE_INDEX, 1) + filledBins[j] = wavesInBin + Make/FREE/D xValues = {binXValues[j]} + SetNumberInWaveNote(xValues, NOTE_INDEX, 1) + xValuesBin[j] = xValues + printf "Group %d, Bin %d, add at index %d\r", i, j, 0 + continue + endif + idx = GetNumberFromWaveNote(wavesInBin, NOTE_INDEX) + printf "Group %d, Bin %d, add at index %d\r", i, j, idx + WAVE xValues = xValuesBin[j] + EnsureLargeEnoughWave(wavesInBin, indexShouldExist = idx) + EnsureLargeEnoughWave(xValues, indexShouldExist = idx) + wavesInBin[idx] = sortedDatasets[j] + xValues[idx] = binXValues[j] + SetNumberInWaveNote(wavesInBin, NOTE_INDEX, idx + 1) + SetNumberInWaveNote(xValues, NOTE_INDEX, idx + 1) + endfor + endfor + + for(i = 0; i < maxBins; i += 1) + if(WaveExists(filledBins[i])) + printf "Bin %d, filling %d\r", i, GetNumberFromWaveNote(filledBins[i], NOTE_INDEX) + else + printf "Bin %d, filling %d\r", i, 0 + endif + endfor + + // Cutoff + for(i = 0; i < maxBins; i += 1) + if(!WaveExists(filledBins[i])) + break + endif + if(GetNumberFromWaveNote(filledBins[i], NOTE_INDEX) < 2) + break + endif + endfor + numBins = i + printf "Cutoff after bin %d\r", i - 1 + Redimension/N=(numBins) filledBins, xValuesBin + + // avg same bins + WAVE/WAVE output = SFH_CreateSFRefWave(graph, opShort, numBins) + for(i = 0; i < numBins; i += 1) + WAVE/WAVE wavesInBin = filledBins[i] + numEntries = GetNumberFromWaveNote(wavesInBin, NOTE_INDEX) + Redimension/N=(numEntries) wavesInBin + + WAVE/WAVE avg = MIES_fWaveAverage(wavesInBin, 1, IGOR_TYPE_64BIT_FLOAT) + output[i] = avg[0] + + size = DimSize(wavesInBin, ROWS) + Make/FREE/D/N=(size) valuesFromBin = WaveRef(wavesInBin, row = p)[0] + WaveStats/Q valuesFromBin + ySdev = V_sdev + + WAVE xValues = xValuesBin[i] + Redimension/N=(numEntries) xValues + xValue = mean(xValues) + WaveStats/Q xValues + xSdev = V_sdev + + WAVE wTmp = output[i] + printf "Bin: %d Avg result: %f, xValue: %f, ySdev: %f, xSdev: %f\r", i, wTmp[0], xValue, ySdev, xSdev + + JWN_SetWaveInWaveNote(output[i], SF_META_TRACECOLOR, traceColor) + JWN_SetNumberInWaveNote(output[i], SF_META_TRACETOFRONT, 1) + JWN_SetNumberInWaveNote(output[i], SF_META_LINESTYLE, 0) + JWN_SetWaveInWaveNote(output[i], SF_META_XVALUES, {xValue}) + JWN_SetWaveInWaveNote(output[i], SF_META_ERRORBARYPLUS, {ySdev}) + JWN_SetWaveInWaveNote(output[i], SF_META_ERRORBARYMINUS, {ySdev}) + JWN_SetWaveInWaveNote(output[i], SF_META_ERRORBARXPLUS, {xSdev}) + JWN_SetWaveInWaveNote(output[i], SF_META_ERRORBARXMINUS, {xSdev}) + endfor + + if(IsEmpty(unit)) + unit = "x" + endif + JWN_SetStringInWaveNote(output, SF_META_XAXISLABEL, unit) + + return output +End + +static Function/WAVE SFO_OperationAvgImplBins(WAVE/WAVE input, string graph, string opShort, WAVE/WAVE binData, WAVE binRange, variable binWidth) + + variable i, j, numBins, binStart, binEnd, numGroups, numDataSets, binValue, binPos, idx + STRUCT RGBColor s + + printf "avg in bins mode:\r" + + [s] = GetTraceColorForAverage() + Make/FREE/W/U traceColor = {s.red, s.green, s.blue} + + numGroups = DimSize(input, ROWS) + binStart = binRange[0] + binEnd = binRange[1] + numBins = ceil((binEnd - binStart) / binWidth) + SFH_ASSERT(numBins < 1E6, "Maximum number of bins is 1E6.") + + // Gather + Make/FREE/WAVE/N=(numBins, numGroups) binnedPerGroup + for(i = 0; i < numGroups; i += 1) + WAVE/WAVE dataSets = input[i] + WAVE/WAVE binDataSets = binData[i] + numDataSets = DimSize(dataSets, ROWS) + SFH_ASSERT(numDataSets == DimSize(binDataSets, ROWS), "The number of datasets of the input and bins are not the same for group " + num2istr(i)) + for(j = 0; j < numDataSets; j += 1) + if(!WaveExists(dataSets[j])) + continue + endif + SFH_ASSERT(WaveExists(binDataSets[j]), "A bin dataset is null") + SFH_ASSERT(IsNumericWave(binDataSets[j]), "A bin dataset must be numeric") + SFH_ASSERT(DimSize(binDataSets[j], ROWS) == 1, "A bin dataset must have exactly one value") + binValue = WaveRef(binDataSets, row = j)[0] + if(binValue < binStart || binValue >= binEnd) + continue + endif + binPos = floor((binValue - binStart) / binWidth) + // Add to bin + WAVE/Z/WAVE wavesInBin = binnedPerGroup[binPos][i] + if(!WaveExists(wavesInBin)) + Make/FREE/WAVE wavesInBin = {dataSets[j]} + SetNumberInWaveNote(wavesInBin, NOTE_INDEX, 1) + binnedPerGroup[binPos][i] = wavesInBin + continue + endif + idx = GetNumberFromWaveNote(wavesInBin, NOTE_INDEX) + EnsureLargeEnoughWave(wavesInBin, indexShouldExist = idx) + wavesInBin[idx] = dataSets[j] + SetNumberInWaveNote(wavesInBin, NOTE_INDEX, idx + 1) + endfor + endfor + printf "Averaging bins:\r" + // avg bins with multiple filling + for(i = 0; i < numBins; i += 1) + for(j = 0; j < numGroups; j += 1) + if(!WaveExists(binnedPerGroup[i][j])) + continue + endif + WAVE/WAVE wavesInBin = binnedPerGroup[i][j] + idx = GetNumberFromWaveNote(wavesInBin, NOTE_INDEX) + Redimension/N=(idx) wavesInBin + printf "Bin %d, Group %d, NumWaves %d, ", i, j, idx + if(idx == 1) + WAVE wTmp = wavesInBin[0] + print "Result:", wTmp[0] + + continue + endif + WAVE/WAVE avg = MIES_fWaveAverage(wavesInBin, 1, IGOR_TYPE_64BIT_FLOAT) + Redimension/N=(1) wavesInBin + wavesInBin[0] = avg[0] + + WAVE wTmp = avg[0] + print "Result:", wTmp[0] + + endfor + endfor + // avg same bins + WAVE/WAVE output = SFH_CreateSFRefWave(graph, opShort, numBins) + for(i = 0; i < numBins; i += 1) + Make/FREE/WAVE/N=(numGroups) sameBin + idx = 0 + for(j = 0; j < numGroups; j += 1) + if(!WaveExists(binnedPerGroup[i][j])) + continue + endif + WAVE/WAVE wavesInBin = binnedPerGroup[i][j] + sameBin[idx] = wavesInBin[0] + idx += 1 + endfor + printf "Bin %d, NumWaves/TotalGroups %d/%d:\r", i, idx, numGroups + if(idx == 0) + Make/FREE/D tmp = {NaN} + output[i] = tmp + else + Redimension/N=(idx) sameBin + WAVE/WAVE avg = MIES_fWaveAverage(sameBin, 1, IGOR_TYPE_64BIT_FLOAT) + output[i] = avg[0] + + WAVE wTmp = output[i] + printf "Avg result: %f\r", wTmp[0] + endif + 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_OperationAvgImplSweepGroups(WAVE/WAVE sweepsFromEachSelection, string graph, string opShort) - variable numData, numMaxSweeps, numGroups, i, j + variable numData, numMaxSweeps, numGroups, i, j, maxIdx STRUCT RGBColor s [s] = GetTraceColorForAverage() @@ -531,7 +810,9 @@ static Function/WAVE SFO_OperationAvgImplSweepGroups(WAVE/WAVE sweepsFromEachSel numGroups = DimSize(sweepsFromEachSelection, ROWS) Make/FREE/D/N=(numGroups) sweepCnts = DimSize(sweepsFromEachSelection[p], ROWS) - numMaxSweeps = WaveMax(sweepCnts) + WaveStats/Q/M=1 sweepCnts + numMaxSweeps = V_max + maxIdx = V_maxRowLoc WAVE/WAVE output = SFH_CreateSFRefWave(graph, opShort, numMaxSweeps) for(i = 0; i < numMaxSweeps; i += 1) Make/FREE/WAVE/N=(numGroups) avgSet @@ -549,6 +830,7 @@ static Function/WAVE SFO_OperationAvgImplSweepGroups(WAVE/WAVE sweepsFromEachSel JWN_SetNumberInWaveNote(output[i], SF_META_TRACETOFRONT, 1) JWN_SetNumberInWaveNote(output[i], SF_META_LINESTYLE, 0) endfor + SFH_TransferFormulaDataWaveNoteAndMeta(sweepsFromEachSelection[maxIdx], output, opShort, SF_DATATYPE_AVG) return output End @@ -1531,6 +1813,7 @@ End Function/WAVE SFO_OperationMerge(STRUCT SF_ExecutionData &exd) variable numElements, numOutputDatasets, wvType + string errorTag SFH_CheckArgumentCount(exd, SF_OP_MERGE, 1, maxArgs = 1) WAVE/WAVE inputWithNull = SF_ResolveDatasetFromJSON(exd, 0) @@ -1563,11 +1846,77 @@ Function/WAVE SFO_OperationMerge(STRUCT SF_ExecutionData &exd) contentTxt[] = WaveText(WaveRef(input[p]), row = 0) endif + WAVE/Z mergedX = SFO_OperationMergeXValues(input) + if(WaveExists(mergedX)) + JWN_SetWaveInWaveNote(content, SF_META_XVALUES, mergedX) + endif + Make/FREE/T errorBarTags = {SF_META_ERRORBARYPLUS, SF_META_ERRORBARYMINUS, SF_META_ERRORBARXPLUS, SF_META_ERRORBARXMINUS} + for(string errorTag : errorBarTags) + WAVE/Z errorbarMerged = SFO_OperationMergeErrorBars(input, errorTag) + if(WaveExists(errorbarMerged)) + JWN_SetWaveInWaveNote(content, errorTag, errorbarMerged) + endif + endfor + output[0] = content + SFH_CopyPlotMetaData(input[0], output[0]) + return SFH_GetOutputForExecutor(output, exd.graph, SF_OP_MERGE) End +static Function/WAVE SFO_OperationMergeXValues(WAVE/WAVE input) + + variable numElements, i + + numElements = DimSize(input, ROWS) + + SFH_ASSERT(DimSize(input, ROWS) > 0, "input must have at least one dataset") + WAVE/Z xWave = JWN_GetNumericWaveFromWaveNote(input[0], SF_META_XVALUES) + if(!WaveExists(xWave)) + return $"" + endif + + SFH_ASSERT(DimSize(xWave, ROWS) == 1, "xValues must be only a one element") + Make/FREE/D/N=(numElements) mergedX + mergedX[0] = xWave[0] + if(numElements > 1) + for(i = 1; i < numElements; i += 1) + WAVE/Z xWave = JWN_GetNumericWaveFromWaveNote(input[i], SF_META_XVALUES) + SFH_ASSERT(WaveExists(xWave), "Can not merge xValues because only some datasets have xValues") + SFH_ASSERT(DimSize(xWave, ROWS) == 1, "xValues must be only a one element") + mergedX[i] = xWave[0] + endfor + endif + + return mergedX +End + +static Function/WAVE SFO_OperationMergeErrorBars(WAVE/WAVE input, string metaTag) + + variable numElements, i + + numElements = DimSize(input, ROWS) + + SFH_ASSERT(DimSize(input, ROWS) > 0, "input must have at least one dataset") + + Make/FREE/D/N=(numElements) mergedError + FastOp mergedError = (NaN) + for(i = 0; i < numElements; i += 1) + + WAVE/Z errorbar = JWN_GetNumericWaveFromWaveNote(input[i], metaTag) + if(WaveExists(errorbar)) + SFH_ASSERT(DimSize(errorbar, ROWS) == 1, "errorBar wave must be only a one element") + mergedError[i] = errorbar[0] + endif + endfor + if(!HasOneFiniteEntry(mergedError)) + return $"" + endif + + return mergedError +End + Function/WAVE SFO_OperationMin(STRUCT SF_ExecutionData &exd) WAVE/WAVE input = SFO_GetNumericVarArgs(exd, SF_OP_MIN) @@ -2203,6 +2552,15 @@ static Function/WAVE SFO_OperationXValuesImpl(WAVE/Z input) return $"" endif + WAVE/Z xValues = JWN_GetNumericWaveFromWaveNote(input, SF_META_XVALUES) + if(WaveExists(xValues)) + return xValues + endif + WAVE/Z/T xValuesT = JWN_GetTextWaveFromWaveNote(input, SF_META_XVALUES) + if(WaveExists(xValuesT)) + return xValuesT + endif + Make/FREE/D/N=(DimSize(input, ROWS), DimSize(input, COLS), DimSize(input, LAYERS), DimSize(input, CHUNKS)) output offset = DimOffset(input, ROWS) delta = DimDelta(input, ROWS) @@ -2223,7 +2581,11 @@ static Function/WAVE SFO_IndexOverDataSetsForPrimitiveOperation(STRUCT SF_Execut WAVE/WAVE arg1 = SF_ResolveDatasetFromJSON(exd, 1) dataSetNum0 = DimSize(arg0, ROWS) dataSetNum1 = DimSize(arg1, ROWS) - SFH_ASSERT(dataSetNum0 > 0 && dataSetNum1 > 0, "No input data for " + opShort) + if(dataSetNum0 == 0 && dataSetNum1 == 0) + WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, 0) + return output + endif + SFH_ASSERT(dataSetNum0 > 0 && dataSetNum1 > 0, "No input data on one side for " + opShort) if(dataSetNum0 == dataSetNum1) WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, dataSetNum0) WAVE/WAVE input = arg0 @@ -2502,3 +2864,1044 @@ Function/WAVE SFO_OperationTestop(STRUCT SF_ExecutionData &exd) return wv End #endif // AUTOMATED_TESTING + +/// @brief Sets the plot meta data for the ivscc_apfrequency operation +static Function SFO_OperationIVSCCApFrequencySetPlotProperties(WAVE wvY, variable xAxisPercentage, variable yAxisPercentage) + + JWN_SetNumberInWaveNote(wvY, SF_META_XAXISPERCENT, xAxisPercentage) + JWN_SetNumberInWaveNote(wvY, SF_META_YAXISPERCENT, yAxisPercentage) +End + +// for avgMode: bins +// ivscc_apfrequency([xaxisOffset, yaxisOffset, xAxisPercentage, yAxisPercentage, prepFit, avgMode, binRange, binWidth, method, level, timeFreq, normalize, xAxisType]) +// +// for avgMode: bins2 +// ivscc_apfrequency([xaxisOffset, yaxisOffset, xAxisPercentage, yAxisPercentage, prepFit, avgMode, method, level, timeFreq, normalize, xAxisType]) +Function/WAVE SFO_OperationIVSCCApFrequency(STRUCT SF_ExecutionData &exd) + + string opShort = SF_OP_IVSCCAPFREQUENCY + variable numArgsMin = 0 + variable numArgsMax = 13 + string formula, expr + variable i, numArgs, col, size, numExp + variable xAxisPercentage, yAxisPercentage + string xaxisOffset, yaxisOffset + variable method, level, binWidth, numBins + string timeFreq, normalize, xAxisType, freqList, currentList, expList, binList, avgMode + STRUCT RGBColor s + + SFH_ASSERT(BSP_IsSweepBrowser(exd.graph), "ivscc_apfrequency only works with sweepbrowser") + + numArgs = SFH_GetNumberOfArguments(exd) + SFH_ASSERT(numArgs <= numArgsMax, "ivscc_apfrequency has " + num2istr(numArgsMax) + " arguments at most.") + SFH_ASSERT(numArgs >= numArgsMin, "ivscc_apfrequency needs at least " + num2istr(numArgsMin) + " argument(s).") + + xaxisOffset = SFH_GetArgumentAsText(exd, opShort, 0, defValue = SF_OP_IVSCCAPFREQUENCY_MIN, allowedValues = {SF_OP_IVSCCAPFREQUENCY_FIRST, SF_OP_IVSCCAPFREQUENCY_MIN, SF_OP_IVSCCAPFREQUENCY_MAX, SF_OP_IVSCCAPFREQUENCY_NONE}) + yaxisOffset = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_IVSCCAPFREQUENCY_MIN, allowedValues = {SF_OP_IVSCCAPFREQUENCY_FIRST, SF_OP_IVSCCAPFREQUENCY_MIN, SF_OP_IVSCCAPFREQUENCY_MAX, SF_OP_IVSCCAPFREQUENCY_NONE}) + xAxisPercentage = SFH_GetArgumentAsNumeric(exd, opShort, 2, defValue = 100, checkFunc = BetweenZeroAndOneHoundred) + yAxisPercentage = SFH_GetArgumentAsNumeric(exd, opShort, 3, defValue = 100, checkFunc = BetweenZeroAndOneHoundred) + WAVE/WAVE prepFit = SFH_GetArgumentAsWave(exd, opShort, 4, defOp = "preparefit()") + + avgMode = SFH_GetArgumentAsText(exd, opShort, 5, defValue = SF_OP_AVG_BINS, allowedValues = {SF_OP_AVG_BINS, SF_OP_AVG_BINS2}) + + if(!CmpStr(avgMode, SF_OP_AVG_BINS)) + WAVE/WAVE wTmp = SFH_GetArgumentAsWave(exd, opShort, 6) + WAVE binRange = wTmp[0] + binWidth = SFH_GetArgumentAsNumeric(exd, opShort, 7, checkFunc = IsStrictlyPositiveAndFinite) + [method, level, timeFreq, normalize, xAxisType] = SFO_GetApFrequencyArguments(exd, opShort, 8) + else + // SF_OP_AVG_BINS2 + [method, level, timeFreq, normalize, xAxisType] = SFO_GetApFrequencyArguments(exd, opShort, 6) + endif + + // create and evaluate variables + WAVE/T sweepMap = SB_GetSweepMap(exd.graph) + col = FindDimlabel(sweepMap, COLS, "FileName") + size = GetNumberFromWaveNote(sweepMap, NOTE_INDEX) + SFH_ASSERT(size > 0, "No sweep data loaded") + Duplicate/FREE/RMD=[0, size - 1][col] sweepMap, fileNames + WAVE/T uniqueFiles = GetUniqueEntries(fileNames, dontDuplicate = 1) + Sort uniqueFiles, uniqueFiles + numExp = DimSize(uniqueFiles, ROWS) + SFH_ASSERT(numExp > 0, "ivscc_apfrequency: data from at least one experiment has to be loaded") + + formula = "sel = select(selsweeps(), selstimset(\"*LP_Rheo*\", \"*supra*\"), selvis(all), selivsccsweepqc(passed))\r" + for(i = 0; i < numExp; i += 1) + sprintf expr, "selexpAD%d = select(selexp(\"%s\"), $sel, selchannels(AD0), selrange(E1))", i, uniqueFiles[i] + formula = SF_AddExpressionToFormula(formula, expr) + sprintf expr, "selexpDA%d = select(selexp(\"%s\"), $sel, selchannels(DA0), selrange(E1))", i, uniqueFiles[i] + formula = SF_AddExpressionToFormula(formula, expr) + sprintf expr, "freq%d = apfrequency(data($selexpAD%d), %d, %f, %s, %s, %s)", i, i, method, level, timeFreq, normalize, xAxisType + formula = SF_AddExpressionToFormula(formula, expr) + sprintf expr, "current%d = max(data($selexpDA%d))", i, i + formula = SF_AddExpressionToFormula(formula, expr) + if(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + sprintf expr, "currentNorm%d = $current%d - extract($current%d, 0)", i, i, i + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + sprintf expr, "currentNorm%d = $current%d - min(merge($current%d))", i, i, i + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + sprintf expr, "currentNorm%d = $current%d - max(merge($current%d))", i, i, i + else // SF_OP_IVSCCAPFREQUENCY_NONE + sprintf expr, "currentNorm%d = $current%d", i, i + endif + formula = SF_AddExpressionToFormula(formula, expr) + endfor + + Make/FREE/T/N=(numExp) freqs, currents, exps + freqs[] = "$freq" + num2istr(p) + freqList = TextWaveToList(freqs, ",", trailSep = 0) + currents[] = "$currentNorm" + num2istr(p) + currentList = TextWaveToList(currents, ",", trailSep = 0) + exps[] = "\"" + uniqueFiles[p] + "\"" + expList = TextWaveToList(exps, ",", trailSep = 0) + + sprintf expr, "ivscc_apfrequency_explist = [%s]", expList + formula = SF_AddExpressionToFormula(formula, expr) + + if(!CmpStr(avgMode, SF_OP_AVG_BINS)) + sprintf expr, "ivsccavg = avg([%s], bins, [%f,%f],%f,[%s])", freqList, binRange[0], binRange[1], binWidth, currentList + formula = SF_AddExpressionToFormula(formula, expr) + sprintf expr, "ivscccurrentavg = avg([%s], bins, [%f,%f],%f,[%s])", currentList, binRange[0], binRange[1], binWidth, currentList + formula = SF_AddExpressionToFormula(formula, expr) + + if(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + expr = "ivsccavg_norm_x = merge($ivscccurrentavg - extract($ivscccurrentavg, 0))" + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + expr = "ivsccavg_norm_x = merge($ivscccurrentavg - min(merge($ivscccurrentavg)))" + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + expr = "ivsccavg_norm_x = merge($ivscccurrentavg - max(merge($ivscccurrentavg)))" + else // SF_OP_IVSCCAPFREQUENCY_NONE + expr = "ivsccavg_norm_x = merge($ivscccurrentavg)" + endif + formula = SF_AddExpressionToFormula(formula, expr) + else + // SF_OP_AVG_BINS2 + sprintf expr, "ivsccavg = avg([%s], bins2, [%s])", freqList, currentList + formula = SF_AddExpressionToFormula(formula, expr) + expr = "ivsccavg_xvalues = xvalues(merge($ivsccavg))" + formula = SF_AddExpressionToFormula(formula, expr) + + if(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + // expr = "ivsccavg_norm_x = merge($ivscccurrentavg - extract($ivscccurrentavg, 0, 0))" + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + expr = "ivsccavg_norm_x = $ivsccavg_xvalues - min($ivsccavg_xvalues)" + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + expr = "ivsccavg_norm_x = $ivsccavg_xvalues - max($ivsccavg_xvalues)" + else // SF_OP_IVSCCAPFREQUENCY_NONE + expr = "ivsccavg_norm_x = $ivsccavg_xvalues" + endif + formula = SF_AddExpressionToFormula(formula, expr) + endif + if(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + expr = "ivsccavg_norm_y = merge($ivsccavg - extract($ivsccavg, 0))" + elseif(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + expr = "ivsccavg_norm_y = merge($ivsccavg - min(merge($ivsccavg)))" + elseif(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + expr = "ivsccavg_norm_y = merge($ivsccavg - max(merge($ivsccavg)))" + else // SF_OP_IVSCCAPFREQUENCY_NONE + expr = "ivsccavg_norm_y = merge($ivsccavg)" + endif + formula = SF_AddExpressionToFormula(formula, expr) + + WAVE/WAVE varStorage = GetSFVarStorage(exd.graph) + Duplicate/FREE varStorage, varBackup + SFE_ExecuteVariableAssignments(exd.graph, formula, allowEmptyCode=1) + + SFH_AddVariableToStorage(exd.graph, "pfit", SFH_GetOutputForExecutor(prepFit, exd.graph, opShort)) + WAVE/WAVE fitResult = SFH_AddVariableToStorageByFormula(exd.graph, "ivscc_apfrequency_fit", "fit2($ivsccavg_norm_y, $ivsccavg_norm_x, $pfit)", opShort) + + // build plot tree + WAVE/WAVE varStorageOp = GetSFVarStorage(exd.graph) + WAVE wvResult = varStorageOp[%ivscc_apfrequency_explist] + + WAVE/WAVE plotAND = SFH_CreateSFRefWave(exd.graph, opShort, 1) + Make/FREE/WAVE/N=(numExp + 2, 2) plotWITH + SetDimlabel COLS, 0, FORMULAX, plotWITH + SetDimlabel COLS, 1, FORMULAY, plotWITH + plotAND[0] = plotWITH + + // apfrequency traces + for(i = 0; i < numExp; i += 1) + if(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + sprintf formula, "merge($freq%d - extract($freq%d, 0))", i, i + elseif(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + sprintf formula, "merge($freq%d - min(merge($freq%d)))", i, i + elseif(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + sprintf formula, "merge($freq%d - max(merge($freq%d)))", i, i + else // SF_OP_IVSCCAPFREQUENCY_NONE + sprintf formula, "merge($freq%d)", i + endif + WAVE/WAVE wvY = SFE_ExecuteFormula(formula, exd.graph, preProcess = 0) + if(DimSize(wvY, ROWS) > 0) + [s] = GetTraceColorNonHeadstage(i) + Make/FREE/W/U traceColor = {s.red, s.green, s.blue, SF_IVSCC_APFREQUENCY_OPACITY} + JWN_SetWaveInWaveNote(wvY[0], SF_META_TRACECOLOR, traceColor) + JWN_SetNumberInWaveNote(wvY[0], SF_META_MOD_MARKER, 19) + JWN_SetStringInWaveNote(wvY[0], SF_META_LEGEND_LINE_PREFIX, uniqueFiles[i]) + endif + plotWITH[i][%FORMULAY] = wvY + SFO_OperationIVSCCApFrequencySetPlotProperties(plotWITH[i][%FORMULAY], xAxisPercentage, yAxisPercentage) + sprintf formula, "merge($currentNorm%d)", i + plotWITH[i][%FORMULAX] = SFE_ExecuteFormula(formula, exd.graph, preProcess = 0) + endfor + + // avg trace + formula = "$ivsccavg_norm_y" + WAVE/WAVE wvY = SFE_ExecuteFormula(formula, exd.graph, preProcess = 0) + if(DimSize(wvY, ROWS) > 0) + JWN_SetStringInWaveNote(wvY[0], SF_META_LEGEND_LINE_PREFIX, "ivscc_apfrequency avg " + avgMode) + endif + JWN_SetStringInWaveNote(wvY, SF_META_XAXISLABEL, "x value") // activates x values + plotWITH[numExp][%FORMULAY] = wvY + SFO_OperationIVSCCApFrequencySetPlotProperties(plotWITH[numExp][%FORMULAY], xAxisPercentage, yAxisPercentage) + + formula = "$ivsccavg_norm_x" + plotWITH[numExp][%FORMULAX] = SFE_ExecuteFormula(formula, exd.graph, preProcess = 0) + + numExp += 1 + // fit trace + formula = "$ivscc_apfrequency_fit" + WAVE/WAVE wvY = SFE_ExecuteFormula(formula, exd.graph, preProcess = 0) + if(DimSize(wvY, ROWS) > 0) + JWN_SetStringInWaveNote(wvY[0], SF_META_LEGEND_LINE_PREFIX, "ivscc_apfrequency fit") + endif + plotWITH[numExp][%FORMULAY] = wvY + + Duplicate/O varBackup, varStorage + SFH_AddVariableToStorage(exd.graph, "ivscc_apfrequency_explist", wvResult) + SFH_AddVariableToStorage(exd.graph, "ivscc_apfrequency_fit", SFH_GetOutputForExecutor(fitResult, exd.graph, opShort)) + + JWN_SetNumberInWaveNote(plotAND, SF_META_PLOT, 1) + + return SFH_GetOutputForExecutor(plotAND, exd.graph, opShort) +End + +Function SFO_OperationPrepareFit_PROTO(WAVE w, variable x) + FATAL_ERROR("Prototype function called") +End + +/// preparefit([fitFuncName, coefs, holdStr, range, constraints]) +Function/WAVE SFO_OperationPrepareFit(STRUCT SF_ExecutionData &exd) + + string opShort = SF_OP_PREPAREFIT + variable numArgs, numCoefs + string fitfuncName, holdStr, checkStr + + SFH_CheckArgumentCount(exd, opShort, 0, maxArgs = 4) + + WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, 1) + JWN_SetStringInWaveNote(output, SF_META_DATATYPE, SF_DATATYPE_PREPAREFIT) + + WAVE/WAVE prepFit = GetSFPrepareFitWave() + output[0] = prepFit + + WAVE/T fitArgs = prepFit[%FITARGS] + + numArgs = SFH_GetNumberOfArguments(exd) + if(numArgs == 0) + fitArgs[%FITFUNCNAME] = SF_PREPAREFIT_NOFUNC + return SFH_GetOutputForExecutor(output, exd.graph, opShort) + endif + + fitfuncName = SFH_GetArgumentAsText(exd, opShort, 0) + if(IsIntegratedFitFunction(fitFuncName)) + WAVE/Z/WAVE coefsArray = SFH_GetArgumentAsWave(exd, opShort, 1, defWave=$"") + if(WaveExists(coefsArray)) + SFH_ASSERT(SFH_IsArray(coefsArray), "Expected array at coefs arg position") + WAVE coefs = coefsArray[0] + else + WAVE/Z coefs = $"" + numCoefs = GetIntegratedFitFunctionCoefficientNumber(fitFuncName) + endif + else + FUNCREF SFO_OperationPrepareFit_PROTO func = $fitfuncName + SFH_ASSERT(FuncRefIsAssigned(FuncRefInfo(func)), "The specified user fit function does not exist: " + fitfuncName) + WAVE/WAVE coefsArray = SFH_GetArgumentAsWave(exd, opShort, 1) + SFH_ASSERT(SFH_IsArray(coefsArray), "Expected array at coefs arg position") + WAVE coefs = coefsArray[0] + endif + fitArgs[%FITFUNCNAME] = fitfuncName + + if(WaveExists(coefs)) + SFH_ASSERT(IsNumericWave(coefs), "Expected numeric wave for coefs argument") + numCoefs = DimSize(coefs, ROWS) + endif + prepFit[%COEFS] = coefs + + holdStr = PadString("", numCoefs, char2num("O")) + holdStr = SFH_GetArgumentAsText(exd, opShort, 2, defValue = holdStr, checkFunc = IsSFPrepareFitHoldString) + SFH_ASSERT(strlen(holdStr) == numCoefs, "Number of coefficients does not match number of characters in hold string.") + holdStr = ReplaceString(SF_PREPAREFIT_HOLDCHAR_HOLD, holdStr, "1") + holdStr = ReplaceString(SF_PREPAREFIT_HOLDCHAR_FREE, holdStr, "0") + fitArgs[%HOLDSTR] = holdStr + + WAVE/Z/WAVE rangeArray = SFH_GetArgumentAsWave(exd, opShort, 3, defWave = $"") + if(WaveExists(rangeArray)) + SFH_ASSERT(SFH_IsArray(rangeArray), "Expected array at range arg position") + WAVE range = rangeArray[0] + SFH_ASSERT(IsNumericWave(range), "Expected numeric wave for range argument") + SFH_ASSERT(DimSize(range, ROWS) == 2, "Expected range wave to have two entries") + SFH_ASSERT(range[0] >= 0, "First range element must be >= 0") + SFH_ASSERT(range[1] <= 0, "Second range element must be <= 0") + prepFit[%RANGE] = range + endif + + WAVE/Z/WAVE constraintsArray = SFH_GetArgumentAsWave(exd, opShort, 4, defWave = $"") + if(WaveExists(constraintsArray)) + SFH_ASSERT(SFH_IsArray(constraintsArray), "Expected array at constraints arg position") + WAVE/T constraints = constraintsArray[0] + SFH_ASSERT(IsTextWave(constraints), "Expected text wave for constraints argument") + prepFit[%CONSTRAINTS] = constraints + endif + + return SFH_GetOutputForExecutor(output, exd.graph, opShort) +End + +/// fit2(wvY, wvX, preparefit(...)) +Function/WAVE SFO_OperationFit2(STRUCT SF_ExecutionData &exd) + + string opShort = SF_OP_FIT2 + string dataType + variable numDatasets + + SFH_CheckArgumentCount(exd, opShort, 2, maxArgs = 3) + WAVE/WAVE datasetsWvY = SFH_GetArgumentAsWave(exd, opShort, 0) + WAVE/WAVE datasetsWvX = SFH_GetArgumentAsWave(exd, opShort, 1) + numDatasets = DimSize(datasetsWvY, ROWS) + dataType = JWN_GetStringFromWaveNote(datasetsWvX, SF_META_DATATYPE) + if(!CmpStr(dataType, SF_DATATYPE_PREPAREFIT)) + WAVE/WAVE prepFit = datasetsWvX[0] + Make/WAVE/FREE/N=(numDatasets) datasetsWvX + else + SFH_ASSERT(numDatasets == DimSize(datasetsWvX, ROWS), "number of datasets for wvY must equal number of datasets for wvX") + WAVE/WAVE prepFitRef = SFH_GetArgumentAsWave(exd, opShort, 2) + dataType = JWN_GetStringFromWaveNote(prepFitRef, SF_META_DATATYPE) + SFH_ASSERT(!CmpStr(dataType, SF_DATATYPE_PREPAREFIT), "Expected argument of type preparefit") + WAVE/WAVE prepFit = prepFitRef[0] + endif + + WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, numDatasets) + + output[] = SFO_OperationFit2Impl(datasetsWvY[p], datasetsWvX[p], prepFit) + + JWN_SetStringInWaveNote(output, SF_META_XAXISLABEL, "x value") // activates x values + + return SFH_GetOutputForExecutor(output, exd.graph, opShort) +End + +static Function/S SFO_OperationFit2GetFitStatusMessage(variable fitError, variable fitQuitReason, variable fitNumIters) + + string msg = "" + + if(FitError == 0) + msg += "Fit Ok.\r" + endif + if((FitError & FIT_ERROR_ANY) == FIT_ERROR_ANY) + msg += "Fit Error.\r" + endif + if((FitError & FIT_ERROR_SINGULARMATRIX) == FIT_ERROR_SINGULARMATRIX) + msg += "Singular Matrix.\r" + endif + if((FitError & FIT_ERROR_OUTOFMEMORY) == FIT_ERROR_OUTOFMEMORY) + msg += "Out of memory.\r" + endif + if((FitError & FIT_ERROR_RETURNEDNANORINF) == FIT_ERROR_RETURNEDNANORINF) + msg += "Fit function returned NaN or Inf.\r" + endif + if((FitError & FIT_ERROR_FUNCREQUESTEDSTOP) == FIT_ERROR_FUNCREQUESTEDSTOP) + msg += "Function requested stop.\r" + endif + if((FitError & FIT_ERROR_REENTRANT_FIT) == FIT_ERROR_REENTRANT_FIT) + msg += "Reentrant fit function call encountered.\r" + endif + if((FitQuitReason & FIT_QUITREASON_ITERATIONLIMITREACHED) == FIT_QUITREASON_ITERATIONLIMITREACHED) + msg += "Iteration limit reached.\r" + endif + if((FitQuitReason & FIT_QUITREASON_STOPPEDBYUSER) == FIT_QUITREASON_STOPPEDBYUSER) + msg += "User stopped fit.\r" + endif + if((FitQuitReason & FIT_QUITREASON_NOCHISQUAREDECREASE) == FIT_QUITREASON_NOCHISQUAREDECREASE) + msg += "chiSquare did not decrease in last 9 iterations.\r" + endif + msg += "Iterations run: " + num2istr(fitNumIters) + + return msg +End + +static Function/WAVE SFO_OperationFit2CalculateWeights(WAVE/Z wMinus, WAVE/Z wPlus) + + if(!WaveExists(wMinus) && !WaveExists(wPlus)) + return $"" + endif + + if(!WaveExists(wPlus)) + Make/FREE/D/N=(DimSize(wMinus, ROWS)) weight + MultiThread weight[] = abs(wMinus[p]) + elseif(!WaveExists(wMinus)) + Make/FREE/D/N=(DimSize(wPlus, ROWS)) weight + MultiThread weight[] = abs(wPlus[p]) + else + Make/FREE/D/N=(DimSize(wMinus, ROWS)) weight + MultiThread weight[] = (abs(wPlus[p]) + abs(wMinus[p])) / 2 + endif + + return weight +End + +static Function/WAVE SFO_OperationFit2Impl(WAVE wvY, WAVE/Z wvX, WAVE/WAVE prepFit) + + string fitFuncName, holdStr, fitStatus + variable V_FitError, V_FitQuitReason, V_FitNumIters, V_ChiSq, V_FitMaxIters + variable numPoints, xErrorsOut, haveConstraints + + V_FitMaxIters = SF_FIT2_MAX_ITERATIONS + + numPoints = DimSize(wvY, ROWS) + + if(WaveExists(wvX)) + WAVE/D xWave = wvX + else + WAVE/Z/D xWave = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_XVALUES) + if(WaveExists(xWave)) + SFH_ASSERT(IsNumericWave(xWave), "Require wvX to be numeric") + else + Make/FREE/D/N=(numPoints) xWave + Multithread xWave[] = IndexToScale(wvY, p, ROWS) + endif + endif + SFH_ASSERT(numPoints == DimSize(xWave, ROWS), "Number of points in xWave must equal number of points in y-wave") + + WAVE/T fitArgs = prepFit[%FITARGS] + fitFuncName = fitArgs[%FITFUNCNAME] + if(!CmpStr(fitFuncName, SF_PREPAREFIT_NOFUNC)) + return $"" + endif + + holdStr = fitArgs[%HOLDSTR] + WAVE/Z coefs = prepFit[%COEFS] + WAVE/Z/T constraints = prepFit[%CONSTRAINTS] + haveConstraints = WaveExists(constraints) + if(!haveConstraints) + // use always a constraints wave to reduce flag combinations for CurveFit + Make/FREE/T/N=0 constraints + endif + + WAVE/Z/D errorbarYPlus = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_ERRORBARYPLUS) + if(WaveExists(errorbarYPlus)) + SFH_ASSERT(numPoints == DimSize(errorbarYPlus, ROWS), "number of points in errorbar must equal the number of points from y-wave") + endif + WAVE/Z/D errorbarYMinus = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_ERRORBARYMINUS) + if(WaveExists(errorbarYMinus)) + SFH_ASSERT(numPoints == DimSize(errorbarYMinus, ROWS), "number of points in errorbar must equal the number of points from y-wave") + endif + WAVE/Z/D errorbarXPlus = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_ERRORBARXPLUS) + if(WaveExists(errorbarXPlus)) + SFH_ASSERT(numPoints == DimSize(errorbarXPlus, ROWS), "number of points in errorbar must equal the number of points from y-wave") + endif + WAVE/Z/D errorbarXMinus = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_ERRORBARXMINUS) + if(WaveExists(errorbarXMinus)) + SFH_ASSERT(numPoints == DimSize(errorbarXMinus, ROWS), "number of points in errorbar must equal the number of points from y-wave") + endif + + WAVE/Z/D weightY = SFO_OperationFit2CalculateWeights(errorbarYMinus, errorbarYPlus) + WAVE/Z/D weightX = SFO_OperationFit2CalculateWeights(errorbarXMinus, errorbarXPlus) + xErrorsOut = WaveExists(weightX) + + if(!WaveExists(weightY)) + // use always a weight wave for Y to reduce flag combinations for CurveFit + Make/FREE/D/N=(numPoints) weightY + FastOp weightY = 1 + endif + + Make/FREE/D/N=(numPoints) fitOutput, yResiduals, xResiduals, xOutput, mask + + FastOp mask = 1 + WAVE/Z range = prepFit[%RANGE] + if(WaveExists(range)) + if(range[0] > 0) + mask[0, limit(range[0] - 1, 0, numPoints - 1)] = 0 + endif + if(range[1] < 0) + mask[limit(numPoints + range[1], 0, numPoints - 1), Inf] = 0 + endif + endif + + DFREF dfrSave = GetDataFolderDFR() + DFREF dfr = NewFreeDataFolder() + SetDataFolder dfr + + if(!IsIntegratedFitFunction(fitFuncName)) + // FuncFit + ASSERT(WaveExists(coefs), "For user fit function coefs must exist") + if(xErrorsOut) + // ODR fit + FuncFit/C/Q/M=2/H=holdStr $fitFuncName, coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + FuncFit/C/Q/M=2/H=holdStr $fitFuncName, coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + // CurveFit + strswitch(fitFuncName) + case "gauss": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 gauss, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr gauss, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 gauss, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr gauss, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "lor": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 lor, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr lor, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 lor, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr lor, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "Voigt": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 Voigt, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr Voigt, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 Voigt, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr Voigt, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "exp": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 exp, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr exp, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 exp, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr exp, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "dblexp": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 dblexp, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr dblexp, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 dblexp, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr dblexp, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "exp_XOffset": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 exp_XOffset, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr exp_XOffset, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 exp_XOffset, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr exp_XOffset, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "dblexp_XOffset": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 dblexp_XOffset, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr dblexp_XOffset, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 dblexp_XOffset, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr dblexp_XOffset, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "dblexp_peak": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 dblexp_peak, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr dblexp_peak, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 dblexp_peak, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr dblexp_peak, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "sin": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 sin, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr sin, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 sin, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr sin, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "line": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 line, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr line, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 line, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr line, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly 1": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly 1, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly 1, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly 1, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly 1, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly 2": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly 2, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly 2, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly 2, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly 2, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly 3": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly 3, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly 3, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly 3, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly 3, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly 4": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly 4, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly 4, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly 4, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly 4, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly_XOffset 1": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly_XOffset 1, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly_XOffset 1, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly_XOffset 1, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly_XOffset 1, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly_XOffset 2": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly_XOffset 2, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly_XOffset 2, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly_XOffset 2, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly_XOffset 2, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly_XOffset 3": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly_XOffset 3, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly_XOffset 3, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly_XOffset 3, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly_XOffset 3, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly_XOffset 4": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly_XOffset 4, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly_XOffset 4, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly_XOffset 4, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly_XOffset 4, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "hillequation": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 hillequation, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr hillequation, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 hillequation, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr hillequation, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "sigmoid": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 sigmoid, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr sigmoid, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 sigmoid, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr sigmoid, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "power": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 power, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr power, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 power, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr power, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "lognormal": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 lognormal, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr lognormal, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 lognormal, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr lognormal, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "log": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 log, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr log, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 log, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr log, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "gauss2D": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 gauss2D, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr gauss2D, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 gauss2D, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr gauss2D, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly2D 1": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly2D 1, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly2D 1, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly2D 1, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly2D 1, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly2D 2": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly2D 2, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly2D 2, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly2D 2, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly2D 2, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly2D 3": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly2D 3, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly2D 3, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly2D 3, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly2D 3, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + case "poly2D 4": + if(WaveExists(coefs)) + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly2D 4, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly2D 4, kwCWave=coefs, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + else + if(xErrorsOut) + CurveFit/C/Q/M=2/H=holdStr/ODR=2 poly2D 4, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/XW=weightX/XD=xOutput/XR=xResiduals/I=1/M=mask + else + CurveFit/C/Q/M=2/H=holdStr poly2D 4, wvY/X=xWave/D=fitOutput/C=constraints/W=weightY/A=0/R=yResiduals/I=1/M=mask + endif + endif + break + default: + SFH_FATAL_ERROR("Unsupported integrated fit function") + endswitch + endif + if(!WaveExists(coefs)) + WAVE coefs = W_coef + endif + if(haveConstraints) + WAVE/Z mFitConstraints = M_FitConstraint + WAVE/Z wFitConstraints = W_FitConstraint + endif + + WAVE/Z wSigma = W_Sigma + WAVE/Z mCovar = M_Covar + + SetDataFolder dfrSave + + fitStatus = SFO_OperationFit2GetFitStatusMessage(V_FitError, V_FitQuitReason, V_FitNumIters) + + JWN_CreatePath(fitOutput, SF_SERIALIZE) + if(V_FitError) + Make/FREE/D/N=0 fitOutput + JWN_SetNumberInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITERROR, V_FitError) + JWN_SetNumberInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITQUITREASON, V_FitQuitReason) + JWN_SetNumberInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITNUMITERS, V_FitNumIters) + endif + + JWN_SetStringInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITSTATUSMESSAGE, fitStatus) + JWN_SetStringInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITFUNC, fitFuncName) + + if(V_FitError) + return fitOutput + endif + + JWN_SetWaveInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITCOEFS, coefs) + JWN_SetWaveInWaveNote(fitOutput, SF_META_ERRORBARYPLUS, yResiduals) + JWN_SetWaveInWaveNote(fitOutput, SF_META_ERRORBARYMINUS, yResiduals) + if(xErrorsOut) + JWN_SetWaveInWaveNote(fitOutput, SF_META_ERRORBARXPLUS, xResiduals) + JWN_SetWaveInWaveNote(fitOutput, SF_META_ERRORBARXMINUS, xResiduals) + JWN_SetWaveInWaveNote(fitOutput, SF_META_XVALUES, xOutput) + else + JWN_SetWaveInWaveNote(fitOutput, SF_META_XVALUES, xWave) + endif + + // Possible more fit data: V_npnts, V_nterms, V_nheld + JWN_SetNumberInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITCHISQUARE, V_ChiSq) + if(WaveExists(wSigma)) + JWN_SetWaveInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITWSIGMA, wSigma) + endif + if(WaveExists(mCovar)) + JWN_SetWaveInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITMCOVAR, mCovar) + endif + if(WaveExists(mFitConstraints)) + JWN_SetWaveInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITMFITCONSTRAINT, mFitConstraints) + endif + if(WaveExists(wFitConstraints)) + JWN_SetWaveInWaveNote(fitOutput, SF_SERIALIZE + SF_META_FITWFITCONSTRAINT, wFitConstraints) + endif + + SFH_SetTraceStyleForFit(fitOutput) + + return fitOutput +End + +/// getmeta(data, [keyStr, datasetNumber] +Function/WAVE SFO_OperationGetMeta(STRUCT SF_ExecutionData &exd) + + string opShort = SF_OP_GETMETA + string key, str, path, serStr + variable dsNum, numDatasets, val + + SFH_CheckArgumentCount(exd, opShort, 0, maxArgs = 3) + WAVE/WAVE datasets = SFH_GetArgumentAsWave(exd, opShort, 0) + key = SFH_GetArgumentAsText(exd, opShort, 1, defValue="") + dsNum = SFH_GetArgumentAsNumeric(exd, opShort, 2, defValue=0) + + numDatasets = DimSize(datasets, ROWS) + SFH_ASSERT(dsNum < numDatasets, "Dataset with given number does not exist in input data") + WAVE/Z data = datasets[dsNum] + + WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, 1) + if(!WaveExists(data)) + return SFH_GetOutputForExecutor(output, exd.graph, opShort) + endif + + if(IsEmpty(key)) + WAVE/Z/T keys = JWN_GetKeysAt(data, SF_SERIALIZE) + serStr = "" + for(string key : keys) + path = SF_SERIALIZE + "/" + key + val = JWN_GetNumberFromWaveNote(data, path) + if(!IsNaN(val)) + serStr += key + ": " + num2str(val, "%f") + "\r" + continue + endif + str = JWN_GetStringFromWaveNote(data, path) + if(!IsEmpty(str)) + serStr += key + ":\r" + str + "\r" + continue + endif + WAVE/Z wvn = JWN_GetNumericWaveFromWaveNote(data, path) + if(WaveExists(wvn)) + str = NumericWaveToList(wvn, "\r") + serStr += key + ":\r" + str + continue + endif + WAVE/Z/T wt = JWN_GetTextWaveFromWaveNote(data, path) + if(WaveExists(wt)) + str = TextWaveToList(wt, "\r") + serStr += key + ":\r" + str + continue + endif + endfor + serStr = RemoveEnding(serStr, "\r") + Make/FREE/T wvt = {serStr} + output[0] = wvt + else + path = SF_SERIALIZE + "/" + key + val = JWN_GetNumberFromWaveNote(data, path) + if(!IsNaN(val)) + Make/FREE/D wv = {val} + SetDimLabel ROWS, 0, $key, wv + output[0] = wv + endif + str = JWN_GetStringFromWaveNote(data, path) + if(!IsEmpty(str)) + Make/FREE/T wvt = {str} + SetDimLabel ROWS, 0, $key, wvt + output[0] = wvt + endif + WAVE/Z wvn = JWN_GetNumericWaveFromWaveNote(data, path) + if(WaveExists(wvn)) + output[0] = wvn + endif + WAVE/Z/T wvt = JWN_GetTextWaveFromWaveNote(data, path) + if(WaveExists(wvt)) + output[0] = wvt + endif + endif + + return SFH_GetOutputForExecutor(output, exd.graph, opShort) +End diff --git a/Packages/MIES/MIES_SweepFormula_Parser.ipf b/Packages/MIES/MIES_SweepFormula_Parser.ipf index 764e8f59e5..5a57ebdc4f 100644 --- a/Packages/MIES/MIES_SweepFormula_Parser.ipf +++ b/Packages/MIES/MIES_SweepFormula_Parser.ipf @@ -42,7 +42,7 @@ static StrConstant SF_PARSER_REGEX_SIGNED_NUMBER = "^(?i)[+-]?[0-9]+(?:\.[0 static StrConstant SF_PARSER_REGEX_QUOTED_STRING = "^\".*\"$" static StrConstant SF_PARSER_REGEX_SIGNED_PARENTHESIS = "^(?i)[+-]?\\([\s\S]*$" static StrConstant SF_PARSER_REGEX_SIGNED_FUNCTION = "^(?i)[+-]?[A-Za-z]+" -static StrConstant SF_PARSER_REGEX_OTHER_VALID_CHARS = "[A-Za-z0-9_\.:;=!$]" +static StrConstant SF_PARSER_REGEX_OTHER_VALID_CHARS = "[A-Za-z0-9_\.:;=!$<>]" // The structure stores data that is required and gathered when a SF formula is parsed static Structure SF_ParserData diff --git a/Packages/MIES/MIES_Utilities_Checks.ipf b/Packages/MIES/MIES_Utilities_Checks.ipf index 1bb8a291db..21498c6ce5 100644 --- a/Packages/MIES/MIES_Utilities_Checks.ipf +++ b/Packages/MIES/MIES_Utilities_Checks.ipf @@ -526,3 +526,36 @@ Function ListHasOnlyOneUniqueEntry(string list, [string sep]) return 1 End + +/// @brief Returns 1 if the given fitFuncName is an Igor integrated fit function, 0 otherwise +Function IsIntegratedFitFunction(string fitFuncName) + + variable col + + ASSERT(!IsEmpty(fitFuncName), "Expected non-empty fit func name") + + WAVE/T fitProps = GetSFIgorFitProperties() + + col = FindDimLabel(fitProps, COLS, "FITFUNC") + ASSERT(col >= 0, "Column not found") + FindValue/Z/TEXT=(fitFuncName)/TXOP=4/RMD=[][col] fitProps + + return V_value >= 0 +End + +/// @brief Returns the number of coefficients required for an integrated fit function +Function GetIntegratedFitFunctionCoefficientNumber(string fitFuncName) + + variable col + + ASSERT(!IsEmpty(fitFuncName), "Expected non-empty fit func name") + + WAVE/T fitProps = GetSFIgorFitProperties() + + col = FindDimLabel(fitProps, COLS, "FITFUNC") + ASSERT(col >= 0, "Column not found") + FindValue/Z/TEXT=(fitFuncName)/TXOP=4/RMD=[][col] fitProps + ASSERT(V_value >= 0, "Given fitFuncName is not an integrated Igor fit function") + + return str2num(fitProps[V_row][%NUMCOEFS]) +End diff --git a/Packages/MIES/MIES_Utilities_SFHCheckers.ipf b/Packages/MIES/MIES_Utilities_SFHCheckers.ipf index 9a6961dbc2..e05a967a28 100644 --- a/Packages/MIES/MIES_Utilities_SFHCheckers.ipf +++ b/Packages/MIES/MIES_Utilities_SFHCheckers.ipf @@ -78,3 +78,19 @@ threadsafe Function BetweenZeroAndOneHoundred(variable val) return val >= 0.0 && val <= 100.0 End + +/// @brief Return the truth if `holdStr` is non-empty and contains only SF_PREPAREFIT_HOLDCHAR_HOLD or SF_PREPAREFIT_HOLDCHAR_FREE +/// The function DOES NOT check if the length is correct +/// +/// UTF_NOINSTRUMENTATION +threadsafe Function IsSFPrepareFitHoldString(string holdStr) + + if(IsEmpty(holdStr)) + return 0 + endif + + holdStr = ReplaceString(SF_PREPAREFIT_HOLDCHAR_HOLD, holdStr, "") + holdStr = ReplaceString(SF_PREPAREFIT_HOLDCHAR_FREE, holdStr, "") + + return IsEmpty(holdStr) +End diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index a656b51a1d..81ffce760c 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -7664,6 +7664,41 @@ Function/WAVE GetSweepFormulaY(DFREF dfr, variable graphNr) return wv End +/// @brief Return a permanent wave for errorBars +Function/WAVE GetSweepFormulaErrorbar(DFREF dfr, string traceName, string tagName) + + string wName, suffix + + strswitch(tagName) + case SF_META_ERRORBARYPLUS: + suffix = "yplus" + break + case SF_META_ERRORBARYMINUS: + suffix = "yminus" + break + case SF_META_ERRORBARXPLUS: + suffix = "xplus" + break + case SF_META_ERRORBARXMINUS: + suffix = "xminus" + break + default: + FATAL_ERROR("Unknown errorbar tag") + endswitch + + wName = "sf_errorbar_" + traceName + "_" + suffix + + WAVE/Z/D/SDFR=dfr wv = $wName + + if(WaveExists(wv)) + return wv + endif + + Make/N=0/D dfr:$wName/WAVE=wv + + return wv +End + /// @brief Return the global temporary wave for extended popup menu Function/WAVE GetPopupExtMenuWave() @@ -9367,8 +9402,8 @@ End /// @brief Wave storing sf plot meta information per formularesult, filled in SF_GatherFormulaResults Function/WAVE GetSFPlotMetaData() - Make/FREE/T/N=(5) wv - SetDimensionLabels(wv, "DATATYPE;OPSTACK;ARGSETUPSTACK;XAXISLABEL;YAXISLABEL;", ROWS) + Make/FREE/T/N=(9) wv + SetDimensionLabels(wv, "DATATYPE;OPSTACK;ARGSETUPSTACK;XAXISLABEL;YAXISLABEL;XAXISOFFSET;YAXISOFFSET;XAXISPERCENT;YAXISPERCENT;", ROWS) return wv End @@ -9405,3 +9440,60 @@ Function/WAVE GetFullPlottingWITH(variable size) return plotWITH End + +/// @brief Returns a wave with all Igor integrated fit functions and their respective number of coefficients +/// For poly functions upto 4th order is included (Igor Pro supports up to 20th order) +Function/WAVE GetSFIgorFitProperties() + + Make/FREE/T/N=(28, 2) wv + + wv[0][] = {{"gauss"}, {"4"}} + wv[1][] = {{"lor"}, {"4"}} + wv[2][] = {{"Voigt"}, {"5"}} + wv[3][] = {{"exp"}, {"3"}} + wv[4][] = {{"dblexp"}, {"5"}} + wv[5][] = {{"exp_XOffset"}, {"3"}} + wv[6][] = {{"dblexp_XOffset"}, {"5"}} + wv[7][] = {{"dblexp_peak"}, {"5"}} + wv[8][] = {{"sin"}, {"4"}} + wv[9][] = {{"line"}, {"2"}} + wv[10][] = {{"poly 1"}, {"1"}} + wv[11][] = {{"poly 2"}, {"2"}} + wv[12][] = {{"poly 3"}, {"3"}} + wv[13][] = {{"poly 4"}, {"4"}} + wv[14][] = {{"poly_XOffset 1"}, {"1"}} + wv[15][] = {{"poly_XOffset 2"}, {"2"}} + wv[16][] = {{"poly_XOffset 3"}, {"3"}} + wv[17][] = {{"poly_XOffset 4"}, {"4"}} + wv[18][] = {{"hillequation"}, {"4"}} + wv[19][] = {{"sigmoid"}, {"4"}} + wv[20][] = {{"power"}, {"3"}} + wv[21][] = {{"lognormal"}, {"4"}} + wv[22][] = {{"log"}, {"2"}} + wv[23][] = {{"gauss2D"}, {"7"}} + wv[24][] = {{"poly2D 1"}, {"3"}} + wv[25][] = {{"poly2D 2"}, {"6"}} + wv[26][] = {{"poly2D 3"}, {"10"}} + wv[27][] = {{"poly2D 4"}, {"15"}} + + SetDimLabel COLS, 0, FITFUNC, wv + SetDimLabel COLS, 1, NUMCOEFS, wv + + return wv +End + +/// @brief The returned wave reference wave encapsulates the information gathered by the SF operation PrepareFit +Function/WAVE GetSFPrepareFitWave() + + Make/FREE/T/N=2 txtInfo + SetDimLabel ROWS, 0, FITFUNCNAME, txtInfo + SetDimLabel ROWS, 1, HOLDSTR, txtInfo + + Make/FREE/WAVE wv = {txtInfo, $"", $"", $""} + SetDimLabel ROWS, 0, FITARGS, wv + SetDimLabel ROWS, 1, COEFS, wv + SetDimLabel ROWS, 2, RANGE, wv + SetDimLabel ROWS, 3, CONSTRAINTS, wv + + return wv +End