source: sans/Dev/trunk/NCNR_User_Procedures/Reduction/SANS/ProDiv.ipf @ 570

Last change on this file since 570 was 570, checked in by srkline, 13 years ago

Change (1):
In preparation for release, updated pragma IgorVersion?=6.1 in all procedures

Change (2):
As a side benefit of requiring 6.1, we can use the MultiThread? keyword to thread any model function we like. The speed benefit is only noticeable on functions that require at least one integration and at least 100 points (resolution smearing is NOT threaded, too many threadSafe issues, too little benefit). I have chosen to use the MultiThread? only on the XOP assignment. In the Igor code there are too many functions that are not explicitly declared threadsafe, making for a mess.

File size: 18.1 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=5.0
3#pragma IgorVersion=6.1
4
5
6//********************
7// Vers. 1.2 092101
8//
9// Procedures to create a "DIV" file for use as a detector sensitivity file
10// Follows the same procedure as PRODIV on the VAX
11// -requires two "full" reduced runs from plexiglass or water
12// -prompts the user for the locations of the offset and no-offset files
13// and for the range of data to replace
14// - then writes of the "div" file and fake-VAX format, which is rather ugly
15// since the DIV file is floating point...
16//
17//
18// 08 AUG 03
19// allowed for creation of DIV files on 8m SANS with two beamstops
20//
21// JAN2006 - not modified! still hard-wired to take a 128x128 detector image
22//
23//*********************
24
25//writes an VAX-style WORK file, "exactly" as it would be output from the VAX
26//except for the "dummy" header and the record markers - the record marker bytes are
27// in the files - they are just written as zeros and are meaningless
28//file is:
29//      516 bytes header
30// 128x128=16384 (x4) bytes of data
31// + 2 byte record markers interspersed just for fun
32// = 66116 bytes
33//prompts for name of the output file.
34//
35Function WriteVAXWorkFile(type)
36        String type
37       
38        Wave data=$("root:Packages:NIST:"+type+":data")
39       
40        Variable refnum,ii=0,hdrBytes=516,a,b,offset
41        String fullpath=""
42       
43        Duplicate/O data,tempData
44        Redimension/S/N=(128*128) tempData
45        tempData *= 4
46       
47        PathInfo/S catPathName
48        fullPath = DoSaveFileDialog("Save data as")       //won't actually open the file
49        If(cmpstr(fullPath,"")==0)
50                //user cancel, don't write out a file
51          Close/A
52          Abort "no data file was written"
53        Endif
54       
55        Make/B/O/N=(hdrBytes) hdrWave
56        hdrWave=0
57        FakeDIVHeader(hdrWave)
58       
59        Make/Y=2/O/N=(510) bw510                //Y=2 specifies 32 bit (=4 byte) floating point
60        Make/Y=2/O/N=(511) bw511
61        Make/Y=2/O/N=(48) bw48
62
63        Make/O/B/N=2 recWave            //two bytes
64
65        //actually open the file
66        Open/C="????"/T="TEXT" refNum as fullpath
67        FSetPos refNum, 0
68        //write header bytes (to be skipped when reading the file later)
69       
70        FBinWrite /F=1 refnum,hdrWave
71       
72        ii=0
73        a=0
74        do
75                //write 511 4-byte values (little-endian order), 4* true value
76                bw511[] = tempData[p+a]
77                FBinWrite /B=3/F=4 refnum,bw511
78                a+=511
79                //write a 2-byte record marker
80                FBinWrite refnum,recWave
81               
82                //write 510 4-byte values (little-endian) 4* true value
83                bw510[] = tempData[p+a]
84                FBinWrite /B=3/F=4 refnum,bw510
85                a+=510
86               
87                //write a 2-byte record marker
88                FBinWrite refnum,recWave
89               
90                ii+=1   
91        while(ii<16)
92        //write out last 48  4-byte values (little-endian) 4* true value
93        bw48[] = tempData[p+a]
94        FBinWrite /B=3/F=4 refnum,bw48
95        //close the file
96        Close refnum
97       
98        //go back through and make it look like a VAX datafile
99        Make/W/U/O/N=(511*2) int511             // /W=16 bit signed integers /U=unsigned
100        Make/W/U/O/N=(510*2) int510
101        Make/W/U/O/N=(48*2) int48
102       
103        //skip the header for now
104        Open/A/T="????TEXT" refnum as fullPath
105        FSetPos refnum,0
106       
107        offset=hdrBytes
108        ii=0
109        do
110                //511*2 integers
111                FSetPos refnum,offset
112                FBinRead/B=2/F=2 refnum,int511
113                Swap16BWave(int511)
114                FSetPos refnum,offset
115                FBinWrite/B=2/F=2 refnum,int511
116               
117                //skip 511 4-byte FP = (511*2)*2 2byte int  + 2 bytes record marker
118                offset += 511*2*2 + 2
119               
120                //510*2 integers
121                FSetPos refnum,offset
122                FBinRead/B=2/F=2 refnum,int510
123                Swap16BWave(int510)
124                FSetPos refnum,offset
125                FBinWrite/B=2/F=2 refnum,int510
126               
127                //
128                offset += 510*2*2 + 2
129               
130                ii+=1
131        while(ii<16)
132        //48*2 integers
133        FSetPos refnum,offset
134        FBinRead/B=2/F=2 refnum,int48
135        Swap16BWave(int48)
136        FSetPos refnum,offset
137        FBinWrite/B=2/F=2 refnum,int48
138
139        //move to EOF and close
140        FStatus refnum
141        FSetPos refnum,V_logEOF
142       
143        Close refnum
144       
145        Killwaves/Z hdrWave,bw48,bw511,bw510,recWave,temp16,int511,int510,int48
146End
147
148// given a 16 bit integer wave, read in as 2-byte pairs of 32-bit FP data
149// swap the order of the 2-byte pairs
150//
151Function Swap16BWave(w)
152        Wave w
153
154        Duplicate/O w,temp16
155        //Variable num=numpnts(w),ii=0
156
157        //elegant way to swap even/odd values, using wave assignments
158        w[0,*;2] = temp16[p+1]
159        w[1,*;2] = temp16[p-1]
160
161//crude way, using a loop       
162//      for(ii=0;ii<num;ii+=2)
163//              w[ii] = temp16[ii+1]
164//              w[ii+1] = temp16[ii]
165//      endfor
166       
167        return(0)       
168End
169
170// writes a fake label into the header of the DIV file
171//
172Function FakeDIVHeader(hdrWave)
173        WAVE hdrWave
174       
175        //put some fake text into the sample label position (60 characters=60 bytes)
176        String day=date(),tim=time(),lbl=""
177        Variable start=98,num,ii
178       
179        lbl = "Sensitivity (DIV) created "+day +" "+tim
180        num=strlen(lbl)
181        for(ii=0;ii<num;ii+=1)
182                hdrWave[start+ii] = char2num(lbl[ii])
183        endfor
184
185        return(0)
186End
187
188//works on the data in "type" folder
189//sums all of the data, and normalizes by the number of cells (=128*128)
190// calling procedure must make sure that the folder is on linear scale FIRST
191Function NormalizeDIV(type)
192        String type
193       
194        WAVE data=$("root:Packages:NIST:"+type+":data")
195        Variable totCts=sum(data,Inf,-Inf)              //sum all of the data
196       
197        data /= totCts
198        data *= 128*128
199       
200        return(0)
201End
202
203// prompts the user for the location of the "COR" -level data
204// data can be copied to any data folder (except DIV) for use here...
205//
206// then there is a "pause for user" to allow the user to select the "box"
207// in the ON-AXIS datset that is to be replaced by the data in the off-axis data
208//
209// corrections are done...
210//
211// finally, the DIV file is written to disk
212Function MakeDIVFile(ctrType,offType)
213        String ctrType,offType
214       
215        Prompt ctrType,"On-Center Plex data (corrected)",popup,"STO;SUB;BGD;COR;CAL;SAM;EMP;"
216        Prompt offType,"Offset Plex data (corrected)",popup,"STO;SUB;BGD;COR;CAL;SAM;EMP;"
217        DoPrompt "Pick the data types",ctrType,offType
218        //"COR" data in both places - reduction must be done ahead of time
219       
220        //temporarily set data display to linear
221        NVAR gLog = root:myGlobals:gLogScalingAsDefault
222        Variable oldState = gLog
223        gLog=0  //linear
224       
225        if(V_Flag==1)
226                //user cancelled
227                return(1)
228        endif
229       
230        //show the ctrType
231        //get the xy range to replace
232        Execute "ChangeDisplay(\""+ctrType+"\")"
233       
234        NewPanel/K=2/W=(139,341,382,432) as "Get XY Range"
235        DoWindow/C tmp_GetXY
236        AutoPositionWindow/E/M=1/R=SANS_Data
237        DrawText 15,20,"Find the (X1,X2) and (Y1,Y2) range to"
238        DrawText 15,40,"replace and press continue"
239        Button button0, pos={80,58},size={92,20},title="Continue"
240        Button button0,proc=XYContinueButtonProc
241       
242        PauseForUser tmp_GetXY,SANS_Data
243       
244        //replace the center section of the "on" data with the center of the "off" data
245        Variable x1,x2,y1,y2
246        GetXYRange(x1,x2,y1,y2)
247        Printf "X=(%d,%d)  Y=(%d,%d)\r", x1,x2,y1,y2
248        ReplaceDataBlock(ctrType,offType,x1,x2,y1,y2)
249       
250        DoAlert 1,"Is this NG1 data with a second beamstop?"
251        if(V_flag==1)
252                GetXYRange(x1,x2,y1,y2)
253                Printf "X=(%d,%d)  Y=(%d,%d)\r", x1,x2,y1,y2
254                ReplaceDataBlock(ctrType,offType,x1,x2,y1,y2)
255        endif
256       
257        //normalize the new data (and show it)
258        NormalizeDiv(ctrtype)
259        UpdateDisplayInformation(ctrtype)
260        //write out the new data file
261        WriteVAXWorkFile(ctrtype)
262        gLog = oldState         //set log/lin pref back to user - set preference
263        Return(0)
264End
265
266//ctrData is changed -- offData is not touched
267//simple replacement of the selected data...
268//
269Function ReplaceDataBlock(ctrType,offType,x1,x2,y1,y2)
270        String ctrType,offType
271        Variable x1,x2,y1,y2
272       
273        //do it crudely, with nested for loops
274        WAVE ctrData=$("root:Packages:NIST:"+ctrtype+":data")
275        WAVE offData=$("root:Packages:NIST:"+offtype+":data")
276        Variable ii,jj
277       
278        for(ii=x1;ii<=x2;ii+=1)
279                for(jj=y1;jj<=y2;jj+=1)
280                        ctrData[ii][jj] = offData[ii][jj]
281                endfor
282        endfor
283       
284        return(0)
285End
286
287//continue button waiting for the user to pick the range, and continue the execution
288//
289Function XYContinueButtonProc(ctrlName)
290        String ctrlName
291       
292        DoWindow/K tmp_GetXY
293End
294
295// prompts the user to enter the XY range for the box replacement
296// user can get these numbers by printing out marquee coordinates to the command window
297//
298Function GetXYRange(x1,x2,y1,y2)
299        Variable &x1,&x2,&y1,&y2
300       
301        Variable x1p,x2p,y1p,y2p
302        Prompt x1p,"X1"
303        Prompt x2p,"X2"
304        Prompt y1p,"Y1"
305        Prompt y2p,"Y2"
306        DoPrompt "Enter the range to replace",x1p,x2p,y1p,y2p
307        x1=x1p
308        x2=x2p
309        y1=y1p
310        y2=y2p
311       
312//      Print x1,x2,y1,y2
313        Return(0)
314End
315
316
317/////////////////////
318//
319// for the DIV "protocol" panel, I probably need to have parts of the protocol panel initialized...
320// folders are generated at the startup initialization, before protocol panel
321//
322Proc BuildDIVPanel()
323        DoWindow/F DIV_Panel
324        if(V_flag==0)
325                InitDIVPanel()
326                DIV_Panel()
327        Endif
328End
329
330//initialization procedure for the protocol panel
331//note that :gAbsStr is also shared (common global) to that used in
332//the questionnare form of the protcol (see protocol.ipf)
333//
334//0901, uses 8 points in protocol wave
335Proc InitDIVPanel()
336
337        //set up the global variables needed for the protocol panel
338        //global strings to put in a temporary protocol textwave
339        Variable ii=0,nsteps=8
340        String waveStr="DIV_Protocol"
341        SetDataFolder root:myGlobals:Protocols
342        Make/O/T/N=(nsteps) $"root:myGlobals:Protocols:DIV_Protocol" = ""
343       
344        DIV_protocol[2] = "none"
345        DIV_protocol[3] = "none"
346        DIV_protocol[4] = "none"
347        DIV_protocol[5] = "AVTYPE=none;"
348        DIV_protocol[6] = "DRK=none,DRKMODE=0,"
349       
350
351        String/G root:myGlobals:Protocols:gPlex="Plex"
352        String/G root:myGlobals:Protocols:gPlexBgd="Bgd"
353        String/G root:myGlobals:Protocols:gPlexEmp="Emp"
354        String/G root:myGlobals:Protocols:gPlex_off="Plex offset"
355        String/G root:myGlobals:Protocols:gPlexBgd_off="Bgd offset"
356        String/G root:myGlobals:Protocols:gPlexEmp_off="Emp offset"
357        String/G root:myGlobals:Protocols:gPlexName="Plex_date.div"
358       
359        Variable/G root:myGlobals:Protocols:gPlexX1=45
360        Variable/G root:myGlobals:Protocols:gPlexX2=87
361        Variable/G root:myGlobals:Protocols:gPlexY1=43
362        Variable/G root:myGlobals:Protocols:gPlexY2=85
363        Variable/G root:myGlobals:Protocols:gPlexTrans=0.48
364       
365        SetDataFolder root:
366       
367End
368
369// load in one on-center file and show the box
370//
371Function ShowBoxButtonProc(ba) : ButtonControl
372        STRUCT WMButtonAction &ba
373
374        switch( ba.eventCode )
375                case 2: // mouse up
376                        // click code here
377                        if(cmpstr(ba.ctrlName, "ShowBox") == 0)
378                       
379                                //parse for the first run number
380                                SVAR gPlex = root:myGlobals:Protocols:gPlex
381                                String item,fname
382                               
383                                item = StringFromList(0, gPlex ,",")
384                                fname = FindFileFromRunNumber(str2num(item))
385                                if(strlen(fname) == 0)
386                                        Abort "Bad file number in Plex field"
387                                endif
388                                // load the file
389                                ReadHeaderAndData(fname)        //this is the full Path+file
390                                UpdateDisplayInformation("RAW")
391                                //draw a box of the specified size. This is persistent on the display as you scroll to the offset data
392                                NVAR x1 = root:myGlobals:Protocols:gPlexX1
393                                NVAR x2 = root:myGlobals:Protocols:gPlexX2
394                                NVAR y1 = root:myGlobals:Protocols:gPlexY1
395                                NVAR y2 = root:myGlobals:Protocols:gPlexY2
396                               
397                                SetDrawLayer/W=SANS_Data/K UserFront                    //set the layer, and clear it
398                                SetDrawEnv/W=SANS_Data xcoord=bottom,ycoord=left,fillpat=0,linethick=3,linefgc=(65535, 65535, 65535)
399                                DrawRect/W=SANS_Data x1, y2, x2, y1
400                               
401                                Button $ba.ctrlName,title="Clear Box",rename=HideBox,win=DIV_Panel
402                               
403                        else
404                                if(winType("SANS_Data")==1)
405                                        SetDrawLayer/W=SANS_Data/K UserFront                    //set the layer, and clear it
406                                        Button $ba.ctrlName,title="Show Box",rename=ShowBox,win=DIV_Panel
407                                else
408                                        Button $ba.ctrlName,title="Show Box",rename=ShowBox,win=DIV_Panel
409                                endif
410                        endif   
411                       
412                        break
413        endswitch
414
415        return 0
416End
417
418// do everything...
419//
420Function GenerateDIVButtonProc(ba) : ButtonControl
421        STRUCT WMButtonAction &ba
422
423        switch( ba.eventCode )
424                case 2: // mouse up
425                        // click code here
426                       
427                        //temporarily set data display to linear
428                        NVAR gLog = root:myGlobals:gLogScalingAsDefault
429                        Variable oldState = gLog
430                        gLog=0  //linear
431                       
432                       
433                        SVAR gPlex = root:myGlobals:Protocols:gPlex
434                        SVAR gPlexBgd = root:myGlobals:Protocols:gPlexBgd
435                        SVAR gPlexEmp = root:myGlobals:Protocols:gPlexEmp
436                        SVAR gPlex_off = root:myGlobals:Protocols:gPlex_off
437                        SVAR gPlexBgd_off = root:myGlobals:Protocols:gPlexBgd_off
438                        SVAR gPlexEmp_off = root:myGlobals:Protocols:gPlexEmp_off
439                        SVAR gPlexName = root:myGlobals:Protocols:gPlexName
440                       
441                        NVAR X1 = root:myGlobals:Protocols:gPlexX1
442                        NVAR X2 = root:myGlobals:Protocols:gPlexX2
443                        NVAR Y1 = root:myGlobals:Protocols:gPlexY1
444                        NVAR Y2 = root:myGlobals:Protocols:gPlexY2
445                        NVAR gPlexTrans = root:myGlobals:Protocols:gPlexTrans
446                       
447                        WAVE/T proto = $"root:myGlobals:Protocols:DIV_Protocol"
448                       
449                        String item,fname,str
450                        Variable ii,num
451                // reduce the on-center
452                        //patch trans
453                        num = ItemsInList(gPlex, ",")
454                        for(ii=0;ii<num;ii+=1)
455                                item = StringFromList(ii, gPlex ,",")
456                                fname = FindFileFromRunNumber(str2num(item))
457                                if(strlen(fname) == 0)
458                                        Abort "Bad file number in no offset Plex field"
459                                endif
460                                WriteTransmissionToHeader(fname,gPlexTrans)
461                        endfor
462                       
463                        //go through the protocol
464                        str = ParseRunNumberList(gPlexBgd)
465                        if(strlen(str) > 0)
466                                proto[0] = str
467                        else
468                                Abort "Bad file number in no offset Bgd"
469                        endif
470                        str = ParseRunNumberList(gPlexEmp)
471                        if(strlen(str) > 0)
472                                proto[1] = str
473                        else
474                                Abort "Bad file number in no offset Emp"
475                        endif
476                        str = ParseRunNumberList(gPlex)
477                        if(strlen(str) > 0)
478                                ExecuteProtocol("root:myGlobals:Protocols:DIV_Protocol",str)
479                        else
480                                Abort "Bad file number in no offset Plex"
481                        endif
482                        // move it into STO
483                        Execute "CopyWorkFolder(\"COR\",\"STO\")"
484                       
485                       
486                       
487                // reduce the off-center, keep in STO
488                        //patch trans
489                        num = ItemsInList(gPlex_off, ",")
490                        for(ii=0;ii<num;ii+=1)
491                                item = StringFromList(ii, gPlex_off ,",")
492                                fname = FindFileFromRunNumber(str2num(item))
493                                if(strlen(fname) == 0)
494                                        Abort "Bad file number in Plex field"
495                                endif
496                                WriteTransmissionToHeader(fname,gPlexTrans)
497                        endfor
498                       
499                        //go through the protocol
500                        str = ParseRunNumberList(gPlexBgd_off)
501                        if(strlen(str) > 0)
502                                proto[0] = str
503                        else
504                                Abort "Bad file number in offset Bgd"
505                        endif
506                        str = ParseRunNumberList(gPlexEmp_off)
507                        if(strlen(str) > 0)
508                                proto[1] = str
509                        else
510                                Abort "Bad file number in offset Emp"
511                        endif
512                        str = ParseRunNumberList(gPlex_off)
513                        if(strlen(str) > 0)
514                                ExecuteProtocol("root:myGlobals:Protocols:DIV_Protocol",str)
515                        else
516                                Abort "Bad file number in offset Emp"
517                        endif
518                        ConvertFolderToLinearScale("COR")
519                       
520                       
521                // replace the patch
522                // on-center data is changed (STO)
523                        ReplaceDataBlock("STO","COR",x1,x2,y1,y2)
524                // normalize
525                        NormalizeDiv("STO")
526                        UpdateDisplayInformation("STO")
527                //write out the new data file
528                        WriteVAXWorkFile("STO")
529                               
530                        gLog=oldState           //revert display preference to old state       
531                        break
532        endswitch
533
534        return 0
535End
536
537// if a dark color is used, then
538//¥SetVariable setvar0 labelBack=(65535,65535,65535)
539// for each variable will give a white background to the label text
540Window DIV_Panel() : Panel
541        PauseUpdate; Silent 1           // building window...
542        NewPanel /W=(594,44,932,570)/K=1 as "DIV_Panel"
543//      ModifyPanel cbRGB=(35867,28177,65535)           //purple
544//      ModifyPanel cbRGB=(1,16019,65535)                               //electric blue
545        ModifyPanel cbRGB=(36631,59604,33902)           //spring green
546        SetDrawLayer UserBack
547        DrawRect 71,324,145,391
548        TitleBox title0,pos={14,16},size={50,20},title="No Offset"
549        TitleBox title0_1,pos={17,125},size={35,20},title="Offset"
550        SetVariable setvar0,pos={15,46},size={250,15},title="PLEX",value= root:myGlobals:Protocols:gPlex
551        SetVariable setvar0_1,pos={16,69},size={250,15},title="EMP",value= root:myGlobals:Protocols:gPlexEmp
552        SetVariable setvar0_2,pos={14,92},size={250,15},title="BGD",value= root:myGlobals:Protocols:gPlexBgd
553        SetVariable setvar1,pos={17,158},size={250,15},title="PLEX",value= root:myGlobals:Protocols:gPlex_off
554        SetVariable setvar001,pos={18,181},size={250,15},title="EMP",value= root:myGlobals:Protocols:gPlexEmp_off
555        SetVariable setvar002,pos={16,204},size={250,15},title="BGD",value= root:myGlobals:Protocols:gPlexBgd_off
556        SetVariable setvar002_1,pos={14,251},size={150,15},title="Transmission"
557        SetVariable setvar002_1,limits={0,1,0.01},value= root:myGlobals:Protocols:gPlexTrans
558//      SetVariable setvar003,pos={16,441},size={250,15},title="DIV FILE NAME"
559//      SetVariable setvar003,value= root:myGlobals:Protocols:gPlexName
560        Button ShowBox,pos={226,325},size={90,20},proc=ShowBoxButtonProc,title="Show Box"
561        Button button1,pos={25,441},size={150,20},proc=GenerateDIVButtonProc,title="Generate DIV File"
562        Button button2,pos={25,481},size={150,20},proc=ReloadDIVButtonProc,title="Load DIV File"
563        Button button4,pos={240,481},size={80,20},proc=DoneDIVButtonProc,title="Done"
564        Button button3,pos={240,10},size={50,20},proc=DIVHelpButtonProc,title="Help"
565        SetVariable setvar00201,pos={84,297},size={50,15},limits={0,128,1},title=" ",value= root:myGlobals:Protocols:gPlexY2
566        SetVariable setvar00202,pos={15,350},size={50,15},limits={0,128,1},title=" ",value= root:myGlobals:Protocols:gPlexX1
567        SetVariable setvar00203,pos={85,399},size={50,15},limits={0,128,1},title=" ",value= root:myGlobals:Protocols:gPlexY1
568        SetVariable setvar00204,pos={156,348},size={50,15},limits={0,128,1},title=" ",value= root:myGlobals:Protocols:gPlexX2
569EndMacro
570
571
572// done
573//
574Function DoneDIVButtonProc(ba) : ButtonControl
575        STRUCT WMButtonAction &ba
576
577        switch( ba.eventCode )
578                case 2: // mouse up
579                        // click code here
580                        DoWindow/K DIV_Panel
581                        break
582        endswitch
583
584        return 0
585End
586
587// load in a DIV file, print out the stats, display in SANS_Data
588//
589Function ReloadDIVButtonProc(ba) : ButtonControl
590        STRUCT WMButtonAction &ba
591
592        switch( ba.eventCode )
593                case 2: // mouse up
594                        // click code here
595                        Execute "ReadWork_DIV()"
596                        WaveStats root:Packages:NIST:DIV:data
597                        Print "*"                       
598//                      Execute "ChangeDisplay(\"DIV\")"       
599                        break
600        endswitch
601
602        return 0
603End
604
605//
606Function DIVHelpButtonProc(ba) : ButtonControl
607        STRUCT WMButtonAction &ba
608
609        switch( ba.eventCode )
610                case 2: // mouse up
611                        // click code here
612                        DisplayHelpTopic/Z/K=1 "SANS Data Reduction Tutorial[Detector Sensitivity File]"
613                        if(V_flag !=0)
614                                DoAlert 0,"The SANS Data Reduction Tutorial Help file could not be found"
615                        endif
616                        break
617        endswitch
618
619        return 0
620End
Note: See TracBrowser for help on using the repository browser.