Merge 2 waves

Hi,

I want to merge multiple 3D waves in a way, that the layers from the different waves are alternating. Thus giving MergeWave[][][0] = a[][][0], MergeWave[][]1] = b[][][0], MergeWave[][][2] = a[][][1], MergeWave[][]3] = b[][][1] and so on...
Currently I'm looping over all layers of MergeWave, but this scales rather badly with the size of the input waves. Is there a better way?

Function merge()
    Make /O /N=(500,500, 100) a = 0
    Make /O /N=(500, 500, 100) b = 1
   
    Make /O /N=(500, 500, 200) MergeWave
   
    Variable i, timerRefNum, microSeconds
   
    timerRefNum = startMSTimer
    for (i=0; i<50; i+=1)
        MergeWave[][][i*2] = a[x][y][i*2]
        MergeWave[][][i*2+1] = b[x][y][i*2+1]
    endfor
    microSeconds = stopMSTimer(timerRefNum)
    Print microSeconds/1000, "ms passed."
End
The key here is to use ImageTransform to set the planes. But while I was writing it up I figured I might multithread it as well. I merged my code with yours for easy comparison.

Function merge()
    Make /O /N=(500,500, 100) a = 0
    Make /O /N=(500, 500, 100) b = 1
   
    Make /O /N=(500, 500, 200) MergeWave, MergeWave_New
   
    Variable i, timerRefNum, microSeconds
   
    timerRefNum = startMSTimer
    for (i=0; i<50; i+=1)
        MergeWave[][][i*2] = a[x][y][i*2]
        MergeWave[][][i*2+1] = b[x][y][i*2+1]
    endfor
    microSeconds = stopMSTimer(timerRefNum) / 1e6
   
    variable myTime
   
    timerRefNum = startMSTimer
    Make /N=(DimSize(a, 2)) /FREE W_Dummy   // this is just a trick to use the MultiThread keyword
    MultiThread W_Dummy = MergePlane(a, b, MergeWave_New, p)
    myTime = StopMSTimer(timerRefNum) / 1e6
   
    Printf "Original: %g. Now: %g\r", microSeconds, myTime
End

ThreadSafe Function MergePlane(M_PlaneFromThisWave1, M_PlaneFromThisWave2, M_PlaneToThisWave, fromIndex)
    wave M_PlaneFromThisWave1, M_PlaneFromThisWave2, M_PlaneToThisWave
    variable fromIndex
   
    ImageTransform /P=(fromIndex) getPlane, M_PlaneFromThisWave1
    wave M_ImagePlane
    ImageTransform /D=M_ImagePlane /P=(2 * fromIndex) setPlane, M_PlaneToThisWave
   
    ImageTransform /P=(fromIndex) getPlane, M_PlaneFromThisWave2
    wave M_ImagePlane
    ImageTransform /D=M_ImagePlane /P=(2 * fromIndex + 1) setPlane, M_PlaneToThisWave
End


Result on my laptop:
Quote:
Original: 2.5658. Now: 0.0528195


About 50 times faster.
I decided to see how wave assignments compared:
Function test()

    Make /O /N=(500,500, 100) a = 0
    Make /O /N=(500, 500, 100) b = 1
 
    Make /O /N=(500, 500, 200) MergeWave

    Variable timerref
    timerref = StartMSTimer
    Multithread MergeWave[][][0,;2] = a[p][q][r/2]
    Multithread MergeWave[][][1,;2] = b[p][q][floor(r/2)]
    Variable microSeconds = stopMSTimer(timerref)
    Print microSeconds/1000, "ms passed."
end

On my 8-core Mac Pro:
959.949 ms passed.
Running 741's version:
Original: 3.95354. Now: 0.0563738

So ImageTransform wins, hands down.

Some comments on your code...
a[x][y][i*2]
On the right side of a wave assignment, square brackets refer to point numbers (rows, columns, etc.) but x and y refer to the *scaled* values from the left side. Your code works because you didn't set wave scaling on your waves, so the scaled and unscaled values are the same. The code will fail if you ever feed it a wave with scaling.

a[x][y][i*2]
b[x][y][i*2+1]

I think you want just [i] in both cases, and run the loop for 100 iterations:
        for (i=0; i<100; i+=1)

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com