Concatenate produces null wave in procedure
Hello Everyone:
This should be simple but has me stumped. Inside a procedure, I create a text wave to hold names of different waves that will be concatenated from subfolders:
Make/FREE/T dataWaves = {"Re_data", "f_data", "f_calc"}
Variable numWaves = numpnts( dataWaves)
Later I check to see if one of these waves exists, if not I then cycle over the subfolders concatenating the contained waves:
if (!WaveExists(f_calc))
// - we must be at a top level datafolder (eg, Erken)
// need to cycle over subfolders & concatenate waves
Variable numDFs = CountObjects(":",4)
Variable n
for (n=0; n<numDFs; n+=1)
String expPath = GetIndexedObjName(":",4,n)
SetDataFolder expPath
for (i=0; i<numWaves; i+=1)
String destWavePath = "::" + dataWaves[i]
Concatenate/NP {$dataWaves[i]}, $destWavePath
endfor
SetDataFolder saveDF
endfor
endif
This works just as I intended. All 3 data waves (f_calc, f_data and Re_data) are present and correctly filled with data from the subfolders. But, when I try to use f_calc, it is null:
Variable f_min = min(WaveMin(f_calc), WaveMin(f_data))
It has something to do with f_calc being referenced before it is created via the concatenate operation. I know that I must be making a simple error but...
NOTE: this was run using Igor 8.04 on Mac OS 11.6.1
Thanks for the help,
Joe Kelly
Let us see all of the code.
I don't see where you are re-assigning WAVE f_calc anywhere.
November 30, 2021 at 12:28 pm - Permalink
Yes. Execute this for details:
DisplayHelpTopic "Put WAVE Declaration After Wave Is Created"
November 30, 2021 at 12:30 pm - Permalink
Thanks for looking at this. The entire function is pasted below. The reason that f_calc is declared before the concatenation is so that I can check for its existence. Sometimes (depending on how experiments are organized in subfolders) the concatenation has already been done.
Thanks again,
Joe
// - RunAll: performs pressure drop calculations for all of the tests in the current
// datafolder, including any tests within subfolders.
//
// Input Parameters:
// code : "PH" or "SAM"
// type : radial porosity treatment, either "Uniform", "White" or "Wall"
// model : "Ergun" or "KTA"
//
// Output waves "dP_L" and "f_mod" are created in the appropriate data folders
// with the code name and model appended (eg, dP_L_PH_Ergun).
//
// Graph of modified friction factor is created to show calculated values vs data.
// Friction factor values are calculated for a range of Reynolds numbers and then
// interpolated to experimental value of Re_mod.
//
// Provides statistical summary for code/model accuracy.
//
Function RunAll(code, type, model)
String code // either "PH" or "SAM"
String type // either "Uniform", "White" or "Wall"
String model // "Ergun" or "KTA"
String saveDF = GetDataFolder(1) // so we can return to current folder when finished
// list of waves to be concatenated for this experimenter (or condition).
Make/FREE/T dataWaves = {"Re_data", "f_data", "f_calc"}
Variable numWaves = numpnts( dataWaves)
Variable i
// kill any destination waves that exist, otherwise the concatenation process
// will simply add the waves to the end of the existing ones.
for (i=0; i<numWaves; i+=1)
KillWaves/Z $dataWaves[i]
endfor
// run SAM or Pronghorn for all tests in this folder hierarchy
doCalcs(saveDF, code, type, model)
// gather up the data and calculation results
getData(saveDF, type)
Wave f_calc
if (!WaveExists(f_calc))
// - we must be at a top level datafolder (eg, Erken)
// need to cycle over subfolders & concatenate waves
Variable numDFs = CountObjects(":",4)
Variable n
for (n=0; n<numDFs; n+=1)
String expPath = GetIndexedObjName(":",4,n)
SetDataFolder expPath
for (i=0; i<numWaves; i+=1)
String destWavePath = "::" + dataWaves[i]
Concatenate/NP {$dataWaves[i]}, $destWavePath
endfor
SetDataFolder saveDF
endfor
endif
// create graph for results of friction factor calcs:
Wave f_data
Variable f_min = min(WaveMin(f_calc), WaveMin(f_data))
Variable f_max = max(WaveMax(f_calc), WaveMax(f_data))
Make/O perf = {f_min,f_max} // provides data for perfect agreement line.
Display/W=(159,44,1193,667) perf vs perf
Label left "\\f01Calculated f\BM"
Label bottom "\\f01Measured f\BM"
ModifyGraph lblMargin(left)=25,lblMargin(bottom)=11
ModifyGraph standoff=0
ModifyGraph tick=2,mirror=1
ModifyGraph rgb=(0,0,0)
ModifyGraph lsize=1.5
ModifyGraph highTrip(left)=100000
ModifyGraph highTrip(bottom)=100000
String f_new = "f_" + code + "_" + type + "_" + model
Duplicate/O f_calc, $f_new
AppendToGraph $f_new vs f_data
ModifyGraph mode($f_new)=3
ModifyGraph marker($f_new)=2
ModifyGraph mrkThick($f_new)=0.75
// get error statistics
Duplicate/FREE f_data, f_err // tmp wave to hold relative error
f_err = (f_calc - f_data)/f_data
WaveStats/Q f_err // get statistics for error wave
String legendText = "\\f01\\JC Relative Error Statistics \r\\f00\\JL No. of data points: "
legendText += num2str(V_npnts) + " \r Avg. Error: " + num2str(V_avg) + " \r RMS Error: " + num2str(V_rms)
TextBox/C/N=textErr/A=RB legendText
String name
if (StringMatch(code, "PH"))
name = "Pronghorn"
elseif (StringMatch(code, "SAM"))
name = "SAM"
else
name = ""
endif
legendText = "\\f01 Code: " + name + " \r Drag Model: " + model + " "
TextBox/C/N=textCode/A=LT legendText
KillWaves f_calc
SetDataFolder saveDF
End
November 30, 2021 at 12:37 pm - Permalink
My quick read says that when f_calc does not exist, it is also never created. If f_calc is created within doCalcs or getData, you might do better to return it explicitly from these functions rather than having it "hidden". Or, since you kill it at the end of this top level function anyway, why not just create it as a FREE wave to start?
November 30, 2021 at 12:50 pm - Permalink
First, if you declare a wave reference to a wave that my not exist, always use WAVE/Z instead of just WAVE. The /Z prevents the debugger from kicking in on a null wave reference. For details on this, execute:
DisplayHelpTopic "Runtime Lookup Failure And The Debugger"
You can solve the problem by adding this after the "endif" part of the "if (!WaveExists(f_calc))" block:
WAVE f_data = $dataWaves[1]
WAVE f_calc = $dataWaves[2]
It is OK to redeclare a wave reference.
Here I did not use /Z because the waves are guaranteed to exist.
(Caveat: I don't understand what the Concatenate call is all about.)
November 30, 2021 at 01:03 pm - Permalink
THANKS!
I had forgotten (or never knew) that a wave reference can be redeclared. Although I have used Igor since 1991, I only use it intermittently and so it is always a relearning experience.
Thanks again for a great product and support,
Joe Kelly
PS - Thanks also to J. Weimer for looking at this.
November 30, 2021 at 01:12 pm - Permalink