Low memory experiments by dynamic save/reopen in unpacked experiments?
gsb
DimDelta
. I imagine that even if that's possible, it's not going to be implemented any time soon, so I wonder whether there is something I might be able to write myself. In that regard, I wonder whether there is a way to get a "wave hook"-like function called whenever a wave is about to be accessed or modified? (I could see that hook slowing down processing quite a bit, but nevertheless...) if so, I could 1) check the wave name against the list of waves I want to "load only when in use" 2) reload matches if necessary, perhaps killing and replacing a placeholder before the access/modify begins.
If that type of more general background-running solution isn't possible, I will of course revert to more manually saving waves to hard drive, killing them, and reloading them before I need them.
Do you have a problem that can't be solved by using Igor64?
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
May 2, 2018 at 01:04 pm - Permalink
You can implement something like the following yourself
// Load wave as ibw from disc
// convert to free wave
// return it
End
This function loads a wave from disc and converts it to a free wave. Always when you need that wave you use that function and after the wave assignment goes out of scope the memory is freed.
May 2, 2018 at 01:05 pm - Permalink
In the case that prompted me to write this, each original data file is 8Mb in an unpacked experiment. There are 4 of these per trial, 1-10 trials per experiment (4 on average), 20 experiment in an initial dataset and possible more to deal with down the road. The raw data from this dataset is therefore around 320 MB. The major problem is that I let my analysis get a bit out of hand (I am saving frequency-domain data out to a high nyquist frequency, and then saving differences of spectra and transformations), but I want to retain access to the raw data and the analysis results.
Here was the packed experiment size during analysis:
917 Mb before analysis
1.01 Gb after loading the raw data for one experiment (one set of trials)
1.53 Gb after analyzing that data
A few rounds of that and I am over the 32-bit limit. If I assume 600 Mb on average for the 20 experiments, I am nearing, though not at, the limit for Igor64 (which as I understand would be slightly less than the physical memory of my computer). Even then I could easily end up over the limit in the future.
That said, it is unfortunately far more convenient for me to work in 32-bit Igor, though I am always on a 64-bit computer, because I use an XOP that apparently will not be updated any time soon. I'm not particularly interesting in building my own workaround XOP. I will consider loading all the raw files and then reopening the Igor experiment file as 64-bit. Perhaps I might also be able to grab the files from an unpacked 32-bit experiment.
That's an interesting idea! Thanks!
I agree. Therefore, I would love to leave it to the experts (e.g., Wavemetrics)!
With solid state hard drives becoming the norm, I think it would be a really convenient addition to Igor. On the computer I am using right now,
display
ing one of those 8 Mb waves takes ~5-fold longer thansave
ing orloadwave
ing it. There are definitely some reasonable options for workarounds, but this addition would let Igor users forget about memory (if necessary) and worry about other problems.Thanks again for all the feedback!
May 2, 2018 at 02:10 pm - Permalink
I agree.
It would require changes to our source code such that every access to a wave's data check to see if the data is already in memory or be guaranteed that such as check was already done. Although this is conceptually feasible, actually doing it and maintaining it in a foolproof manner is, I suspect, beyond our abilities.
(Perhaps it could be done using memory-mapped files but I suspect that would be quite difficult to implement flawlessly.)
Perhaps you could change this to retain a reference (i.e., a path to a file or folder on disk) to the raw data. You would use the reference to load the raw data, using the LoadData operation, as needed. You would unload it when no longer needed.
May 2, 2018 at 03:09 pm - Permalink
For a moment I thought I could do so with the user-defined hook for BeforeDebuggerOpensHook. However, in most cases (well, the useful non-literal cases) I fail to recover the name of the global wave that I was trying to declare/use locally. If it's possible to get that detail in all/many such error cases, then the user could handle it. Here's what I mean:
Function displayExample(waveRef0,waveRef1)
String waveRef0,waveRef1
WAVE iDontExistAndYouKnowItHere
WAVE iMightNotButYouDontKnowMe=$waveRef0
display/k=1 $waveref1
End
static Function BeforeDebuggerOpensHook(pathToErrorFunction,isUserBreakpoint)
String pathToErrorFunction
Variable isUserBreakpoint
Variable rtErr= GetRTError(0)
String msg=GetErrMessage(rtErr,3) //could check for a wave name to recover in msg, then search some folder(s) for an ibw of the name
Print "msg:",msg
rtErr= GetRTError(1)
return 1
End
----EDIT: I should mention that this is what is returned when running that example--the identities of the literals can be recovered but not the globals (unless identical).
msg: WAVE; WAVE reference to "iDontExistAndYouKnowItHere" failed.
msg: WAVE; WAVE reference to "iMightNotButYouDontKnowMe" failed.
msg: Display; expected wave name
A related possible alternative would be a user-defined hook function that is called on
WAVE
declarations (or at least their errors) and passes the name of the global that was sought.This of course only handles the loading part, but the unloading part seems easier (e.g., user could just save and kill any large waves with a background function running every so often).
Yes, I agree, and that's probably what I will end up doing. My initial code was (demonstrably) not the greatest, and I was looking for ways to minimize re-writing / additions.
May 3, 2018 at 05:18 am - Permalink
String waveRef0,waveRef1
WAVE/Z iDontExistAndYouKnowItHere
if (!WaveExists(iDontExistAndYouKnowItHere))
WAVE iDontExistAndYouKnowItHere = Load_NonexistentWave(...)
endif
DoSomethingWithTheWave(iDontExistAndYouKnowItHere)
End
That function could be a GetPossiblyNonexistentWave() function that returns a wave reference to the now-loaded wave.
But it would be easier to use Igor64. What XOP is it that you need?
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
May 3, 2018 at 11:21 am - Permalink
Display $waveRef
instead of declaring them locally is probably going to add a little headache.The raw data files are Axon Instruments/Molecular Devices ABF files, and I use Bruxton's DataAccess XOP (https://www.bruxton.com/DataAccess/index.html). I have asked Bruxton about it, and at least at the time they did not have plans to add 64-bit compatibility. Adam Light once mentioned to me that it may in fact be a limitation of the tools provided by Molecular Devices for ABF files (along the lines discussed here).
As one potential workaround, I have wondered whether it might be possible to run one instance of 32-bit and one instance of 64-bit Igor side by side (as unpacked experiments if necessary) with some way of dynamically requesting that the 32 bit retrieve the waves and save them as ibws so the 64-bit instance can open them in that form. The 32-bit instance would be something of a slave/intermediary between the 64-bit instance and the XOP. Might there be an examples of packages that others have written that move files between two instances of Igor?
Thanks again for all the input. I agree. Hopefully it will be mostly as simple as a function like that (coupled with the previous suggestions of tracking where waves were stored to the hard drive), followed by some CTRL+F for WAVE. My habit of de-referencing global waves e.g.
May 3, 2018 at 12:33 pm - Permalink
For a low-tech approach that may work, choose File->Example Experiments->Programming->Watch Folder.
The master IGOR64 would write commands to a text file in a folder watched by the slave IGOR32. The slave would execute the commands and return results via another folder.
Or simpler yet, you could manually execute commands in IGOR32 and have IGOR64 watch for results. I would definitely start with this simpler approach.
I think in your scenario you might do better than that because of virtual memory. If the experiment contains a lot of data that you don't access after loading the experiment, then the physical memory for that data will be used for other data that you do access. That said, physical memory inexpensive and is a good investment when dealing with a lot of data.
May 3, 2018 at 12:58 pm - Permalink
The example Howard pointed out is a good place to start. Another approach that should work would be to use an ExecuteScriptText command from Igor64 to call the 32-bit Igor.exe with the /X flag. The command you would pass to the \X flag would be something like
[full path to Igor.exe] /X "ConvertABFToWave(\"C:\\Users\\me\\Documents\\data1.abf\")"
Getting the escaping of the quote marks and backslashes right might take some work.
You can use SpecialDirPath with the "Igor Application" selector to get the Igor installation directory. Then you'd append "\\IgorBinaries_Win32\\Igor.exe" to the end of that to get the full path to the 32-bit Igor executable.
ConvertABFToWave() would be a function defined in an Igor procedure file that's contained in your Igor Pro 7 User Files\Igor Procedures directory. Since the file would also be loaded by Igor64, you would want to conditionally compile that function based on the absence of the IGOR64 symbol. See
DisplayHelpTopic "Predefined Global Symbols"
for details on that.ConvertABFToWave would do the conversion from ABF to IFW and save the output file in the same directory as the source directory (or something else, if that works better for you). You have the option of using the /W flag with ExecuteScriptText on windows to force Igor to wait until the process returns, but that won't be of much use if you're calling Igor.exe, since it's a GUI program and ExecuteScriptText will return once Igor.exe starts processing messages. So you'll need to have a loop after the call to ExecuteScriptText that waits until the output file is written.
For an ExecuteScriptText example, see http://www.igorexchange.com/node/1243.
See also:
May 3, 2018 at 02:42 pm - Permalink
May 4, 2018 at 06:19 am - Permalink
For anyone else that hasn't done something like this before and might like to try, the approach I settled on was a windows command-line back and forth between 32-bit and 64-bit. I was surprised to find that it was possible to avoid background tasks because script-initiated commands conveniently appear to run in parallel with on-going execution.
One key to setting this up in a timely manner was giving up on nested strings in /x script commands from the windows command line. As predicted, it seemed like it would really take some work.
Here's the function that acted as intermediary between instances of Igor (not mac compatible):
strconstant ksExecutable64="IgorBinaries_x64\Igor64.exe"
function executeScriptIn32Or64(cmdStr,igorVers)
String cmdStr //command to execute in other instance of igor e.g., "funcB(7223)"
Variable igorVers //version of Igor to command
String windowsIgorPath = SpecialDirPath("Igor Application",0,1,0)
string execPath
switch (igorVers)
case 32:
execPath = "\""+ windowsIgorPath + ksExecutable32 +"\""
break
case 64:
execPath = "\""+ windowsIgorPath + ksExecutable64 +"\""
break
default:
return 0 //not a valid igor version
endswitch
String scriptText = execPath + " /x \"" + cmdStr + "\""
ExecuteScriptText scriptText
end
That would be great. For better or worse, at the moment I am stuck on other time-consuming edge case projects, such as wrapping up my dissertation research!
May 5, 2018 at 07:35 am - Permalink
Nice!
May 5, 2018 at 12:43 pm - Permalink