Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
de827e8
UpgradeLabNotebook: Fix comment for setting column dimension labels
t-b Nov 18, 2025
b94ede5
UpgradeLabNotebook: Set the row dimension labels for the key waves
t-b Nov 18, 2025
12ddfc8
UpgradeLabNotebook: Set the wave version in the end
t-b Nov 18, 2025
a290383
UpgradeLabNotebook: Fix NOTE_INDEX calculation
t-b Nov 18, 2025
929af2a
LBN: Do labnotebook upgrade on most common MIES entry points
MichaelHuth Apr 2, 2025
8074d23
Conversion/MIES_MassExperimentProcessing.ipf: Fix it
t-b Nov 17, 2025
4bd2295
Compilation Test: Add MIES_MassExperimentProcessing.ipf
t-b Nov 19, 2025
8fe7550
Databrowser: Only upgrade the labnotebooks on locking
t-b Nov 18, 2025
312fa6b
MIES_MassExperimentProcessing.ipf: Adapt debug constants
t-b Nov 18, 2025
72151d6
GetLogbookSortedKeys: Add assertion
t-b Nov 19, 2025
507a663
Packages/IPNWB: Update it
t-b Nov 19, 2025
cab6820
UpgradeLabNotebook: Handle very early labnotebooks
t-b Nov 19, 2025
f0ea006
treewide: Avoid single letter function references
t-b Nov 19, 2025
a5bf092
GetAllDevices: Avoid RTE on bogus folder names
t-b Nov 19, 2025
271de75
DeviceHasUserComments: Prefer GetSetVariableString
t-b Nov 19, 2025
b7f32ad
MIES_MassExperimentProcessing.ipf: Factor NextFile out
t-b Nov 19, 2025
3086621
PerformMiesTasks: Create one NWB file per device
t-b Nov 19, 2025
1ea9c8d
PerformMiesTasks: Prefer NWB_VERSION_LATEST
t-b Nov 27, 2025
4479125
MIES_MassExperimentProcessing.ipf: Add function to create empty files
t-b Nov 19, 2025
dc24421
Labnotebook waves: Set the initial row dimension labels
t-b Nov 19, 2025
80ee79f
ProcessCurrentExperiment: Prefer CaptureHistoryStart/CaptureHistory
t-b Nov 26, 2025
02dba05
ProcessCurrentExperiment: Factor out json path creation
t-b Nov 26, 2025
59482fe
PerformMiesTasks: Enhance error handling
t-b Nov 27, 2025
70a306b
GetAllDevices: Upgrade folder path before using it
t-b Nov 27, 2025
2b7fd08
NWB_ExportAllData: Fix exporting data to multiple devices from old files
t-b Nov 19, 2025
8a73743
NWB_ExportAllData: Check that we have data for the requested device
t-b Nov 27, 2025
fda7a15
Packages/IPNWB: Update it
t-b Nov 27, 2025
7c44b0f
NWB_AppendSweepLowLevel: Add assertion if GetDAQDataSingleColumnWaveN…
t-b Nov 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 82 additions & 46 deletions Packages/Conversion/MIES_MassExperimentProcessing.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
/// - Ensure that only MIES is installed and no other Igor Pro packages
/// - In the MIES installation folder (All Users: `C:\Program Files\MIES`, User: `C:\Users\$User\Documents\MIES`)
/// create an empty file named `UserConfig.txt`.
/// - Execute CreateEmptyFiles() to create required empty files in `User Procedures`
///
/// Running:
/// - Start Igor Pro
Expand All @@ -30,8 +31,8 @@

#ifdef MEP_DEBUGGING

static StrConstant INPUT_FOLDER = "C:tim-data:pxp_examples_for_nwb_2:"
static StrConstant OUTPUT_FOLDER = "C:tim-data:output:"
static StrConstant INPUT_FOLDER = "E:tim-data:pxp_examples_for_nwb_2:"
static StrConstant OUTPUT_FOLDER = "E:tim-data:output:"

#else

Expand Down Expand Up @@ -85,8 +86,8 @@ End

static Function ProcessCurrentExperiment(STRUCT MultiExperimentProcessPrefs &prefs)

variable jsonID, index
string outputFilePath, inputFile, outputFolder
variable jsonID, index, ref, error
string outputFileTemplate, inputFile, outputFolder, history, path, message, file, regex

jsonID = GetJSON(prefs)

Expand All @@ -97,28 +98,44 @@ static Function ProcessCurrentExperiment(STRUCT MultiExperimentProcessPrefs &pre
PathInfo home
inputFile = S_path + GetExperimentName() + ".pxp"

outputFilePath = outputFolder + S_path + GetExperimentName() + ".nwb"
outputFileTemplate = outputFolder + S_path + GetExperimentName()

index = JSON_GetVariable(jsonID, "/index")
JSON_AddString(jsonID, "/log/" + num2str(index) + "/from", inputFile)
JSON_AddString(jsonID, "/log/" + num2str(index) + "/to", outputFilePath)
path = "/log/" + num2str(JSON_GetVariable(jsonID, "/index"))
JSON_AddString(jsonID, path + "/from", inputFile)
JSON_AddString(jsonID, path + "/to", outputFileTemplate)

DoWindow/K HistoryCarbonCopy
NewNotebook/V=0/F=0/N=HistoryCarbonCopy
ref = CaptureHistoryStart()

AssertOnAndClearRTError()
try
PerformMiesTasks(outputFilePath); AbortOnRTE
PerformMiesTasks(outputFileTemplate); AbortOnRTE
catch
ClearRTError()
print "Caught an RTE"
JSON_AddBoolean(jsonID, "/log/" + num2str(index) + "/error", 1)
message = GetRTErrMessage()
error = ClearRTError()

if(error >= 0)
printf "Encountered lingering RTE of %d (message: %s) after executing PerformMiesTasks.\r", error, message
else
printf "Encountered Abort with V_AbortCode: %d\r", V_AbortCode
endif

JSON_AddBoolean(jsonID, path + "/error", 1)
JSON_SetVariable(jsonID, "/errors", JSON_GetVariable(jsonID, "/errors") + 1)
HDF5CloseFile/A/Z 0
DeleteFile/Z outputFilePath

regex = "\\Q" + outputFileTemplate + "\\E" + ".*\.nwb$"
WAVE/Z/T files = GetAllFilesRecursivelyFromPath("home", regex = regex)

if(WaveExists(files))
for(file : files)
DeleteFile/Z file
endfor
endif
endtry

Notebook HistoryCarbonCopy, getData=1
JSON_AddString(jsonID, "/log/" + num2str(index) + "/output", trimstring(S_Value))
history = CaptureHistory(ref, 1)

JSON_AddString(jsonID, path + "/output", trimstring(history))

JSON_SetVariable(jsonID, "/processed", JSON_GetVariable(jsonID, "/processed") + 1)
else
Expand All @@ -130,28 +147,20 @@ static Function ProcessCurrentExperiment(STRUCT MultiExperimentProcessPrefs &pre
StoreJSON(prefs, jsonID)
End

static Function PerformMiesTasks(string outputFilePath)
static Function PerformMiesTasks(string outputFileTemplate)

string folder, message
variable nwbVersion, error
string folder

printf "Free Memory: %g GB\r", GetFreeMemory()

folder = GetFolder(outputFilePath)
folder = GetFolder(outputFileTemplate)

if(!FolderExists(folder))
CreateFolderOnDisk(folder)
endif

ClearRTError()

nwbVersion = 2
NWB_ExportAllData(nwbVersion, overrideFullFilePath = outputFilePath)
NWB_ExportAllData(NWB_VERSION_LATEST, overrideFileTemplate = outputFileTemplate)
HDF5CloseFile/A/Z 0

message = GetRTErrMessage()
error = GetRTError(1)
ASSERT(error == 0, "Encountered lingering RTE of " + num2str(error) + "(message: " + message + ") after executing NWB_ExportAllData.")
End

static Function IsAppropriateExperiment()
Expand Down Expand Up @@ -232,23 +241,32 @@ static Function AfterFileOpenHook(variable refNum, string file, string pathName,

ProcessCurrentExperiment(prefs)

// See if there are more experiments to process.
string nextExperimentFullPath = FindNextExperiment(prefs)
if(strlen(nextExperimentFullPath) == 0)
// Process is finished
prefs.processRunning = 0 // Flag process is finished.
Execute/P "NEWEXPERIMENT " // Post command to close this experiment.
print "Multi-experiment process is finished."
else
// Load the next experiment in the designated folder, if any.
PostLoadNextExperiment(nextExperimentFullPath) // Post operation queue commands to load next experiment
endif

SavePackagePrefs(prefs)
NextFile(prefs)

return 0 // Tell Igor to handle file in default fashion.
End

Function CreateEmptyFiles()

string file
string path = SpecialDirPath("Igor Pro User Files", 0, 0, 0) + "User Procedures:"

Make/T/FREE files = {"MIES_Include.ipf", \
"TJ_MIES_AnalysisBrowser.ipf", \
"TJ_MIES_Include.ipf", \
"UTF_HardwareHelperFunctions.ipf", \
"UTF_HardwareMain.ipf", \
"UserAnalysisFunctions.ipf", \
"tango_Panel.ipf", \
"tango_loader.ipf", \
"unit-testing.ipf", \
"UserConfig.txt"}

for(file : files)
SaveTextFile("", path + file)
endfor
End

// This function enables our special Igor hooks which skip saving the experiment
Function StartMultiExperimentProcess()

Expand All @@ -260,7 +278,7 @@ End
// Allow user to choose the folder containing the experiment files and start the process.
Function StartMultiExperimentProcessWrapper()

string message, settingsFile, inputFolder, outputFolder, files
string message, settingsFile, inputFolder, outputFolder
variable jsonID

STRUCT MultiExperimentProcessPrefs prefs
Expand Down Expand Up @@ -296,7 +314,7 @@ Function StartMultiExperimentProcessWrapper()
outputFolder = S_Path
ASSERT(V_flag, "Invalid path")

WAVE/Z files = GetAllFilesRecursivelyFromPath("MultiExperimentInputFolder", regex = "(?i)\.pxp$")
WAVE/Z/T files = GetAllFilesRecursivelyFromPath("MultiExperimentInputFolder", regex = "(?i)\.pxp$")

if(WaveExists(files))
Sort/A=2 files, files
Expand All @@ -312,10 +330,10 @@ Function StartMultiExperimentProcessWrapper()
JSON_AddVariable(jsonID, "/processed", 0)
JSON_AddVariable(jsonID, "/errors", 0)
JSON_AddVariable(jsonID, "/skipped", 0)
JSON_AddVariable(jsonID, "/total", DimSize(inputPXPs, ROWS))
JSON_AddVariable(jsonID, "/total", DimSize(files, ROWS))

JSON_AddTreeArray(jsonID, "/log")
JSON_AddObjects(jsonID, "/log", objCount = DimSize(inputPXPs, ROWS))
JSON_AddObjects(jsonID, "/log", objCount = DimSize(files, ROWS))

prefs.settingsFile = outputFolder + "conversion.json"
StoreJSON(prefs, jsonID)
Expand All @@ -331,6 +349,23 @@ Function StartMultiExperimentProcessWrapper()
return 0
End

Function NextFile(STRUCT MultiExperimentProcessPrefs &prefs)

// See if there are more experiments to process.
string nextExperimentFullPath = FindNextExperiment(prefs)
if(strlen(nextExperimentFullPath) == 0)
// Process is finished
prefs.processRunning = 0 // Flag process is finished.
Execute/P "NEWEXPERIMENT " // Post command to close this experiment.
print "Multi-experiment process is finished."
else
// Load the next experiment in the designated folder, if any.
PostLoadNextExperiment(nextExperimentFullPath) // Post operation queue commands to load next experiment
endif

SavePackagePrefs(prefs)
End

#ifdef MEP_DEBUGGING

Function TestMe()
Expand All @@ -339,6 +374,7 @@ Function TestMe()

LoadPackagePrefs(prefs)
ProcessCurrentExperiment(prefs)
NextFile(prefs)
End

#endif // MEP_DEBUGGING
2 changes: 1 addition & 1 deletion Packages/IPNWB
Submodule IPNWB updated 54 files
+3 −3 IPNWB_Constants.ipf
+3 −1 IPNWB_HDF5Helpers.ipf
+1 −1 IPNWB_NWBUtils.ipf
+5 −2 IPNWB_Structures.ipf
+2 −3 IPNWB_Utils.ipf
+17 −22 IPNWB_Writer.ipf
+14 −2 Readme.rst
+2 −2 conf.py
+1 −2 doc/nwb2.rst
+211 −58 doc/schema.diff
+1 −1 namespace/core/json/nwb.base.json
+1 −1 namespace/core/json/nwb.behavior.json
+1 −1 namespace/core/json/nwb.device.json
+1 −1 namespace/core/json/nwb.ecephys.json
+1 −1 namespace/core/json/nwb.epoch.json
+1 −1 namespace/core/json/nwb.file.json
+1 −1 namespace/core/json/nwb.icephys.json
+1 −1 namespace/core/json/nwb.image.json
+1 −1 namespace/core/json/nwb.misc.json
+1 −1 namespace/core/json/nwb.namespace.json
+1 −1 namespace/core/json/nwb.ogen.json
+1 −1 namespace/core/json/nwb.ophys.json
+1 −1 namespace/core/json/nwb.retinotopy.json
+88 −7 namespace/core/yaml/nwb.base.yaml
+18 −10 namespace/core/yaml/nwb.behavior.yaml
+48 −4 namespace/core/yaml/nwb.device.yaml
+98 −15 namespace/core/yaml/nwb.ecephys.yaml
+1 −14 namespace/core/yaml/nwb.epoch.yaml
+98 −68 namespace/core/yaml/nwb.file.yaml
+189 −6 namespace/core/yaml/nwb.icephys.yaml
+50 −13 namespace/core/yaml/nwb.image.yaml
+94 −37 namespace/core/yaml/nwb.misc.yaml
+62 −59 namespace/core/yaml/nwb.namespace.yaml
+9 −4 namespace/core/yaml/nwb.ogen.yaml
+53 −15 namespace/core/yaml/nwb.ophys.yaml
+3 −3 namespace/core/yaml/nwb.retinotopy.yaml
+1 −0 namespace/hdmf-common/json/base.json
+1 −0 namespace/hdmf-common/json/experimental.json
+1 −1 namespace/hdmf-common/json/namespace.json
+1 −0 namespace/hdmf-common/json/resources.json
+1 −1 namespace/hdmf-common/json/sparse.json
+1 −1 namespace/hdmf-common/json/table.json
+21 −0 namespace/hdmf-common/yaml/base.yaml
+13 −0 namespace/hdmf-common/yaml/experimental.yaml
+51 −20 namespace/hdmf-common/yaml/namespace.yaml
+105 −0 namespace/hdmf-common/yaml/resources.yaml
+19 −8 namespace/hdmf-common/yaml/sparse.yaml
+53 −40 namespace/hdmf-common/yaml/table.yaml
+10 −11 namespace/ndx-mies/yaml/namespace.yaml
+9 −0 requirements.in
+179 −0 requirements.txt
+1 −1 specifications
+8 −5 tools/run-ipt.sh
+4 −17 update_specifications.sh
24 changes: 12 additions & 12 deletions Packages/MIES/MIES_AnalysisFunctionHelpers.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -469,19 +469,19 @@ End
/// parameters, possibly including the type, as specified by the function
/// `$func_GetParams`
///
/// @param func Analysis function `V3` which must be valid and existing
/// @param mode Bit mask values from @ref GetListOfParamsModeFlags
Function/S AFH_GetListOfAnalysisParams(string func, variable mode)
/// @param funcname Analysis function `V3` which must be valid and existing
/// @param mode Bit mask values from @ref GetListOfParamsModeFlags
Function/S AFH_GetListOfAnalysisParams(string funcname, variable mode)

string params, re

FUNCREF AFP_PARAM_GETTER_V3 f = $(func + "_GetParams")
FUNCREF AFP_PARAM_GETTER_V3 func = $(funcname + "_GetParams")

if(!FuncRefIsAssigned(FuncRefInfo(f))) // no such getter functions
if(!FuncRefIsAssigned(FuncRefInfo(func))) // no such getter functions
return ""
endif

params = f()
params = func()

ASSERT(strsearch(params, ";", 0) == -1, "Entries must be separated with ,")

Expand All @@ -501,19 +501,19 @@ End

/// @brief Get help string from optional `$func_GetHelp`
///
/// @param func Analysis function `V3`
/// @param name Parameter name
Function/S AFH_GetHelpForAnalysisParameter(string func, string name)
/// @param funcname Analysis function `V3`
/// @param name Parameter name
Function/S AFH_GetHelpForAnalysisParameter(string funcname, string name)

FUNCREF AFP_PARAM_HELP_GETTER_V3 f = $(func + "_GetHelp")
FUNCREF AFP_PARAM_HELP_GETTER_V3 func = $(funcname + "_GetHelp")

if(!FuncRefIsAssigned(FuncRefInfo(f)))
if(!FuncRefIsAssigned(FuncRefInfo(func)))
return ""
endif

AssertOnAndClearRTError()
try
return f(name); AbortOnRTE
return func(name); AbortOnRTE
catch
ClearRTError()
// ignoring errors here
Expand Down
8 changes: 4 additions & 4 deletions Packages/MIES/MIES_Async.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ threadsafe static Function/DF ASYNC_Run_Worker(DFREF dfr)
DFREF dfrOut, dfrTemp

SVAR WFunc = dfr:$ASYNC_WORKERFUNC_STR
FUNCREF ASYNC_Worker f = $WFunc
FUNCREF ASYNC_Worker func = $WFunc

DFREF dfrInp = dfr:input
DFREF dfrAsync = dfr:async
Expand All @@ -139,7 +139,7 @@ threadsafe static Function/DF ASYNC_Run_Worker(DFREF dfr)
dfrOut = $""
AssertOnAndClearRTError()
try
dfrOut = f(dfrInp); AbortOnRTE
dfrOut = func(dfrInp); AbortOnRTE
catch
rtErrMsg = GetRTErrMessage()
rtErr = ClearRTError()
Expand Down Expand Up @@ -243,7 +243,7 @@ Function ASYNC_ThreadReadOut()
track[%$workloadClass][%OUTPUTCOUNT] += 1

SVAR RFunc = dfr:$ASYNC_READOUTFUNC_STR
FUNCREF ASYNC_ReadOut f = $RFunc
FUNCREF ASYNC_ReadOut func = $RFunc
NVAR rtErr = dfr:$ASYNC_RTERROR_STR
SVAR rtErrMsg = dfr:$ASYNC_RTERRORMSG_STR
NVAR abortCode = dfr:$ASYNC_ABORTCODE_STR
Expand All @@ -256,7 +256,7 @@ Function ASYNC_ThreadReadOut()
statCnt += 1
AssertOnAndClearRTError()
try
f(ar); AbortOnRTE
func(ar); AbortOnRTE
catch
msg = GetRTErrMessage()
ASSERT(!ClearRTError(), "ReadOut function " + RFunc + " encountered an RTE: " + msg)
Expand Down
2 changes: 1 addition & 1 deletion Packages/MIES/MIES_Constants.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Constant SWEEP_EPOCH_VERSION = 9
/// - New/Changed layers of entries
///
///@{
Constant LABNOTEBOOK_VERSION = 81
Constant LABNOTEBOOK_VERSION = 82
Constant RESULTS_VERSION = 3
///@}

Expand Down
6 changes: 1 addition & 5 deletions Packages/MIES/MIES_DAEphys.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -4601,11 +4601,7 @@ Function DAP_LockDevice(string win)
headstage = GetSliderPositionIndex(deviceLocked, "slider_DataAcq_ActiveHeadstage")
P_SaveUserSelectedHeadstage(deviceLocked, headstage)

// upgrade all four labnotebook waves in wanna-be atomic way
GetLBNumericalKeys(deviceLocked)
GetLBNumericalValues(deviceLocked)
GetLBTextualKeys(deviceLocked)
GetLBTextualValues(deviceLocked)
UpgradeLabNotebook(deviceLocked)

NVAR sessionStartTime = $GetSessionStartTime()
sessionStartTime = DateTimeInUTC()
Expand Down
6 changes: 2 additions & 4 deletions Packages/MIES/MIES_DataBrowser.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@ static Function/S DB_LockToDevice(string win, string device)
for(i = first; i <= last; i += 1)
SplitAndUpgradeSweepGlobal(device, i)
endfor

UpgradeLabNotebook(device)
endif

UpdateSweepPlot(win)
Expand Down Expand Up @@ -421,10 +423,6 @@ Function DB_UpdateSweepPlot(string win)
return NaN
endif

// fetch keys waves to trigger a potential labnotebook upgrade
WAVE numericalKeys = DB_GetLBNWave(win, LBN_NUMERICAL_KEYS)
WAVE textualKeys = DB_GetLBNWave(win, LBN_TEXTUAL_KEYS)

WAVE numericalValues = DB_GetLBNWave(win, LBN_NUMERICAL_VALUES)
WAVE textualValues = DB_GetLBNWave(win, LBN_TEXTUAL_VALUES)

Expand Down
Loading
Loading