Skip to content
137 changes: 65 additions & 72 deletions Packages/MIES/MIES_BrowserSettingsPanel.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ static StrConstant SWEEPCONTROL_CONTROLS_SWEEPBROWSER = "popup_SweepControl_Sele

static StrConstant BSP_USER_DATA_SF_CONTENT_CRC = "SweepFormulaContentCRC"

static Constant BSP_EPOCH_LEVELS = 5

/// @brief return the name of the external panel depending on main window name
///
/// @param mainPanel mainWindow panel name
Expand Down Expand Up @@ -1597,12 +1599,11 @@ End
/// @brief Debug function to add traces with epoch information
Function BSP_AddTracesForEpochs(string win)

variable i, j, k, numEntries, start_x, start_y, end_x, end_y, yOffset
variable headstage, yLevelOffset, level, idx, numTraces, numEpochs
variable i, j, numEntries, start_x, start_y, end_x, end_y, yOffset
variable headstage, channelType, channelNumber, channelNumberDA, yLevelOffset, level, idx, numTraces, numEpochs
variable sweepNumber, traceIndex
STRUCT RGBColor c
string xaxis, yaxis, axes, axis, levels_x_name, levels_y_name, name, epochInfoStr
string level_0_trace, level_1_trace, level_2_trace, level_3_trace, level_4_trace
string xaxis, yaxis, axes, axis, levels_x_name, levels_y_name, name, epochInfoStr, idPart, level_x_trace

if(!BSP_IsDataBrowser(win) && !BSP_IsSweepBrowser(win))
printf "The current window is neither a databrowser nor a sweepbrowser windows.\r"
Expand All @@ -1613,78 +1614,92 @@ Function BSP_AddTracesForEpochs(string win)
DFREF dfr = GetEpochsVisualizationFolder(BSP_GetFolder(win, MIES_BSP_PANEL_FOLDER))
BSP_RemoveTraces(win)

WAVE/T/Z traceInfos = GetTraceInfos(win, addFilterKeys = {"channelType", "AssociatedHeadstage"}, addFilterValues = {"AD", "1"})
WAVE/T/Z traceInfosHS = GetTraceInfos(win, addFilterKeys = {"channelType", "AssociatedHeadstage"}, addFilterValues = {"AD", "1"})

if(!WaveExists(traceInfos))
if(!WaveExists(traceInfosHS))
// fallback to DA traces
WAVE/T/Z traceInfos = GetTraceInfos(win, addFilterKeys = {"channelType", "AssociatedHeadstage"}, addFilterValues = {"DA", "1"})
WAVE/T/Z traceInfosHS = GetTraceInfos(win, addFilterKeys = {"channelType", "AssociatedHeadstage"}, addFilterValues = {"DA", "1"})
endif

if(!WaveExists(traceInfos))
return NaN
endif
WAVE/T/Z traceInfosUnassocDA = GetTraceInfos(win, addFilterKeys = {"channelType", "AssociatedHeadstage"}, addFilterValues = {"DA", "0"})

if(!WaveExists(traceInfosHS) && !WaveExists(traceInfosUnassocDA))
return NaN
elseif(!WaveExists(traceInfosHS))
WAVE/T traceInfos = traceInfosUnassocDA
elseif(!WaveExists(traceInfosUnassocDA))
WAVE/T traceInfos = traceInfosHS
else
Concatenate/FREE/T/NP=(ROWS) {traceInfosUnassocDA}, traceInfosHS
WAVE/T traceInfos = traceInfosHS
endif

traceIndex = GetNextTraceIndex(win)

numTraces = DimSize(traceInfos, ROWS)
for(j = 0; j < numTraces; j += 1)
yaxis = traceInfos[j][%YAXIS]
xaxis = traceInfos[j][%XAXIS]
for(i = 0; i < numTraces; i += 1)
yaxis = traceInfos[i][%YAXIS]
xaxis = traceInfos[i][%XAXIS]

// use our own y axis
// need to replace for both AD and DA cases
yaxis = ReplaceString("_DA", yaxis, "_EP_DA")
yaxis = ReplaceString("_AD", yaxis, "_EP_DA")
yaxis = ReplaceString("_DA", yaxis, DB_AXIS_PART_EPOCHS + "_DA")
yaxis = ReplaceString("_AD", yaxis, DB_AXIS_PART_EPOCHS + "_DA")

headstage = str2num(traceInfos[i][%headstage])
sweepNumber = str2num(traceInfos[i][%sweepNumber])
channelType = WhichListItem(traceInfos[i][%channelType], XOP_CHANNEL_NAMES)
channelNumber = str2num(traceInfos[i][%channelNumber])

headstage = str2num(traceInfos[j][%headstage])
sweepNumber = str2num(traceInfos[j][%sweepNumber])
switch(channelType)
case XOP_CHANNEL_TYPE_ADC:
channelNumberDA = SFH_GetDAChannel(win, sweepNumber, channelType, channelNumber)
break
case XOP_CHANNEL_TYPE_DAC:
channelNumberDA = channelNumber
break
default:
ASSERT(0, "Unsupported channelType")
endswitch

WAVE/Z/T textualValues = BSP_GetLogbookWave(win, LBT_LABNOTEBOOK, LBN_TEXTUAL_VALUES, sweepNumber = sweepNumber)
ASSERT(WaveExists(textualValues), "Textual LabNotebook not found.")

WAVE/Z/T numericalValues = BSP_GetLogbookWave(win, LBT_LABNOTEBOOK, LBN_NUMERICAL_VALUES, sweepNumber = sweepNumber)
ASSERT(WaveExists(numericalValues), "Numerical LabNotebook not found.")
// present since a2172f03 (Added generations of epoch information wave, 2019-05-22)
WAVE/T/Z epochLBEntries = GetLastSetting(textualValues, sweepNumber, EPOCHS_ENTRY_KEY, DATA_ACQUISITION_MODE)

if(!WaveExists(epochLBEntries))
continue
endif

epochInfoStr = epochLBEntries[headstage]

if(IsEmpty(epochInfoStr))
WAVE/T/Z epochsFromLBN = EP_FetchEpochs(numericalValues, textualValues, sweepNumber, channelNumberDA, XOP_CHANNEL_TYPE_DAC)
if(!WaveExists(epochsFromLBN))
continue
endif

WAVE/T epochs = EP_EpochStrToWave(epochInfoStr)
SetEpochsDimensionLabels(epochs)

sprintf name, "epochs_sweep%d_HS%d", sweepNumber, headstage
sprintf idPart, "_sweep%d_chan%d_type%d_HS%d", sweepNumber, channelNumber, channelType, headstage
sprintf name, "epochs_%s", idPart

Duplicate/O/T epochs, dfr:$name/Wave=epochs
Duplicate/O/T epochsFromLBN, dfr:$name/Wave=epochs

yLevelOffset = 10
yOffset = - yLevelOffset

numEpochs = DimSize(epochs, ROWS)

Make/FREE/N=(5) currentLevel, indexInLevel
Make/FREE/N=(BSP_EPOCH_LEVELS) currentLevel, indexInLevel

sprintf levels_x_name, "levels_x_sweep%d_HS%d", sweepNumber, headstage
sprintf levels_x_name, "levels_x_%s", idpart
Make/O/N=(numEpochs * 3, 5, 2) dfr:$levels_x_name/WAVE=levels_x
levels_x = NaN

sprintf levels_y_name, "levels_y_sweep%d_HS%d", sweepNumber, headstage
sprintf levels_y_name, "levels_y_%s", idPart
Make/O/N=(numEpochs * 3, 5, 2) dfr:$levels_y_name/WAVE=levels_y
levels_y = NaN
SetStringInWaveNote(levels_y, "EpochInfo", GetWavesDataFolder(epochs, 2))

for(k = 0; k < numEpochs; k += 1)
for(j = 0; j < numEpochs; j += 1)

start_x = str2num(epochs[k][0]) * ONE_TO_MILLI
end_x = str2num(epochs[k][1]) * ONE_TO_MILLI
start_x = str2num(epochs[j][0]) * ONE_TO_MILLI
end_x = str2num(epochs[j][1]) * ONE_TO_MILLI

// handle EPOCH_USER_LEVEL being -1
level = str2num(epochs[k][3]) + 1
level = str2num(epochs[j][3]) + 1

start_y = yOffset - yLevelOffset * level - 0.1 * yLevelOffset * currentLevel[level]
end_y = start_y
Expand All @@ -1693,49 +1708,27 @@ Function BSP_AddTracesForEpochs(string win)
levels_x[idx][level][0] = start_x
levels_x[idx + 1][level][0] = end_x
levels_x[idx + 2][level][0] = NaN
levels_x[idx, idx + 2][level][1] = k
levels_x[idx, idx + 2][level][1] = j

levels_y[idx][level][0] = start_y
levels_y[idx + 1][level][0] = end_y
levels_y[idx + 2][level][0] = NaN
levels_y[idx, idx + 2][level][1] = k
levels_y[idx, idx + 2][level][1] = j

indexInLevel[level] = idx + 3

currentLevel[level] += 1
endfor

sprintf level_0_trace, "%s_level%d_x_sweep%d_HS%d", GetTraceNamePrefix(traceIndex++), 0, sweepNumber, headstage
sprintf level_1_trace, "%s_level%d_x_sweep%d_HS%d", GetTraceNamePrefix(traceIndex++), 1, sweepNumber, headstage
sprintf level_2_trace, "%s_level%d_x_sweep%d_HS%d", GetTraceNamePrefix(traceIndex++), 2, sweepNumber, headstage
sprintf level_3_trace, "%s_level%d_x_sweep%d_HS%d", GetTraceNamePrefix(traceIndex++), 3, sweepNumber, headstage
sprintf level_4_trace, "%s_level%d_x_sweep%d_HS%d", GetTraceNamePrefix(traceIndex++), 4, sweepNumber, headstage

AppendToGraph/W=$win/L=$yAxis levels_y[][0]/TN=$level_0_trace vs levels_x[][0]
TUD_SetUserDataFromWaves(win, level_0_trace, {"traceType", "occurence", "XAXIS", "YAXIS"}, {"EpochVis", "", "bottom", yaxis})

AppendToGraph/W=$win/L=$yAxis levels_y[][1]/TN=$level_1_trace vs levels_x[][1]
TUD_SetUserDataFromWaves(win, level_1_trace, {"traceType", "occurence", "XAXIS", "YAXIS"}, {"EpochVis", "", "bottom", yaxis})

AppendToGraph/W=$win/L=$yAxis levels_y[][2]/TN=$level_2_trace vs levels_x[][2]
TUD_SetUserDataFromWaves(win, level_2_trace, {"traceType", "occurence", "XAXIS", "YAXIS"}, {"EpochVis", "", "bottom", yaxis})

AppendToGraph/W=$win/L=$yAxis levels_y[][3]/TN=$level_3_trace vs levels_x[][3]
TUD_SetUserDataFromWaves(win, level_3_trace, {"traceType", "occurence", "XAXIS", "YAXIS"}, {"EpochVis", "", "bottom", yaxis})

AppendToGraph/W=$win/L=$yAxis levels_y[][4]/TN=$level_4_trace vs levels_x[][4]
TUD_SetUserDataFromWaves(win, level_4_trace, {"traceType", "occurence", "XAXIS", "YAXIS"}, {"EpochVis", "", "bottom", yaxis})

[c] = GetTraceColor(0)
ModifyGraph/W=$win marker($level_0_trace)=10, mode($level_0_trace)=4, rgb($level_0_trace)=(c.red, c.green, c.blue)
[c] = GetTraceColor(1)
ModifyGraph/W=$win marker($level_1_trace)=10, mode($level_1_trace)=4, rgb($level_1_trace)=(c.red, c.green, c.blue)
[c] = GetTraceColor(2)
ModifyGraph/W=$win marker($level_2_trace)=10, mode($level_2_trace)=4, rgb($level_2_trace)=(c.red, c.green, c.blue)
[c] = GetTraceColor(3)
ModifyGraph/W=$win marker($level_3_trace)=10, mode($level_3_trace)=4, rgb($level_3_trace)=(c.red, c.green, c.blue)
[c] = GetTraceColor(4)
ModifyGraph/W=$win marker($level_4_trace)=10, mode($level_4_trace)=4, rgb($level_4_trace)=(c.red, c.green, c.blue)
for(j = 0; j < BSP_EPOCH_LEVELS; j += 1)
sprintf level_x_trace, "%s_level%d_x_%s", GetTraceNamePrefix(traceIndex++), j, idPart

AppendToGraph/W=$win/L=$yAxis levels_y[][j]/TN=$level_x_trace vs levels_x[][j]
TUD_SetUserDataFromWaves(win, level_x_trace, {"traceType", "occurence", "XAXIS", "YAXIS"}, {"EpochVis", "", "bottom", yaxis})

[c] = GetTraceColor(j)
ModifyGraph/W=$win marker($level_x_trace)=10, mode($level_x_trace)=4, rgb($level_x_trace)=(c.red, c.green, c.blue)
endfor

SetWindow $win tooltipHook(hook) = BSP_EpochGraphToolTip

Expand Down
6 changes: 6 additions & 0 deletions Packages/MIES/MIES_Constants.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -2094,3 +2094,9 @@ Constant SATURDAY = 7
/// @}

Constant SECONDS_PER_DAY = 86400

/// @name DataBrowser visualisation constants
/// @anchor DataBrowserVisualizationConstants
/// @{
Strconstant DB_AXIS_PART_EPOCHS = "_EP"
/// @}
4 changes: 2 additions & 2 deletions Packages/MIES/MIES_Epochs.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ End
/// @param device device
/// @param s struct holding all input
Function EP_CollectEpochInfo(string device, STRUCT DataConfigurationResult &s)
variable i, channel, headstage, singleSetLength, epochOffset, epochBegin, epochEnd

variable i, channel, singleSetLength, epochOffset, epochBegin, epochEnd
variable stimsetCol, startOffset, stopCollectionPoint
string tags

Expand All @@ -80,7 +81,6 @@ Function EP_CollectEpochInfo(string device, STRUCT DataConfigurationResult &s)
endif

channel = s.DACList[i]
headstage = s.headstageDAC[i]
startOffset = s.insertStart[i]
singleSetLength = s.setLength[i]
WAVE singleStimSet = s.stimSet[i]
Expand Down
24 changes: 14 additions & 10 deletions Packages/MIES/MIES_MiesUtilities.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -2320,11 +2320,11 @@ Function LayoutGraph(string win, STRUCT TiledGraphSettings &tgs)
// up to three blocks

// (?<! is a negative look behind assertion
regex = ".*(?<!EP_)DA$"
sprintf regex, ".*(?<!%s_)DA$", DB_AXIS_PART_EPOCHS
WAVE/T/Z DAaxes = GrepWave(allVerticalAxes, regex)
numBlocksDA = WaveExists(DAaxes) ? DimSize(DAaxes, ROWS) : 0

regex = ".*EP_DA$"
sprintf regex, ".*%s_DA$", DB_AXIS_PART_EPOCHS
WAVE/T/Z Epochaxes = GrepWave(allVerticalAxes, regex)
numBlocksEpoch = WaveExists(Epochaxes) ? DimSize(Epochaxes, ROWS) : 0

Expand Down Expand Up @@ -2392,8 +2392,8 @@ Function LayoutGraph(string win, STRUCT TiledGraphSettings &tgs)
WAVE/T/Z axes = GrepWave(allVerticalAxes, regex)
numBlocksDA = WaveExists(axes) ? DimSize(axes, ROWS) : 0

// epoch info for associated DA channels
regex = ".*col0_EP_DA_(?:[[:digit:]]{1,2})_HS_(?:[[:digit:]]{1,2})$"
// epoch info slots for associated and unassociated DA channels
sprintf regex, ".*col0%s_DA_(?:[[:digit:]]{1,2})_HS_(?:([[:digit:]]{1,2}|NaN))$", DB_AXIS_PART_EPOCHS
WAVE/T/Z axes = GrepWave(allVerticalAxes, regex)
numBlocksEpoch = WaveExists(axes) ? DimSize(axes, ROWS) : 0

Expand Down Expand Up @@ -2429,7 +2429,7 @@ Function LayoutGraph(string win, STRUCT TiledGraphSettings &tgs)
for(i = 0; i < numBlocksHS; i += 1)
headstage = headstages[i]
// (?<! is a negative look behind assertion
regex = ".*(?<!EP_)DA_(?:[[:digit:]]{1,2})_HS_" + num2str(headstage)
sprintf regex, ".*(?<!%s_)DA_(?:[[:digit:]]{1,2})_HS_%d", DB_AXIS_PART_EPOCHS, headstage
WAVE/T/Z axes = GrepWave(allVerticalAxes, regex)

lastFreeAxis = last
Expand All @@ -2438,7 +2438,7 @@ Function LayoutGraph(string win, STRUCT TiledGraphSettings &tgs)
EnableAxis(graph, axes, spacePerSlot, first, last)
endif

regex = ".*EP_DA_(?:[[:digit:]]{1,2})_HS_" + num2str(headstage)
sprintf regex, ".*%s_DA_(?:[[:digit:]]{1,2})_HS_%d", DB_AXIS_PART_EPOCHS, headstage
WAVE/T/Z axes = GrepWave(allVerticalAxes, regex)

if(WaveExists(axes))
Expand All @@ -2462,10 +2462,17 @@ Function LayoutGraph(string win, STRUCT TiledGraphSettings &tgs)

// unassoc DA
for(i = 0; i < numBlocksUnassocDA; i += 1)
regex = ".*DA_" + num2str(unassocDA[i]) + "_HS_NaN"
sprintf regex, ".*(?<!%s)_DA_%d_HS_NaN", DB_AXIS_PART_EPOCHS, unassocDA[i]
WAVE/T/Z axes = GrepWave(allVerticalAxes, regex)
ASSERT(WaveExists(axes), "Unexpected number of matches")
EnableAxis(graph, axes, spacePerSlot, first, last)

sprintf regex, ".*%s_DA_%d_HS_NaN", DB_AXIS_PART_EPOCHS, unassocDA[i]
WAVE/T/Z axes = GrepWave(allVerticalAxes, regex)

if(WaveExists(axes))
EnableAxis(graph, axes, EPOCH_SLOT_MULTIPLIER * spacePerSlot, first, last)
endif
endfor

// unassoc AD
Expand All @@ -2476,9 +2483,6 @@ Function LayoutGraph(string win, STRUCT TiledGraphSettings &tgs)
EnableAxis(graph, axes, ADC_SLOT_MULTIPLIER * spacePerSlot, first, last)
endfor

// BSP_AddTracesForEpochs ignores unassociated DA channels
// so we don't have epoch axes here

// TTLs
for(i = 0; i < numBlocksTTL; i += 1)
regex = ttlsWithBits[i]
Expand Down
12 changes: 11 additions & 1 deletion Packages/MIES/MIES_SweepFormula_Helpers.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,17 @@ Function/WAVE SFH_GetSweepsForFormula(string graph, WAVE range, WAVE/Z selectDat
endif

if(WaveExists(epochNames))
DAChannel = SFH_GetDAChannel(graph, sweepNo, chanType, chanNr)
switch(chanType)
case XOP_CHANNEL_TYPE_ADC:
DAChannel = SFH_GetDAChannel(graph, sweepNo, chanType, chanNr)
SFH_ASSERT(!IsNaN(DAChannel), "No epochs for unassoc AD channel AD" + num2istr(chanNr))
break
case XOP_CHANNEL_TYPE_DAC:
DAChannel = chanNr
break
default:
ASSERT(0, "Unsupported channelType")
endswitch
WAVE/Z numericalValues = BSP_GetLogbookWave(graph, LBT_LABNOTEBOOK, LBN_NUMERICAL_VALUES, sweepNumber = sweepNo)
WAVE/Z textualValues = BSP_GetLogbookWave(graph, LBT_LABNOTEBOOK, LBN_TEXTUAL_VALUES, sweepNumber = sweepNo)
SFH_ASSERT(WaveExists(textualValues) && WaveExists(numericalValues), "LBN not found for sweep " + num2istr(sweepNo))
Expand Down
42 changes: 42 additions & 0 deletions Packages/tests/HardwareBasic/UTF_SweepFormulaHardware.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -770,3 +770,45 @@ static Function SF_InsertedTPVersusTP_REENTRY([str])
CHECK_EQUAL_WAVES(steadyStateInsertedHS1, steadyStateTPStorage_HS1, mode = WAVE_DATA, tol = 0.1)
CHECK_EQUAL_WAVES(instInsertedHS1, instTPStorage_HS1, mode = WAVE_DATA, tol = 0.1)
End

// UTF_TD_GENERATOR DeviceNameGeneratorMD1
static Function SF_UnassociatedDATTL_Epochs([str])
string str

STRUCT DAQSettings s
InitDAQSettingsFromString(s, "MD1_RA0_I0_L0_BKG1" + \
"__HS0_DA0_AD0_CM:VC:_ST:StimulusSetA_DA_0:" + \
"__HS1_DA1_AD1_CM:VC:_ST:StimulusSetC_DA_0:" + \
"__HS2_DA2_AD2_CM:VC:_ST:StimulusSetA_DA_0:_ASO0" + \
"__TTL1_ST:StimulusSetA_TTL_0:" + \
"__TTL3_ST:StimulusSetB_TTL_0:" + \
"__TTL5_ST:StimulusSetA_TTL_0:" + \
"__TTL7_ST:StimulusSetB_TTL_0:")

AcquireData_NG(s, str)
End

static Function SF_UnassociatedDATTL_Epochs_REENTRY([string str])

string graph, formula, bsPanel

graph = DB_OpenDataBrowser()
bsPanel = BSP_GetPanel(graph)
PGC_SetAndActivateControl(bsPanel, "check_BrowserSettings_DAC", val=1)

formula = "data(\"E0_PT_*\",select(channels(DA2),sweeps()))"
WAVE/WAVE data = SF_ExecuteFormula(formula, graph, useVariables=0)
CHECK_WAVE(data, WAVE_WAVE)
CHECK_EQUAL_VAR(DimSize(data, ROWS), 29)
WAVE epochData = data[0]
CHECK_WAVE(epochData, NUMERIC_WAVE)
CHECK_GT_VAR(DimSize(epochData, ROWS), 1)

formula = "epochs(\"E0_PT_*\",select(channels(DA2),sweeps()),name)"
WAVE/WAVE data = SF_ExecuteFormula(formula, graph, useVariables=0)
CHECK_WAVE(data, WAVE_WAVE)
CHECK_EQUAL_VAR(DimSize(data, ROWS), 29)
WAVE/T epochDataT = data[0]
CHECK_WAVE(epochDataT, TEXT_WAVE)
CHECK_EQUAL_STR(epochDataT[0], "E0_PT_P0_P")
End