source: sans/Dev/trunk/NCNR_User_Procedures/Reduction/SANS/NCNR_Utils.ipf @ 911

Last change on this file since 911 was 911, checked in by srkline, 10 years ago

Updated the NGB attenuator tables with Katie's new measurements from May 2013.

Made some changes to Auto-Fit to make it more useable. Will turn it "on" when documentation is finished.

Changed how the random deviate function is calculated to improve the estimates of multiple scattering. Now the q-range of integration is shifted to lower q for the USANS calculation (using very large objects). Also, the number of points used in the integration is chosen adaptively until a constant value of scattering cross section is obtained. There are still some functions where the integration fails (power laws). These will always fail. My best solution currently is to flag the times when the XS>100. Then the estimates are invalid. The 1D simulation is fine, the 2D is reasonably fine, but anything to do with multile scattering is incorrect.

File size: 70.1 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=5.0
3#pragma IgorVersion=6.1
4
5// this file contains globals and functions that are specific to a
6// particular facility or data file format
7// branched out 29MAR07 - SRK
8//
9// functions are either labeled with the procedure file that calls them,
10// or noted that they are local to this file
11
12
13// initializes globals that are specific to a particular facility
14// - number of XY pixels
15// - pixexl resolution [cm]
16// - detector deadtime constant [s]
17//
18// called by Initialize.ipf
19//
20Function InitFacilityGlobals()
21
22        //Detector -specific globals
23        Variable/G root:myGlobals:gNPixelsX=128
24        Variable/G root:myGlobals:gNPixelsY=128
25       
26        // as of Jan2008, detector pixel sizes are read directly from the file header, so they MUST
27        // be set correctly in instr.cfg - these values are not used, but declared to avoid errors
28        Variable/G root:myGlobals:PixelResNG3_ILL = 1.0         //pixel resolution in cm
29        Variable/G root:myGlobals:PixelResNG5_ILL = 1.0
30        Variable/G root:myGlobals:PixelResNG7_ILL = 1.0
31        Variable/G root:myGlobals:PixelResNG3_ORNL = 0.5
32        Variable/G root:myGlobals:PixelResNG5_ORNL = 0.5
33        Variable/G root:myGlobals:PixelResNG7_ORNL = 0.5
34        Variable/G root:myGlobals:PixelResNGB_ORNL = 0.5
35//      Variable/G root:myGlobals:PixelResCGB_ORNL = 0.5                // fiction
36
37        Variable/G root:myGlobals:PixelResDefault = 0.5
38       
39        Variable/G root:myGlobals:DeadtimeNG3_ILL = 3.0e-6              //deadtime in seconds
40        Variable/G root:myGlobals:DeadtimeNG5_ILL = 3.0e-6
41        Variable/G root:myGlobals:DeadtimeNG7_ILL = 3.0e-6
42        Variable/G root:myGlobals:DeadtimeNGB_ILL = 4.0e-6              // fictional
43        Variable/G root:myGlobals:DeadtimeNG3_ORNL_VAX = 3.4e-6         //pre - 23-JUL-2009 used VAX
44        Variable/G root:myGlobals:DeadtimeNG3_ORNL_ICE = 1.5e-6         //post - 23-JUL-2009 used ICE
45        Variable/G root:myGlobals:DeadtimeNG5_ORNL = 0.6e-6                     //as of 9 MAY 2002
46        Variable/G root:myGlobals:DeadtimeNG7_ORNL_VAX = 3.4e-6         //pre 25-FEB-2010 used VAX
47        Variable/G root:myGlobals:DeadtimeNG7_ORNL_ICE = 2.3e-6         //post 25-FEB-2010 used ICE
48        Variable/G root:myGlobals:DeadtimeNGB_ORNL_ICE = 4.0e-6         //per JGB 16-JAN-2013, best value we have for the oscillating data
49
50//      Variable/G root:myGlobals:DeadtimeCGB_ORNL_ICE = 1.5e-6         // fiction
51
52        Variable/G root:myGlobals:DeadtimeDefault = 3.4e-6
53
54        //new 11APR07
55        Variable/G root:myGlobals:BeamstopXTol = -8                     // (cm) is BS Xpos is -5 cm or less, it's a trans measurement
56        // sample aperture offset is NOT stored in the VAX header, but it should be
57        // - when it is, remove the global and write an accessor AND make a place for
58        // it in the RealsRead
59        Variable/G root:myGlobals:apOff = 5.0                           // (cm) distance from sample aperture to sample position
60
61End
62
63
64//**********************
65// Resolution calculation - used by the averaging routines
66// to calculate the resolution function at each q-value
67// - the return value is not used
68//
69// equivalent to John's routine on the VAX Q_SIGMA_AVE.FOR
70// Incorporates eqn. 3-15 from J. Appl. Cryst. (1995) v. 28 p105-114
71//
72// - 21 MAR 07 uses projected BS diameter on the detector
73// - APR 07 still need to add resolution with lenses. currently there is no flag in the
74//          raw data header to indicate the presence of lenses.
75//
76// - Aug 07 - added input to switch calculation based on lenses (==1 if in)
77//
78// - called by CircSectAvg.ipf and RectAnnulAvg.ipf
79//
80// passed values are read from RealsRead
81// except DDet and apOff, which are set from globals before passing
82//
83//
84Function/S getResolution(inQ,lambda,lambdaWidth,DDet,apOff,S1,S2,L1,L2,BS,del_r,usingLenses,SigmaQ,QBar,fSubS)
85        Variable inQ, lambda, lambdaWidth, DDet, apOff, S1, S2, L1, L2, BS, del_r,usingLenses
86        Variable &fSubS, &QBar, &SigmaQ         //these are the output quantities at the input Q value
87       
88        //lots of calculation variables
89        Variable a2, q_small, lp, v_lambda, v_b, v_d, vz, yg, v_g
90        Variable r0, delta, inc_gamma, fr, fv, rmd, v_r1, rm, v_r
91
92        //Constants
93        Variable vz_1 = 3.956e5         //velocity [cm/s] of 1 A neutron
94        Variable g = 981.0                              //gravity acceleration [cm/s^2]
95
96        String results
97        results ="Failure"
98
99        S1 *= 0.5*0.1                   //convert to radius and [cm]
100        S2 *= 0.5*0.1
101
102        L1 *= 100.0                     // [cm]
103        L1 -= apOff                             //correct the distance
104
105        L2 *= 100.0
106        L2 += apOff
107        del_r *= 0.1                            //width of annulus, convert mm to [cm]
108       
109        BS *= 0.5*0.1                   //nominal BS diameter passed in, convert to radius and [cm]
110        // 21 MAR 07 SRK - use the projected BS diameter, based on a point sample aperture
111        Variable LB
112        LB = 20.1 + 1.61*BS                     //distance in cm from beamstop to anode plane (empirical)
113        BS = bs + bs*lb/(l2-lb)         //adjusted diameter of shadow from parallax
114       
115        //Start resolution calculation
116        a2 = S1*L2/L1 + S2*(L1+L2)/L1
117        q_small = 2.0*Pi*(BS-a2)*(1.0-lambdaWidth)/(lambda*L2)
118        lp = 1.0/( 1.0/L1 + 1.0/L2)
119
120        v_lambda = lambdaWidth^2/6.0
121       
122//      if(usingLenses==1)                      //SRK 2007
123        if(usingLenses != 0)                    //SRK 2008 allows for the possibility of different numbers of lenses in header
124                v_b = 0.25*(S1*L2/L1)^2 +0.25*(2/3)*(lambdaWidth/lambda)^2*(S2*L2/lp)^2         //correction to 2nd term
125        else
126                v_b = 0.25*(S1*L2/L1)^2 +0.25*(S2*L2/lp)^2              //original form
127        endif
128       
129        v_d = (DDet/2.3548)^2 + del_r^2/12.0
130        vz = vz_1 / lambda
131        yg = 0.5*g*L2*(L1+L2)/vz^2
132        v_g = 2.0*(2.0*yg^2*v_lambda)                                   //factor of 2 correction, B. Hammouda, 2007
133
134        r0 = L2*tan(2.0*asin(lambda*inQ/(4.0*Pi) ))
135        delta = 0.5*(BS - r0)^2/v_d
136
137        if (r0 < BS)
138                inc_gamma=exp(gammln(1.5))*(1-gammp(1.5,delta))
139        else
140                inc_gamma=exp(gammln(1.5))*(1+gammp(1.5,delta))
141        endif
142
143        fSubS = 0.5*(1.0+erf( (r0-BS)/sqrt(2.0*v_d) ) )
144        if (fSubS <= 0.0)
145                fSubS = 1.e-10
146        endif
147        fr = 1.0 + sqrt(v_d)*exp(-1.0*delta) /(r0*fSubS*sqrt(2.0*Pi))
148        fv = inc_gamma/(fSubS*sqrt(Pi)) - r0^2*(fr-1.0)^2/v_d
149
150        rmd = fr*r0
151        v_r1 = v_b + fv*v_d +v_g
152
153        rm = rmd + 0.5*v_r1/rmd
154        v_r = v_r1 - 0.5*(v_r1/rmd)^2
155        if (v_r < 0.0)
156                v_r = 0.0
157        endif
158        QBar = (4.0*Pi/lambda)*sin(0.5*atan(rm/L2))
159        SigmaQ = QBar*sqrt(v_r/rmd^2 +v_lambda)
160
161
162// more readable method for calculating the variance in Q
163// EXCEPT - this is calculated for Qo, NOT qBar
164// (otherwise, they are nearly equivalent, except for close to the beam stop)
165//      Variable kap,a_val,a_val_l2,m_h
166//      g = 981.0                               //gravity acceleration [cm/s^2]
167//      m_h     = 252.8                 // m/h [=] s/cm^2
168//     
169//      kap = 2*pi/lambda
170//      a_val = L2*(L1+L2)*g/2*(m_h)^2
171//      a_val_L2 = a_val/L2*1e-16               //convert 1/cm^2 to 1/A^2
172//
173//      sigmaQ = 0
174//      sigmaQ = 3*(S1/L1)^2
175//     
176//      if(usingLenses != 0)
177//              sigmaQ += 2*(S2/lp)^2*(lambdaWidth)^2   //2nd term w/ lenses
178//      else   
179//              sigmaQ += 2*(S2/lp)^2                                           //2nd term w/ no lenses
180//      endif
181//     
182//      sigmaQ += (del_r/L2)^2
183//      sigmaQ += 2*(r0/L2)^2*(lambdaWidth)^2
184//      sigmaQ += 4*(a_val_l2)^2*lambda^4*(lambdaWidth)^2
185//     
186//      sigmaQ *= kap^2/12
187//      sigmaQ = sqrt(sigmaQ)
188
189
190        results = "success"
191        Return results
192End
193
194
195//
196//**********************
197// 2D resolution function calculation - ***NOT*** in terms of X and Y
198// but written in terms of Parallel and perpendicular to the Q vector at each point
199//
200// -- it is more naturally written this way since the 2D function is an ellipse with its major
201// axis pointing in the direction of Q_parallel. Hence there is no way to properly define the
202// elliptical gaussian in terms of sigmaX and sigmaY
203//
204// For a full description of the gravity effect on the resolution, see:
205//
206//      "The effect of gravity on the resolution of small-angle neutron diffraction peaks"
207//      D.F.R Mildner, J.G. Barker & S.R. Kline J. Appl. Cryst. (2011). 44, 1127-1129.
208//      [ doi:10.1107/S0021889811033322 ]
209//
210//              2/17/12 SRK
211//              NOTE: the first 2/3 of this code is the 1D code, copied here just to have the beam stop
212//                              calculation here, if I decide to implement it. The real calculation is all at the
213//                              bottom and is quite compact
214//
215//
216//
217//
218// - 21 MAR 07 uses projected BS diameter on the detector
219// - APR 07 still need to add resolution with lenses. currently there is no flag in the
220//          raw data header to indicate the presence of lenses.
221//
222// - Aug 07 - added input to switch calculation based on lenses (==1 if in)
223//
224// passed values are read from RealsRead
225// except DDet and apOff, which are set from globals before passing
226//
227// phi is the azimuthal angle, CCW from +x axis
228// r_dist is the real-space distance from ctr of detector to QxQy pixel location
229//
230// MAR 2011 - removed the del_r terms, they don't apply since no bining is done to the 2D data
231//
232Function/S get2DResolution(inQ,phi,lambda,lambdaWidth,DDet,apOff,S1,S2,L1,L2,BS,del_r,usingLenses,r_dist,SigmaQX,SigmaQY,fSubS)
233        Variable inQ, phi,lambda, lambdaWidth, DDet, apOff, S1, S2, L1, L2, BS, del_r,usingLenses,r_dist
234        Variable &SigmaQX,&SigmaQY,&fSubS               //these are the output quantities at the input Q value
235       
236        //lots of calculation variables
237        Variable a2, lp, v_lambda, v_b, v_d, vz, yg, v_g
238        Variable r0, delta, inc_gamma, fr, fv, rmd, v_r1, rm, v_r
239
240        //Constants
241        Variable vz_1 = 3.956e5         //velocity [cm/s] of 1 A neutron
242        Variable g = 981.0                              //gravity acceleration [cm/s^2]
243        Variable m_h    = 252.8                 // m/h [=] s/cm^2
244
245        String results
246        results ="Failure"
247
248        S1 *= 0.5*0.1                   //convert to radius and [cm]
249        S2 *= 0.5*0.1
250
251        L1 *= 100.0                     // [cm]
252        L1 -= apOff                             //correct the distance
253
254        L2 *= 100.0
255        L2 += apOff
256        del_r *= 0.1                            //width of annulus, convert mm to [cm]
257       
258        BS *= 0.5*0.1                   //nominal BS diameter passed in, convert to radius and [cm]
259        // 21 MAR 07 SRK - use the projected BS diameter, based on a point sample aperture
260        Variable LB
261        LB = 20.1 + 1.61*BS                     //distance in cm from beamstop to anode plane (empirical)
262        BS = bs + bs*lb/(l2-lb)         //adjusted diameter of shadow from parallax
263       
264        //Start resolution calculation
265        a2 = S1*L2/L1 + S2*(L1+L2)/L1
266        lp = 1.0/( 1.0/L1 + 1.0/L2)
267
268        v_lambda = lambdaWidth^2/6.0
269       
270//      if(usingLenses==1)                      //SRK 2007
271        if(usingLenses != 0)                    //SRK 2008 allows for the possibility of different numbers of lenses in header
272                v_b = 0.25*(S1*L2/L1)^2 +0.25*(2/3)*(lambdaWidth/lambda)^2*(S2*L2/lp)^2         //correction to 2nd term
273        else
274                v_b = 0.25*(S1*L2/L1)^2 +0.25*(S2*L2/lp)^2              //original form
275        endif
276       
277        v_d = (DDet/2.3548)^2 + del_r^2/12.0
278        vz = vz_1 / lambda
279        yg = 0.5*g*L2*(L1+L2)/vz^2
280        v_g = 2.0*(2.0*yg^2*v_lambda)                                   //factor of 2 correction, B. Hammouda, 2007
281
282        r0 = L2*tan(2.0*asin(lambda*inQ/(4.0*Pi) ))
283        delta = 0.5*(BS - r0)^2/v_d
284
285        if (r0 < BS)
286                inc_gamma=exp(gammln(1.5))*(1-gammp(1.5,delta))
287        else
288                inc_gamma=exp(gammln(1.5))*(1+gammp(1.5,delta))
289        endif
290
291        fSubS = 0.5*(1.0+erf( (r0-BS)/sqrt(2.0*v_d) ) )
292        if (fSubS <= 0.0)
293                fSubS = 1.e-10
294        endif
295//      fr = 1.0 + sqrt(v_d)*exp(-1.0*delta) /(r0*fSubS*sqrt(2.0*Pi))
296//      fv = inc_gamma/(fSubS*sqrt(Pi)) - r0^2*(fr-1.0)^2/v_d
297//
298//      rmd = fr*r0
299//      v_r1 = v_b + fv*v_d +v_g
300//
301//      rm = rmd + 0.5*v_r1/rmd
302//      v_r = v_r1 - 0.5*(v_r1/rmd)^2
303//      if (v_r < 0.0)
304//              v_r = 0.0
305//      endif
306
307        Variable kap,a_val,a_val_L2,proj_DDet
308       
309        kap = 2*pi/lambda
310        a_val = L2*(L1+L2)*g/2*(m_h)^2
311        a_val_L2 = a_val/L2*1e-16               //convert 1/cm^2 to 1/A^2
312
313
314        // the detector pixel is square, so correct for phi
315        proj_DDet = DDet*cos(phi) + DDet*sin(phi)
316
317
318///////// OLD - don't use ---
319//in terms of Q_parallel ("x") and Q_perp ("y") - this works, since parallel is in the direction of Q and I
320// can calculate that from the QxQy (I just need the projection)
321//// for test case with no gravity, set a_val = 0
322//// note that gravity has no wavelength dependence. the lambda^4 cancels out.
323////
324////    a_val = 0
325////    a_val_l2 = 0
326//
327//     
328//      // this is really sigma_Q_parallel
329//      SigmaQX = kap*kap/12 * (3*(S1/L1)^2 + 3*(S2/LP)^2 + (proj_DDet/L2)^2 + (sin(phi))^2*8*(a_val_L2)^2*lambda^4*lambdaWidth^2)
330//      SigmaQX += inQ*inQ*v_lambda
331//
332//      //this is really sigma_Q_perpendicular
333//      proj_DDet = DDet*sin(phi) + DDet*cos(phi)               //not necessary, since DDet is the same in both X and Y directions
334//
335//      SigmaQY = kap*kap/12 * (3*(S1/L1)^2 + 3*(S2/LP)^2 + (proj_DDet/L2)^2 + (cos(phi))^2*8*(a_val_L2)^2*lambda^4*lambdaWidth^2)
336//     
337//      SigmaQX = sqrt(SigmaQX)
338//      SigmaQy = sqrt(SigmaQY)
339//     
340
341/////////////////////////////////////////////////
342/////   
343//      ////// this is all new, inclusion of gravity effect into the parallel component
344//       perpendicular component is purely geometric, no gravity component
345//
346// the shadow factor is calculated as above -so keep the above calculations, even though
347// most of them are redundant.
348//
349       
350////    //
351        Variable yg_d,acc,sdd,ssd,lambda0,DL_L,sig_l
352        Variable var_qlx,var_qly,var_ql,qx,qy,sig_perp,sig_para, sig_para_new
353       
354        G = 981.  //!   ACCELERATION OF GRAVITY, CM/SEC^2
355        acc = vz_1              //      3.956E5 //!     CONVERT WAVELENGTH TO VELOCITY CM/SEC
356        SDD = L2                //1317
357        SSD = L1                //1627          //cm
358        lambda0 = lambda                //              15
359        DL_L = lambdaWidth              //0.236
360        SIG_L = DL_L/sqrt(6)
361        YG_d = -0.5*G*SDD*(SSD+SDD)*(LAMBDA0/acc)^2
362/////   Print "DISTANCE BEAM FALLS DUE TO GRAVITY (CM) = ",YG
363//              Print "Gravity q* = ",-2*pi/lambda0*2*yg_d/sdd
364       
365        sig_perp = kap*kap/12 * (3*(S1/L1)^2 + 3*(S2/LP)^2 + (proj_DDet/L2)^2)
366        sig_perp = sqrt(sig_perp)
367       
368       
369        FindQxQy(inQ,phi,qx,qy)
370
371// missing a factor of 2 here, and the form is different than the paper, so re-write   
372//      VAR_QLY = SIG_L^2 * (QY+4*PI*YG_d/(2*SDD*LAMBDA0))^2
373//      VAR_QLX = (SIG_L*QX)^2
374//      VAR_QL = VAR_QLY + VAR_QLX  //! WAVELENGTH CONTRIBUTION TO VARIANCE
375//      sig_para = (sig_perp^2 + VAR_QL)^0.5
376       
377        // r_dist is passed in, [=]cm
378        // from the paper
379        a_val = 0.5*G*SDD*(SSD+SDD)*m_h^2 * 1e-16               //units now are cm /(A^2)
380       
381        var_QL = 1/6*(kap/SDD)^2*(DL_L)^2*(r_dist^2 - 4*r_dist*a_val*lambda0^2*sin(phi) + 4*a_val^2*lambda0^4)
382        sig_para_new = (sig_perp^2 + VAR_QL)^0.5
383       
384       
385///// return values PBR
386        SigmaQX = sig_para_new
387        SigmaQy = sig_perp
388       
389////   
390       
391        results = "success"
392        Return results
393End
394
395
396
397
398//Utility function that returns the detector resolution (in cm)
399//Global values are set in the Initialize procedure
400//
401//
402// - called by CircSectAvg.ipf, RectAnnulAvg.ipf, and ProtocolAsPanel.ipf
403//
404// fileStr is passed as TextRead[3]
405// detStr is passed as TextRead[9]
406//
407// *** as of Jan 2008, depricated. Now detector pixel sizes are read from the file header
408// rw[10] = x size (mm); rw[13] = y size (mm)
409//
410Function xDetectorPixelResolution(fileStr,detStr)
411        String fileStr,detStr
412       
413        Variable DDet
414        String instr=fileStr[1,3]       //filestr is "[NGnSANSn] " or "[NGnSANSnn]" (11 characters total)
415       
416        NVAR PixelResNG3_ILL = root:myGlobals:PixelResNG3_ILL           //pixel resolution in cm
417        NVAR PixelResNG5_ILL = root:myGlobals:PixelResNG5_ILL
418        NVAR PixelResNG7_ILL = root:myGlobals:PixelResNG7_ILL
419        NVAR PixelResNGB_ILL = root:myGlobals:PixelResNGB_ILL
420        NVAR PixelResNG3_ORNL = root:myGlobals:PixelResNG3_ORNL
421        NVAR PixelResNG5_ORNL = root:myGlobals:PixelResNG5_ORNL
422        NVAR PixelResNG7_ORNL = root:myGlobals:PixelResNG7_ORNL
423        NVAR PixelResNGB_ORNL = root:myGlobals:PixelResNGB_ORNL
424//      NVAR PixelResCGB_ORNL = root:myGlobals:PixelResCGB_ORNL
425        NVAR PixelResDefault = root:myGlobals:PixelResDefault
426       
427        strswitch(instr)
428                case "CGB":
429                case "NG3":
430                        if(cmpstr(detStr, "ILL   ") == 0 )
431                                DDet= PixelResNG3_ILL
432                        else
433                                DDet = PixelResNG3_ORNL //detector is ordella-type
434                        endif
435                        break
436                case "NG5":
437                        if(cmpstr(detStr, "ILL   ") == 0 )
438                                DDet= PixelResNG5_ILL
439                        else
440                                DDet = PixelResNG5_ORNL //detector is ordella-type
441                        endif
442                        break
443                case "NG7":
444                        if(cmpstr(detStr, "ILL   ") == 0 )
445                                DDet= PixelResNG7_ILL
446                        else
447                                DDet = PixelResNG7_ORNL //detector is ordella-type
448                        endif
449                        break
450                case "NGA":
451                case "NGB":
452                        if(cmpstr(detStr, "ILL   ") == 0 )
453                                DDet= PixelResNGB_ILL
454                        else
455                                DDet = PixelResNGB_ORNL //detector is ordella-type
456                        endif
457                        break
458                default:                                                       
459                        //return error?
460                        DoAlert 0, "No matching instrument xDetectorPixelResolution-- Using default resolution"
461                        DDet = PixelResDefault  //0.5 cm, typical for new ORNL detectors
462        endswitch
463       
464        return(DDet)
465End
466
467//Utility function that returns the detector deadtime (in seconds)
468//Global values are set in the Initialize procedure
469//
470// - called by WorkFileUtils.ipf
471//
472// fileStr is passed as TextRead[3]
473// detStr is passed as TextRead[9]
474// dateAndTimeStr is passed as TextRead[1]
475//      --- if no date/time string is passed, ICE values are the default
476//
477// Due to the switch from VAX -> ICE, there were some hardware changes that led to
478// a change in the effective detector dead time. The dead time was re-measured by J. Barker
479// as follows:
480//      Instrument                              Date measured                           deadtime constant
481//      NG3                                                     DECEMBER 2009                           1.5 microseconds
482//      NG7                                                     APRIL2010                                       2.3 microseconds
483//      NGB                                                     JAN 2013                                        4 microseconds
484//
485//
486// The day of the switch to ICE on NG7 was 25-FEB-2010 (per J. Krzywon)
487// The day of the switch to ICE on NG3 was 23-JUL-2009 (per C. Gagnon)
488//
489// so any data after these dates is to use the new dead time constant. The switch is made on the
490// data collection date.
491//
492//
493Function DetectorDeadtime(fileStr,detStr,[dateAndTimeStr])
494        String fileStr,detStr,dateAndTimeStr
495       
496        Variable deadtime
497        String instr=fileStr[1,3]       //filestr is "[NGnSANSn] " or "[NGnSANSnn]" (11 characters total)
498       
499        NVAR DeadtimeNG3_ILL = root:myGlobals:DeadtimeNG3_ILL           //pixel resolution in cm
500        NVAR DeadtimeNG5_ILL = root:myGlobals:DeadtimeNG5_ILL
501        NVAR DeadtimeNG7_ILL = root:myGlobals:DeadtimeNG7_ILL
502        NVAR DeadtimeNGB_ILL = root:myGlobals:DeadtimeNGB_ILL
503        NVAR DeadtimeNG3_ORNL_VAX = root:myGlobals:DeadtimeNG3_ORNL_VAX
504        NVAR DeadtimeNG3_ORNL_ICE = root:myGlobals:DeadtimeNG3_ORNL_ICE
505//      NVAR DeadtimeCGB_ORNL_ICE = root:myGlobals:DeadtimeCGB_ORNL_ICE
506        NVAR DeadtimeNG5_ORNL = root:myGlobals:DeadtimeNG5_ORNL
507        NVAR DeadtimeNG7_ORNL_VAX = root:myGlobals:DeadtimeNG7_ORNL_VAX
508        NVAR DeadtimeNG7_ORNL_ICE = root:myGlobals:DeadtimeNG7_ORNL_ICE
509        NVAR DeadtimeNGB_ORNL_ICE = root:myGlobals:DeadtimeNGB_ORNL_ICE
510        NVAR DeadtimeDefault = root:myGlobals:DeadtimeDefault
511       
512        // if no date string is passed, default to the ICE values
513        if(strlen(dateAndTimeStr)==0)
514                dateAndTimeStr = "01-JAN-2011"          //dummy date to force to ICE values
515        endif
516       
517       
518        Variable NG3_to_ICE = ConvertVAXDay2secs("23-JUL-2009")
519        Variable NG7_to_ICE = ConvertVAXDay2secs("25-FEB-2010")
520        Variable fileTime = ConvertVAXDay2secs(dateAndTimeStr)
521
522       
523        strswitch(instr)
524                case "CGB":
525                case "NG3":
526                        if(cmpstr(detStr, "ILL   ") == 0 )
527                                deadtime= DeadtimeNG3_ILL
528                        else
529                                if(fileTime > NG3_to_ICE)
530                                        deadtime = DeadtimeNG3_ORNL_ICE //detector is ordella-type, using ICE hardware
531                                else
532                                        deadtime = DeadtimeNG3_ORNL_VAX //detector is ordella-type
533                                endif
534                        endif
535                        break
536                case "NG5":
537                        if(cmpstr(detStr, "ILL   ") == 0 )
538                                deadtime= DeadtimeNG5_ILL
539                        else
540                                deadtime = DeadtimeNG5_ORNL     //detector is ordella-type
541                        endif
542                        break
543                case "NG7":
544                        if(cmpstr(detStr, "ILL   ") == 0 )
545                                deadtime= DeadtimeNG7_ILL
546                        else
547                                if(fileTime > NG7_to_ICE)
548                                        deadtime = DeadtimeNG7_ORNL_ICE //detector is ordella-type, using ICE hardware
549                                else
550                                        deadtime = DeadtimeNG7_ORNL_VAX //detector is ordella-type
551                                endif
552                        endif
553                        break
554                case "NGA":
555                case "NGB":
556                        if(cmpstr(detStr, "ILL   ") == 0 )
557                                deadtime= DeadtimeNGB_ILL
558                        else
559                                deadtime = DeadtimeNGB_ORNL_ICE //detector is ordella-type, using ICE hardware
560                        endif
561//                      Print "Using fictional values for NGB dead time"
562                        break
563                default:                                                       
564                        //return error?
565                        DoAlert 0, "no matching instrument DetectorDeadtime, using default"
566                        deadtime = DeadtimeDefault      //1e-6 seconds, typical for new ORNL detectors
567        endswitch
568       
569        return(deadtime)
570End
571
572// converts ONLY DD-MON-YYYY portion of the data collection time
573// to a number of seconds from midnight on 1/1/1904, as Igor likes to do
574//
575// dateAndTime is the full string of "dd-mon-yyyy hh:mm:ss" as returned by the function
576// getFileCreationDate(file)
577//
578Function ConvertVAXDay2secs(dateAndTime)
579        string dateAndTime
580       
581        Variable day,yr,mon,time_secs
582        string monStr
583
584        sscanf dateandtime,"%d-%3s-%4d",day,monStr,yr
585        mon = monStr2num(monStr)
586//      print yr,mon,day
587        time_secs = date2secs(yr,mon,day)
588
589        return(time_secs)
590end
591
592// dd-mon-yyyy hh:mm:ss -> seconds
593// the VAX uses 24 hr time for hh
594//
595Function ConvertVAXDateTime2secs(dateAndTime)
596        string dateAndTime
597       
598        Variable day,yr,mon,hh,mm,ss,time_secs
599        string str,monStr
600       
601        str=dateandtime
602        sscanf str,"%d-%3s-%4d %d:%d:%d",day,monStr,yr,hh,mm,ss
603        mon = monStr2num(monStr)
604//      print yr,mon,day,hh,mm,ss
605        time_secs = date2secs(yr,mon,day)
606        time_secs += hh*3600 + mm*60 + ss
607
608
609        return(time_secs)
610end
611
612// takes a month string and returns the corresponding number
613//
614Function monStr2num(monStr)
615        String monStr
616       
617        String list=";JAN;FEB;MAR;APR;MAY;JUN;JUL;AUG;SEP;OCT;NOV;DEC;"
618        return(WhichListItem(monStr, list ,";"))
619end
620
621
622//make a three character string of the run number
623//Moved to facility utils
624Function/S RunDigitString(num)
625        Variable num
626       
627        String numStr=""
628        if(num<10)
629                numStr = "00"+num2str(num)
630        else
631                if(num<100)
632                        numStr = "0"+num2str(num)
633                else
634                        numStr = num2str(num)
635                Endif
636        Endif
637        //Print "numstr = ",numstr
638        return(numstr)
639End
640
641//given a filename of a SANS data filename of the form
642//TTTTTnnn.SAn_TTT_Txxx
643//returns the prefix "TTTTT" as some number of characters
644//returns "" as an invalid file prefix
645//
646// NCNR-specifc, does not really belong here - but it's a beta procedure used for the
647// Combine Files Panel
648//
649Function/S GetPrefixStrFromFile(item)
650        String item
651        String invalid = ""     //"" is not a valid run prefix, since it's text
652        Variable num=-1
653       
654        //find the "dot"
655        String runStr=""
656        Variable pos = strsearch(item,".",0)
657        if(pos == -1)
658                //"dot" not found
659                return (invalid)
660        else
661                //found, skip the three characters preceeding it
662                if (pos <=3)
663                        //not enough characters
664                        return (invalid)
665                else
666                        runStr = item[0,pos-4]
667                        return (runStr)
668                Endif
669        Endif
670End
671
672
673
674
675/////VAX filename/Run number parsing utilities
676//
677// a collection of uilities for processing vax filenames
678//and processing lists (especially for display in popup menus)
679//
680//required to correctly account for VAX supplied version numbers, which
681//may or may not be removed by the ftp utility
682//
683// - parses lists of run numbers into real filenames
684// - selects proper detector constants
685//
686//**************************
687//
688//given a filename of a SANS data filename of the form
689//TTTTTnnn.SAn_TTT_Txxx
690//returns the run number "nnn" as a number
691//returns -1 as an invalid file number
692//
693// called by several ipfs
694//
695//
696Function GetRunNumFromFile(item)
697        String item
698        Variable invalid = -1   //negative numbers are invalid
699        Variable num=-1
700       
701        //find the "dot"
702        String runStr=""
703        Variable pos = strsearch(item,".",0)
704        if(pos == -1)
705                //"dot" not found
706                return (invalid)
707        else
708                //found, get the three characters preceeding it
709                if (pos <=2)
710                        //not enough characters
711                        return (invalid)
712                else
713                        runStr = item[pos-3,pos-1]
714                        //convert to a number
715                        num = str2num(runStr)
716                        //if valid, return it
717                        if (num == NaN)
718                                //3 characters were not a number
719                                return (invalid)
720                        else
721                                //run was OK
722                                return (num)
723                        Endif
724                Endif
725        Endif
726End
727
728//given a filename of a SANS data filename of the form
729//TTTTTnnn.SAn_TTT_Txxx
730//returns the run number "nnn" as a STRING of THREE characters
731//returns "ABC" as an invalid file number
732//
733// local function to aid in locating files by run number
734//
735Function/S GetRunNumStrFromFile(item)
736        String item
737        String invalid = "ABC"  //"ABC" is not a valid run number, since it's text
738        Variable num=-1
739       
740        //find the "dot"
741        String runStr=""
742        Variable pos = strsearch(item,".",0)
743        if(pos == -1)
744                //"dot" not found
745                return (invalid)
746        else
747                //found, get the three characters preceeding it
748                if (pos <=2)
749                        //not enough characters
750                        return (invalid)
751                else
752                        runStr = item[pos-3,pos-1]
753                        return (runStr)
754                Endif
755        Endif
756End
757
758//returns a string containing the full path to the file containing the
759//run number "num". The null string is returned if no valid file can be found
760//the path "catPathName" used and is hard-wired, will abort if this path does not exist
761//the file returned will be a RAW SANS data file, other types of files are
762//filtered out.
763//
764// called by Buttons.ipf and Transmission.ipf, and locally by parsing routines
765//
766Function/S FindFileFromRunNumber(num)
767        Variable num
768       
769        String fullName="",partialName="",item=""
770        //get list of raw data files in folder that match "num" (add leading zeros)
771        if( (num>999) || (num<=0) )
772                //Print "error in  FindFileFromRunNumber(num), file number too large or too small"
773                Return ("")
774        Endif
775        //make a three character string of the run number
776        String numStr=""
777        if(num<10)
778                numStr = "00"+num2str(num)
779        else
780                if(num<100)
781                        numStr = "0"+num2str(num)
782                else
783                        numStr = num2str(num)
784                Endif
785        Endif
786        //Print "numstr = ",numstr
787       
788        //make sure that path exists
789        PathInfo catPathName
790        String path = S_path
791        if (V_flag == 0)
792                Abort "folder path does not exist - use Pick Path button"
793        Endif
794        String list="",newList="",testStr=""
795       
796        list = IndexedFile(catPathName,-1,"????")       //get all files in folder
797        //find (the) one with the number in the run # location in the name
798        Variable numItems,ii,runFound,isRAW
799        numItems = ItemsInList(list,";")                //get the new number of items in the list
800        ii=0
801        do
802                //parse through the list in this order:
803                // 1 - does item contain run number (as a string) "TTTTTnnn.SAn_XXX_Tyyy"
804                // 2 - exclude by isRaw? (to minimize disk access)
805                item = StringFromList(ii, list  ,";" )
806                if(strlen(item) != 0)
807                        //find the run number, if it exists as a three character string
808                        testStr = GetRunNumStrFromFile(item)
809                        runFound= cmpstr(numStr,testStr)        //compare the three character strings, 0 if equal
810                        if(runFound == 0)
811                                //the run Number was found
812                                //build valid filename
813                                partialName = FindValidFileName(item)
814                                if(strlen(partialName) != 0)            //non-null return from FindValidFileName()
815                                        fullName = path + partialName
816                                        //check if RAW, if so,this must be the file!
817                                        isRAW = CheckIfRawData(fullName)
818                                        if(isRaw)
819                                                //stop here
820                                                return(fullname)
821                                        Endif
822                                Endif
823                        Endif
824                Endif
825                ii+=1
826        while(ii<numItems)              //process all items in list
827        Return ("")     //null return if file not found in list
828End
829
830//function to test a binary file to see if it is a RAW binary SANS file
831//first checks the total bytes in the file (which for raw data is 33316 bytes)
832//**note that the "DIV" file will also show up as a raw file by the run field
833//should be listed in CAT/SHORT and in patch windows
834//
835//Function then checks the file fname (full path:file) for "RAW" run.type field
836//if not found, the data is not raw data and zero is returned
837//
838// called by many procedures (both external and local)
839//
840Function CheckIfRawData(fname)
841        String fname
842       
843        Variable refnum,totalBytes
844        String testStr=""
845       
846        Open/R/T="????TEXT" refNum as fname
847        if(strlen(s_filename) == 0)     //user cancel (/Z not used, so V_flag not set)
848                return(0)
849        endif
850       
851        //get the total number of bytes in the file
852        FStatus refNum
853        totalBytes = V_logEOF
854        //Print totalBytes
855        if(totalBytes < 100)
856                Close refNum
857                return(0)               //not a raw file
858        endif
859        FSetPos refNum,75
860        FReadLine/N=3 refNum,testStr
861        Close refNum
862       
863        if(totalBytes == 33316 && ( cmpstr(testStr,"RAW")==0 ||  cmpstr(testStr,"SIM")==0))
864                //true, is raw data file
865                Return(1)
866        else
867                //some other file
868                Return(0)
869        Endif
870End
871
872//function to test a file to see if it is a DIV file
873//
874// returns truth 0/1
875//
876// called by many procedures (both external and local)
877//
878Function CheckIfDIVData(fname)
879        String fname
880       
881
882        Variable refnum,totalBytes
883//      String testStr=""
884       
885        Open/R/T="????TEXT" refNum as fname
886        if(strlen(s_filename) == 0)     //user cancel (/Z not used, so V_flag not set)
887                return(0)
888        endif
889       
890        //get the total number of bytes in the file
891        FStatus refNum
892        totalBytes = V_logEOF
893        //Print totalBytes
894        if(totalBytes < 100)
895                Close refNum
896                return(0)               //not a raw file
897        endif
898//      FSetPos refNum,75
899//      FReadLine/N=3 refNum,testStr
900        Close refNum
901       
902        if(totalBytes == 66116)         // && ( cmpstr(testStr,"RAW")==0 ||  cmpstr(testStr,"SIM")==0))
903                //true, is raw data file
904                Return(1)
905        else
906                //some other file
907                Return(0)
908        Endif
909
910End
911
912//function to check the header of a raw data file (full path specified by fname)
913//checks the field of the x-position of the beamstop during data collection
914//if the x-position is more negative (farther to the left) than xTol(input)
915//the the beamstop is "out" and the file is a transmission run and not a scattering run
916//xtol typically set at -5 (cm) - trans runs have bs(x) at -10 to -15 cm
917// function returns 1 if beamstop is out, 0 if beamstop is in
918//
919// tolerance is set as a global value "root:myGlobals:BeamstopXTol"
920//
921// called by Transmission.ipf, CatVSTable.ipf, NSORT.ipf
922//
923Function isTransFile(fName)
924        String fname
925       
926        Variable refnum,xpos
927        NVAR xTol = root:myGlobals:BeamstopXTol
928       
929        //pos = 369, read one real value
930       
931        SetDataFolder root:
932        String GBLoadStr="GBLoadWave/O/N=tempGBwave/T={2,2}/J=2/W=1/Q"
933        String strToExecute=""
934        // 1 R*4 value
935        strToExecute = GBLoadStr + "/S=368/U=1" + "\"" + fname + "\""
936        Execute strToExecute
937        Wave w=$"root:tempGBWave0"
938        xPos = w[0]
939        KillWaves/Z w
940        //Print "xPos = ",xpos
941       
942        if(xpos<=xTol)
943                //xpos is farther left (more negative) than xtol (currently -5 cm)
944                Return(1)
945        else
946                //some other file
947                Return(0)
948        Endif
949End
950
951
952//function to remove all spaces from names when searching for filenames
953//the filename (as saved) will never have interior spaces (TTTTTnnn_AB _Bnnn)
954//but the text field in the header WILL, if less than 3 characters were used for the
955//user's initials, and can have leading spaces if prefix was less than 5 characters
956//
957//returns a string identical to the original string, except with the interior spaces removed
958//
959// local function for file name manipulation
960//
961Function/S RemoveAllSpaces(str)
962        String str
963       
964        String tempstr = str
965        Variable ii,spc,len             //should never be more than 2 or 3 trailing spaces in a filename
966        ii=0
967        do
968                len = strlen(tempStr)
969                spc = strsearch(tempStr," ",0)          //is the last character a space?
970                if (spc == -1)
971                        break           //no more spaces found, get out
972                endif
973                str = tempstr
974                tempStr = str[0,(spc-1)] + str[(spc+1),(len-1)] //remove the space from the string
975        While(1)        //should never be more than 2 or 3
976       
977        If(strlen(tempStr) < 1)
978                tempStr = ""            //be sure to return a null string if problem found
979        Endif
980       
981        //Print strlen(tempstr)
982       
983        Return(tempStr)
984               
985End
986
987
988//Function attempts to find valid filename from partial name by checking for
989// the existence of the file on disk.
990// - checks as is
991// - adds ";vers" for possible VAX files
992// - strips spaces
993// - permutations of upper/lowercase
994//
995// added 11/99 - uppercase and lowercase versions of the file are tried, if necessary
996// since from marquee, the filename field (textread[0]) must be used, and can be a mix of
997// upper/lowercase letters, while the filename on the server (should) be all caps
998// now makes repeated calls to ValidFileString()
999//
1000// returns a valid filename (No path prepended) or a null string
1001//
1002// called by any functions, both external and local
1003//
1004Function/S FindValidFilename(partialName)
1005        String PartialName
1006       
1007        String retStr=""
1008       
1009        //try name with no changes - to allow for ABS files that have spaces in the names 12APR04
1010        retStr = ValidFileString(partialName)
1011        if(cmpstr(retStr,"") !=0)
1012                //non-null return
1013                return(retStr)
1014        Endif
1015       
1016        //if the partial name is derived from the file header, there can be spaces at the beginning
1017        //or in the middle of the filename - depending on the prefix and initials used
1018        //
1019        //remove any leading spaces from the name before starting
1020        partialName = RemoveAllSpaces(partialName)
1021       
1022        //try name with no spaces
1023        retStr = ValidFileString(partialName)
1024        if(cmpstr(retStr,"") !=0)
1025                //non-null return
1026                return(retStr)
1027        Endif
1028       
1029        //try all UPPERCASE
1030        partialName = UpperStr(partialName)
1031        retStr = ValidFileString(partialName)
1032        if(cmpstr(retStr,"") !=0)
1033                //non-null return
1034                return(retStr)
1035        Endif
1036       
1037        //try all lowercase (ret null if failure)
1038        partialName = LowerStr(partialName)
1039        retStr = ValidFileString(partialName)
1040        if(cmpstr(retStr,"") !=0)
1041                //non-null return
1042                return(retStr)
1043        else
1044                return(retStr)
1045        Endif
1046End
1047
1048// Function checks for the existence of a file
1049// partialName;vers (to account for VAX filenaming conventions)
1050// The partial name is tried first with no version number
1051//
1052// *** the PATH is hard-wired to catPathName (which is assumed to exist)
1053// version numers up to ;10 are tried
1054// only the "name;vers" is returned if successful. The path is not prepended
1055//
1056// local function
1057//
1058Function/S ValidFileString(partialName)
1059        String partialName
1060       
1061        String tempName = "",msg=""
1062        Variable ii,refnum
1063       
1064        ii=0
1065        do
1066                if(ii==0)
1067                        //first pass, try the partialName
1068                        tempName = partialName
1069                        Open/Z/R/T="????TEXT"/P=catPathName refnum tempName     //Does open file (/Z flag)
1070                        if(V_flag == 0)
1071                                //file exists
1072                                Close refnum            //YES needed,
1073                                break
1074                        endif
1075                else
1076                        tempName = partialName + ";" + num2str(ii)
1077                        Open/Z/R/T="????TEXT"/P=catPathName refnum tempName
1078                        if(V_flag == 0)
1079                                //file exists
1080                                Close refnum
1081                                break
1082                        endif
1083                Endif
1084                ii+=1
1085                //print "ii=",ii
1086        while(ii<11)
1087        //go get the selected bits of information, using tempName, which exists
1088        if(ii>=11)
1089                //msg = partialName + " not found. is version number > 11?"
1090                //DoAlert 0, msg
1091                //PathInfo catPathName
1092                //Print S_Path
1093                Return ("")             //use null string as error condition
1094        Endif
1095       
1096        Return (tempName)
1097End
1098
1099//returns a string containing filename (WITHOUT the ;vers)
1100//the input string is a full path to the file (Mac-style, still works on Win in IGOR)
1101//with the folders separated by colons
1102//
1103// called by MaskUtils.ipf, ProtocolAsPanel.ipf, WriteQIS.ipf
1104//
1105Function/S GetFileNameFromPathNoSemi(fullPath)
1106        String fullPath
1107       
1108        Variable offset1,offset2
1109        String filename=""
1110        //String PartialPath
1111        offset1 = 0
1112        do
1113                offset2 = StrSearch(fullPath, ":", offset1)
1114                if (offset2 == -1)                              // no more colons ?
1115                        fileName = FullPath[offset1,strlen(FullPath) ]
1116                        //PartialPath = FullPath[0, offset1-1]
1117                        break
1118                endif
1119                offset1 = offset2+1
1120        while (1)
1121       
1122        //remove version number from name, if it's there - format should be: filename;N
1123        filename =  StringFromList(0,filename,";")              //returns null if error
1124       
1125        Return filename
1126End
1127
1128//returns a string containing filename (INCLUDING the ;vers)
1129//the input string is a full path to the file (Mac-style, still works on Win in IGOR)
1130//with the folders separated by colons
1131//
1132// local, currently unused
1133//
1134Function/S GetFileNameFromPathKeepSemi(fullPath)
1135        String fullPath
1136       
1137        Variable offset1,offset2
1138        String filename
1139        //String PartialPath
1140        offset1 = 0
1141        do
1142                offset2 = StrSearch(fullPath, ":", offset1)
1143                if (offset2 == -1)                              // no more colons ?
1144                        fileName = FullPath[offset1,strlen(FullPath) ]
1145                        //PartialPath = FullPath[0, offset1-1]
1146                        break
1147                endif
1148                offset1 = offset2+1
1149        while (1)
1150       
1151        //keep version number from name, if it's there - format should be: filename;N
1152       
1153        Return filename
1154End
1155
1156//given the full path and filename (fullPath), strips the data path
1157//(Mac-style, separated by colons) and returns this path
1158//this partial path is the same string that would be returned from PathInfo, for example
1159//
1160// - allows the user to save to a different path than catPathName
1161//
1162// called by WriteQIS.ipf
1163//
1164Function/S GetPathStrFromfullName(fullPath)
1165        String fullPath
1166       
1167        Variable offset1,offset2
1168        //String filename
1169        String PartialPath
1170        offset1 = 0
1171        do
1172                offset2 = StrSearch(fullPath, ":", offset1)
1173                if (offset2 == -1)                              // no more colons ?
1174                        //fileName = FullPath[offset1,strlen(FullPath) ]
1175                        PartialPath = FullPath[0, offset1-1]
1176                        break
1177                endif
1178                offset1 = offset2+1
1179        while (1)
1180       
1181        Return PartialPath
1182End
1183
1184//given the VAX filename, pull off the first 8 characters to make a valid
1185//file string that can be used for naming averaged 1-d files
1186//
1187// called by ProtocolAsPanel.ipf and Tile_2D.ipf
1188//
1189Function/S GetNameFromHeader(fullName)
1190        String fullName
1191        String temp, newName = ""
1192        Variable spc,ii=0
1193       
1194        //filename is 20 characters NNNNNxxx.SAn_NNN_NNN
1195        //want the first 8 characters, NNNNNxxx, then strip off any spaces at the beginning
1196        //NNNNN was entered as less than 5 characters
1197        //returns a null string if no name can be found
1198        do
1199                temp = fullname[ii,7]           //characters ii,7 of the name
1200                spc = strsearch(temp," ",0)
1201                if (spc == -1)
1202                        break           //no more spaces found
1203                endif
1204                ii+=1
1205        While(ii<8)
1206       
1207        If(strlen(temp) < 1)
1208                newName = ""            //be sure to return a null string if problem found
1209        else
1210                newName = temp
1211        Endif
1212       
1213        Return(newName)
1214End
1215
1216//list (input) is a list, typically returned from IndexedFile()
1217//which is semicolon-delimited, and may contain filenames from the VAX
1218//that contain version numbers, where the version number appears as a separate list item
1219//(and also as a non-existent file)
1220//these numbers must be purged from the list, especially for display in a popup
1221//or list processing of filenames
1222//the function returns the list, cleaned of version numbers (up to 11)
1223//raw data files will typically never have a version number other than 1.
1224//
1225// if there are no version numbers in the list, the input list is returned
1226//
1227// called by CatVSTable.ipf, NSORT.ipf, Transmission.ipf, WorkFileUtils.ipf
1228//
1229Function/S RemoveVersNumsFromList(list)
1230        String list
1231       
1232        //get rid of version numbers first (up to 11)
1233        Variable ii,num
1234        String item
1235        num = ItemsInList(list,";")
1236        ii=1
1237        do
1238                item = num2str(ii)
1239                list = RemoveFromList(item, list ,";" )
1240                ii+=1
1241        while(ii<12)
1242       
1243        return (list)
1244End
1245
1246//input is a list of run numbers, and output is a list of filenames (not the full path)
1247//*** input list must be COMMA delimited***
1248//output is equivalent to selecting from the CAT table
1249//if some or all of the list items are valid filenames, keep them...
1250//if an error is encountered, notify of the offending element and return a null list
1251//
1252//output is COMMA delimited
1253//
1254// this routine is expecting that the "ask", "none" special cases are handled elsewhere
1255//and not passed here
1256//
1257// called by Marquee.ipf, MultipleReduce.ipf, ProtocolAsPanel.ipf
1258//
1259Function/S ParseRunNumberList(list)
1260        String list
1261       
1262        String newList="",item="",tempStr=""
1263        Variable num,ii,runNum
1264       
1265        //expand number ranges, if any
1266        list = ExpandNumRanges(list)
1267       
1268        num=itemsinlist(list,",")
1269       
1270        for(ii=0;ii<num;ii+=1)
1271                //get the item
1272                item = StringFromList(ii,list,",")
1273                //is it already a valid filename?
1274                tempStr=FindValidFilename(item) //returns filename if good, null if error
1275                if(strlen(tempstr)!=0)
1276                        //valid name, add to list
1277                        //Print "it's a file"
1278                        newList += tempStr + ","
1279                else
1280                        //not a valid name
1281                        //is it a number?
1282                        runNum=str2num(item)
1283                        //print runnum
1284                        if(numtype(runNum) != 0)
1285                                //not a number -  maybe an error                       
1286                                DoAlert 0,"List item "+item+" is not a valid run number or filename. Please enter a valid number or filename."
1287                                return("")
1288                        else
1289                                //a run number or an error
1290                                tempStr = GetFileNameFromPathNoSemi( FindFileFromRunNumber(runNum) )
1291                                if(strlen(tempstr)==0)
1292                                        //file not found, error
1293                                        DoAlert 0,"List item "+item+" is not a valid run number. Please enter a valid number."
1294                                        return("")
1295                                else
1296                                        newList += tempStr + ","
1297                                endif
1298                        endif
1299                endif
1300        endfor          //loop over all items in list
1301       
1302        return(newList)
1303End
1304
1305//takes a comma delimited list that MAY contain number range, and
1306//expands any range of run numbers into a comma-delimited list...
1307//and returns the new list - if not a range, return unchanged
1308//
1309// local function
1310//
1311Function/S ExpandNumRanges(list)
1312        String list
1313       
1314        String newList="",dash="-",item,str
1315        Variable num,ii,hasDash
1316       
1317        num=itemsinlist(list,",")
1318//      print num
1319        for(ii=0;ii<num;ii+=1)
1320                //get the item
1321                item = StringFromList(ii,list,",")
1322                //does it contain a dash?
1323                hasDash = strsearch(item,dash,0)                //-1 if no dash found
1324                if(hasDash == -1)
1325                        //not a range, keep it in the list
1326                        newList += item + ","
1327                else
1328                        //has a dash (so it's a range), expand (or add null)
1329                        newList += ListFromDash(item)           
1330                endif
1331        endfor
1332       
1333        return newList
1334End
1335
1336//be sure to add a trailing comma to the return string...
1337//
1338// local function
1339//
1340Function/S ListFromDash(item)
1341        String item
1342       
1343        String numList="",loStr="",hiStr=""
1344        Variable lo,hi,ii
1345       
1346        loStr=StringFromList(0,item,"-")        //treat the range as a list
1347        hiStr=StringFromList(1,item,"-")
1348        lo=str2num(loStr)
1349        hi=str2num(hiStr)
1350        if( (numtype(lo) != 0) || (numtype(hi) !=0 ) || (lo > hi) )
1351                numList=""
1352                return numList
1353        endif
1354        for(ii=lo;ii<=hi;ii+=1)
1355                numList += num2str(ii) + ","
1356        endfor
1357       
1358        Return numList
1359End
1360
1361
1362////////Transmission
1363//******************
1364//lookup tables for attenuator transmissions
1365//NG3 and NG7 attenuators are physically different, so the transmissions are slightly different
1366//NG1 - (8m SANS) is not supported
1367//
1368// new calibration done June 2007, John Barker
1369//
1370Proc MakeNG3AttenTable()
1371
1372        NewDataFolder/O root:myGlobals:Attenuators
1373        //do explicitly to avoid data folder problems, redundant, but it must work without fail
1374        Variable num=10         //10 needed for tables after June 2007
1375
1376        Make/O/N=(num) root:myGlobals:Attenuators:ng3att0
1377        Make/O/N=(num) root:myGlobals:Attenuators:ng3att1
1378        Make/O/N=(num) root:myGlobals:Attenuators:ng3att2
1379        Make/O/N=(num) root:myGlobals:Attenuators:ng3att3
1380        Make/O/N=(num) root:myGlobals:Attenuators:ng3att4
1381        Make/O/N=(num) root:myGlobals:Attenuators:ng3att5
1382        Make/O/N=(num) root:myGlobals:Attenuators:ng3att6
1383        Make/O/N=(num) root:myGlobals:Attenuators:ng3att7
1384        Make/O/N=(num) root:myGlobals:Attenuators:ng3att8
1385        Make/O/N=(num) root:myGlobals:Attenuators:ng3att9
1386        Make/O/N=(num) root:myGlobals:Attenuators:ng3att10
1387       
1388        // and a wave for the errors at each attenuation factor
1389        Make/O/N=(num) root:myGlobals:Attenuators:ng3att0_err
1390        Make/O/N=(num) root:myGlobals:Attenuators:ng3att1_err
1391        Make/O/N=(num) root:myGlobals:Attenuators:ng3att2_err
1392        Make/O/N=(num) root:myGlobals:Attenuators:ng3att3_err
1393        Make/O/N=(num) root:myGlobals:Attenuators:ng3att4_err
1394        Make/O/N=(num) root:myGlobals:Attenuators:ng3att5_err
1395        Make/O/N=(num) root:myGlobals:Attenuators:ng3att6_err
1396        Make/O/N=(num) root:myGlobals:Attenuators:ng3att7_err
1397        Make/O/N=(num) root:myGlobals:Attenuators:ng3att8_err
1398        Make/O/N=(num) root:myGlobals:Attenuators:ng3att9_err
1399        Make/O/N=(num) root:myGlobals:Attenuators:ng3att10_err
1400       
1401       
1402        //each wave has 10 elements, the transmission of att# at the wavelengths
1403        //lambda = 4,5,6,7,8,10,12,14,17,20 (4 A and 20 A are extrapolated values)
1404        Make/O/N=(num) root:myGlobals:Attenuators:ng3lambda={4,5,6,7,8,10,12,14,17,20}
1405       
1406        // new calibration done June 2007, John Barker
1407        root:myGlobals:Attenuators:ng3att0 = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
1408        root:myGlobals:Attenuators:ng3att1 = {0.444784,0.419,0.3935,0.3682,0.3492,0.3132,0.2936,0.2767,0.2477,0.22404}
1409        root:myGlobals:Attenuators:ng3att2 = {0.207506,0.1848,0.1629,0.1447,0.1292,0.1056,0.09263,0.08171,0.06656,0.0546552}
1410        root:myGlobals:Attenuators:ng3att3 = {0.092412,0.07746,0.06422,0.05379,0.04512,0.03321,0.02707,0.02237,0.01643,0.0121969}
1411        root:myGlobals:Attenuators:ng3att4 = {0.0417722,0.03302,0.02567,0.02036,0.01604,0.01067,0.00812,0.006316,0.00419,0.00282411}
1412        root:myGlobals:Attenuators:ng3att5 = {0.0187129,0.01397,0.01017,0.007591,0.005668,0.003377,0.002423,0.001771,0.001064,0.000651257}
1413        root:myGlobals:Attenuators:ng3att6 = {0.00851048,0.005984,0.004104,0.002888,0.002029,0.001098,0.0007419,0.0005141,0.000272833,0.000150624}
1414        root:myGlobals:Attenuators:ng3att7 = {0.00170757,0.001084,0.0006469,0.0004142,0.0002607,0.0001201,7.664e-05,4.06624e-05,1.77379e-05,7.30624e-06}
1415        root:myGlobals:Attenuators:ng3att8 = {0.000320057,0.0001918,0.0001025,6.085e-05,3.681e-05,1.835e-05,6.74002e-06,3.25288e-06,1.15321e-06,3.98173e-07}
1416        root:myGlobals:Attenuators:ng3att9 = {6.27682e-05,3.69e-05,1.908e-05,1.196e-05,8.738e-06,6.996e-06,6.2901e-07,2.60221e-07,7.49748e-08,2.08029e-08}
1417        root:myGlobals:Attenuators:ng3att10 = {1.40323e-05,8.51e-06,5.161e-06,4.4e-06,4.273e-06,1.88799e-07,5.87021e-08,2.08169e-08,4.8744e-09,1.08687e-09}
1418 
1419  // percent errors as measured, May 2007 values
1420  // zero error for zero attenuators, appropriate average values put in for unknown values
1421        root:myGlobals:Attenuators:ng3att0_err = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1422        root:myGlobals:Attenuators:ng3att1_err = {0.15,0.142,0.154,0.183,0.221,0.328,0.136,0.13,0.163,0.15}
1423        root:myGlobals:Attenuators:ng3att2_err = {0.25,0.257,0.285,0.223,0.271,0.405,0.212,0.223,0.227,0.25}
1424        root:myGlobals:Attenuators:ng3att3_err = {0.3,0.295,0.329,0.263,0.323,0.495,0.307,0.28,0.277,0.3}
1425        root:myGlobals:Attenuators:ng3att4_err = {0.35,0.331,0.374,0.303,0.379,0.598,0.367,0.322,0.33,0.35}
1426        root:myGlobals:Attenuators:ng3att5_err = {0.4,0.365,0.418,0.355,0.454,0.745,0.411,0.367,0.485,0.4}
1427        root:myGlobals:Attenuators:ng3att6_err = {0.45,0.406,0.473,0.385,0.498,0.838,0.454,0.49,0.5,0.5}
1428        root:myGlobals:Attenuators:ng3att7_err = {0.6,0.554,0.692,0.425,0.562,0.991,0.715,0.8,0.8,0.8}
1429        root:myGlobals:Attenuators:ng3att8_err = {0.7,0.705,0.927,0.503,0.691,1.27,1,1,1,1}
1430        root:myGlobals:Attenuators:ng3att9_err = {1,0.862,1.172,0.799,1.104,1.891,1.5,1.5,1.5,1.5}
1431        root:myGlobals:Attenuators:ng3att10_err = {1.5,1.054,1.435,1.354,1.742,2,2,2,2,2}
1432 
1433 
1434  //old tables, pre-June 2007
1435//      Make/O/N=9 root:myGlobals:Attenuators:ng3lambda={5,6,7,8,10,12,14,17,20}
1436//      root:myGlobals:Attenuators:ng3att0 = {1, 1, 1, 1, 1, 1, 1, 1,1 }
1437//      root:myGlobals:Attenuators:ng3att1 = {0.421, 0.394, 0.371, 0.349, 0.316, 0.293, 0.274, 0.245,0.220}
1438//      root:myGlobals:Attenuators:ng3att2 = {0.187, 0.164, 0.145, 0.130, 0.106, 0.0916, 0.0808, 0.0651,0.0531}
1439//      root:myGlobals:Attenuators:ng3att3 = {0.0777, 0.0636, 0.0534, 0.0446, 0.0330, 0.0262, 0.0217, 0.0157 ,0.0116}
1440//      root:myGlobals:Attenuators:ng3att4 = {0.0328, 0.0252, 0.0195, 0.0156, 0.0104, 7.68e-3, 5.98e-3, 3.91e-3,0.00262}
1441//      root:myGlobals:Attenuators:ng3att5 = {0.0139, 9.94e-3, 7.34e-3, 5.44e-3, 3.29e-3, 2.25e-3, 1.66e-3, 9.95e-4, 6.12e-4}
1442//      root:myGlobals:Attenuators:ng3att6 = {5.95e-3, 3.97e-3, 2.77e-3, 1.95e-3, 1.06e-3, 6.81e-4, 4.71e-4, 2.59e-4 , 1.45e-4}
1443//      root:myGlobals:Attenuators:ng3att7 = {1.07e-3, 6.24e-4, 3.90e-4, 2.44e-4, 1.14e-4, 6.55e-5, 4.10e-5, 1.64e-5 , 7.26e-6}
1444//      root:myGlobals:Attenuators:ng3att8 = {1.90e-4, 9.84e-5, 5.60e-5, 3.25e-5, 1.55e-5, 6.60e-6, 3.42e-6, 1.04e-6 , 3.48e-7}
1445//      root:myGlobals:Attenuators:ng3att9 = {3.61e-5, 1.74e-5, 9.90e-6, 6.45e-6, 2.35e-6, 6.35e-7, 2.86e-7, 6.61e-8 , 1.73e-8}
1446//      root:myGlobals:Attenuators:ng3att10 = {7.60e-6, 3.99e-6, 2.96e-6, 2.03e-6, 3.34e-7, 6.11e-8, 2.39e-8, 4.19e-9 , 8.60e-10}
1447
1448End
1449
1450// new calibration done June 2007, John Barker
1451Proc MakeNG7AttenTable()
1452
1453        NewDataFolder/O root:myGlobals:Attenuators
1454       
1455        Variable num=10         //10 needed for tables after June 2007
1456       
1457        Make/O/N=(num) root:myGlobals:Attenuators:ng7att0
1458        Make/O/N=(num) root:myGlobals:Attenuators:ng7att1
1459        Make/O/N=(num) root:myGlobals:Attenuators:ng7att2
1460        Make/O/N=(num) root:myGlobals:Attenuators:ng7att3
1461        Make/O/N=(num) root:myGlobals:Attenuators:ng7att4
1462        Make/O/N=(num) root:myGlobals:Attenuators:ng7att5
1463        Make/O/N=(num) root:myGlobals:Attenuators:ng7att6
1464        Make/O/N=(num) root:myGlobals:Attenuators:ng7att7
1465        Make/O/N=(num) root:myGlobals:Attenuators:ng7att8
1466        Make/O/N=(num) root:myGlobals:Attenuators:ng7att9
1467        Make/O/N=(num) root:myGlobals:Attenuators:ng7att10
1468       
1469        // and a wave for the errors at each attenuation factor
1470        Make/O/N=(num) root:myGlobals:Attenuators:ng7att0_err
1471        Make/O/N=(num) root:myGlobals:Attenuators:ng7att1_err
1472        Make/O/N=(num) root:myGlobals:Attenuators:ng7att2_err
1473        Make/O/N=(num) root:myGlobals:Attenuators:ng7att3_err
1474        Make/O/N=(num) root:myGlobals:Attenuators:ng7att4_err
1475        Make/O/N=(num) root:myGlobals:Attenuators:ng7att5_err
1476        Make/O/N=(num) root:myGlobals:Attenuators:ng7att6_err
1477        Make/O/N=(num) root:myGlobals:Attenuators:ng7att7_err
1478        Make/O/N=(num) root:myGlobals:Attenuators:ng7att8_err
1479        Make/O/N=(num) root:myGlobals:Attenuators:ng7att9_err
1480        Make/O/N=(num) root:myGlobals:Attenuators:ng7att10_err 
1481       
1482        //NG7 wave has 10 elements, the transmission of att# at the wavelengths
1483        //lambda =4, 5,6,7,8,10,12,14,17,20
1484        // note that some of the higher attenuations and ALL of the 4 A and 20A data is interpolated
1485        // none of these values are expected to be used in reality since the flux would be too low in practice
1486        Make/O/N=(num) root:myGlobals:Attenuators:ng7lambda={4,5,6,7,8,10,12,14,17,20}
1487
1488// New calibration, June 2007, John Barker
1489        root:myGlobals:Attenuators:ng7att0 = {1, 1, 1, 1, 1, 1, 1, 1 ,1,1}     
1490        root:myGlobals:Attenuators:ng7att1 = {0.448656,0.4192,0.3925,0.3661,0.3458,0.3098,0.2922,0.2738,0.2544,0.251352}
1491        root:myGlobals:Attenuators:ng7att2 = {0.217193,0.1898,0.1682,0.148,0.1321,0.1076,0.0957,0.08485,0.07479,0.0735965}
1492        root:myGlobals:Attenuators:ng7att3 = {0.098019,0.07877,0.06611,0.05429,0.04548,0.03318,0.02798,0.0234,0.02004,0.0202492}
1493        root:myGlobals:Attenuators:ng7att4 = {0.0426904,0.03302,0.02617,0.02026,0.0158,0.01052,0.008327,0.006665,0.005745,0.00524807}
1494        root:myGlobals:Attenuators:ng7att5 = {0.0194353,0.01398,0.01037,0.0075496,0.005542,0.003339,0.002505,0.001936,0.001765,0.00165959}
1495        root:myGlobals:Attenuators:ng7att6 = {0.00971666,0.005979,0.004136,0.002848,0.001946,0.001079,0.0007717,0.000588,0.000487337,0.000447713}
1496        root:myGlobals:Attenuators:ng7att7 = {0.00207332,0.001054,0.0006462,0.0003957,0.0002368,0.0001111,7.642e-05,4.83076e-05,3.99401e-05,3.54814e-05}
1497        root:myGlobals:Attenuators:ng7att8 = {0.000397173,0.0001911,0.0001044,5.844e-05,3.236e-05,1.471e-05,6.88523e-06,4.06541e-06,3.27333e-06,2.81838e-06}
1498        root:myGlobals:Attenuators:ng7att9 = {9.43625e-05,3.557e-05,1.833e-05,1.014e-05,6.153e-06,1.64816e-06,6.42353e-07,3.42132e-07,2.68269e-07,2.2182e-07}
1499        root:myGlobals:Attenuators:ng7att10 = {2.1607e-05,7.521e-06,2.91221e-06,1.45252e-06,7.93451e-07,1.92309e-07,5.99279e-08,2.87928e-08,2.19862e-08,1.7559e-08}
1500
1501  // percent errors as measured, May 2007 values
1502  // zero error for zero attenuators, appropriate average values put in for unknown values
1503        root:myGlobals:Attenuators:ng7att0_err = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1504        root:myGlobals:Attenuators:ng7att1_err = {0.2,0.169,0.1932,0.253,0.298,0.4871,0.238,0.245,0.332,0.3}
1505        root:myGlobals:Attenuators:ng7att2_err = {0.3,0.305,0.3551,0.306,0.37,0.6113,0.368,0.413,0.45,0.4}
1506        root:myGlobals:Attenuators:ng7att3_err = {0.4,0.355,0.4158,0.36,0.4461,0.7643,0.532,0.514,0.535,0.5}
1507        root:myGlobals:Attenuators:ng7att4_err = {0.45,0.402,0.4767,0.415,0.5292,0.9304,0.635,0.588,0.623,0.6}
1508        root:myGlobals:Attenuators:ng7att5_err = {0.5,0.447,0.5376,0.487,0.6391,1.169,0.708,0.665,0.851,0.8}
1509        root:myGlobals:Attenuators:ng7att6_err = {0.6,0.501,0.6136,0.528,0.8796,1.708,0.782,0.874,1,1}
1510        root:myGlobals:Attenuators:ng7att7_err = {0.8,0.697,0.9149,0.583,1.173,2.427,1.242,2,2,2}
1511        root:myGlobals:Attenuators:ng7att8_err = {1,0.898,1.24,0.696,1.577,3.412,3,3,3,3}
1512        root:myGlobals:Attenuators:ng7att9_err = {1.5,1.113,1.599,1.154,2.324,4.721,5,5,5,5}
1513        root:myGlobals:Attenuators:ng7att10_err = {1.5,1.493,5,5,5,5,5,5,5,5} 
1514 
1515
1516// Pre-June 2007 calibration values - do not use these anymore 
1517////    root:myGlobals:Attenuators:ng7att0 = {1, 1, 1, 1, 1, 1, 1, 1 ,1}
1518////    root:myGlobals:Attenuators:ng7att1 = {0.418, 0.393, 0.369, 0.347, 0.313, 0.291, 0.271, 0.244, 0.219 }
1519////    root:myGlobals:Attenuators:ng7att2 = {0.189, 0.167, 0.148, 0.132, 0.109, 0.0945, 0.0830, 0.0681, 0.0560}
1520////    root:myGlobals:Attenuators:ng7att3 = {0.0784, 0.0651, 0.0541, 0.0456, 0.0340, 0.0273, 0.0223, 0.0164 , 0.0121}
1521////    root:myGlobals:Attenuators:ng7att4 = {0.0328, 0.0256, 0.0200, 0.0159, 0.0107, 7.98e-3, 6.14e-3, 4.09e-3 , 0.00274}
1522////    root:myGlobals:Attenuators:ng7att5 = {0.0139, 0.0101, 7.43e-3, 5.58e-3, 3.42e-3, 2.36e-3, 1.70e-3, 1.03e-3 , 6.27e-4}
1523////    root:myGlobals:Attenuators:ng7att6 = {5.90e-3, 4.07e-3, 2.79e-3, 1.99e-3, 1.11e-3, 7.13e-4, 4.91e-4, 2.59e-4 , 1.42e-4}
1524////    root:myGlobals:Attenuators:ng7att7 = {1.04e-3, 6.37e-4, 3.85e-4, 2.46e-4, 1.16e-4, 6.86e-5, 4.10e-5, 1.64e-5 ,7.02e-6}
1525////    root:myGlobals:Attenuators:ng7att8 = {1.90e-4, 1.03e-4, 5.71e-5, 3.44e-5, 1.65e-5, 6.60e-6, 3.42e-6, 1.04e-6 , 3.48e-7}
1526////    root:myGlobals:Attenuators:ng7att9 = {3.58e-5, 1.87e-5, 1.05e-5, 7.00e-6, 2.35e-6, 6.35e-7, 2.86e-7, 6.61e-8 , 1.73e-8}
1527////    root:myGlobals:Attenuators:ng7att10 = {7.76e-6, 4.56e-6, 3.25e-6, 2.03e-6, 3.34e-7, 6.11e-8, 2.39e-8, 4.19e-9, 8.60e-10}
1528End
1529
1530
1531// xxxx JAN 2013 -- Using John's measured values from 23 JAN 2013
1532//
1533// xxxx there are 13 discrete wavelengths in NGBLambda = 13 (only 10 used for 30m)
1534// xxxx there are only 9 attenuators, not 10 as in the 30m
1535//
1536// -- updated MAY 2013 --
1537// K. Weigandt's calibration
1538// 12 discrete wavelengths
1539// 10 attenuators
1540//
1541Proc MakeNGBAttenTable()
1542
1543        NewDataFolder/O root:myGlobals:Attenuators
1544       
1545//      Variable num=13         //13 needed for tables to cover 3A - 30A
1546        Variable num=12         //12 needed for tables to cover 3A - 30A
1547       
1548        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt0
1549        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt1
1550        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt2
1551        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt3
1552        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt4
1553        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt5
1554        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt6
1555        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt7
1556        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt8
1557        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt9
1558        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt10
1559       
1560        // and a wave for the errors at each attenuation factor
1561        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt0_err
1562        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt1_err
1563        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt2_err
1564        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt3_err
1565        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt4_err
1566        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt5_err
1567        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt6_err
1568        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt7_err
1569        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt8_err
1570        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt9_err
1571        Make/O/N=(num) root:myGlobals:Attenuators:NGBatt10_err 
1572       
1573        //NGB wave has 13 elements, the transmission of att# at the wavelengths
1574        //lambda = 3A to 30A
1575        // note that some of the higher attenuations and ALL of the 30A data is interpolated
1576        // none of these values are expected to be used in reality since the flux would be too low in practice
1577//      Make/O/N=(num) root:myGlobals:Attenuators:NGBlambda={3,4,5,6,7,8,10,12,14,17,20,25,30}          //this is for 13 wavelengths
1578        Make/O/N=(num) root:myGlobals:Attenuators:NGBlambda={3,4,5,6,8,10,12,14,16,20,25,30}            // 12 wavelengths, MAY 2013
1579
1580
1581// new calibrations MAY 2013
1582        root:myGlobals:Attenuators:NGBatt0 = {1,1,1,1,1,1,1,1,1,1,1,1,1}       
1583        root:myGlobals:Attenuators:NGBatt1 = {0.512,0.474,0.418,0.392,0.354,0.325,0.294,0.27,0.255,0.222,0.185,0.155}
1584        root:myGlobals:Attenuators:NGBatt2 = {0.268,0.227,0.184,0.16,0.129,0.108,0.0904,0.0777,0.0689,0.0526,0.0372,0.0263}
1585        root:myGlobals:Attenuators:NGBatt3 = {0.135,0.105,0.0769,0.0629,0.0455,0.0342,0.0266,0.0212,0.0178,0.0117,0.007,0.00429}
1586        root:myGlobals:Attenuators:NGBatt4 = {0.0689,0.0483,0.0324,0.0249,0.016,0.0109,0.00782,0.00583,0.0046,0.00267,0.00135,0.000752}
1587        root:myGlobals:Attenuators:NGBatt5 = {0.0348,0.0224,0.0136,0.00979,0.0056,0.00347,0.0023,0.0016,0.0012,0.000617,0.000282,0.000155}
1588        root:myGlobals:Attenuators:NGBatt6 = {0.018,0.0105,0.00586,0.00398,0.00205,0.00115,0.000709,0.000467,0.000335,0.000157,7.08e-05,4e-05}
1589        root:myGlobals:Attenuators:NGBatt7 = {0.00466,0.00226,0.00104,0.000632,0.00026,0.000123,6.8e-05,4.26e-05,3e-05,1.5e-05,8e-06,4e-06}
1590        root:myGlobals:Attenuators:NGBatt8 = {0.00121,0.000488,0.000187,0.000101,3.52e-05,1.61e-05,9.79e-06,7.68e-06,4.4e-06,2e-06,1e-06,5e-07}
1591        root:myGlobals:Attenuators:NGBatt9 = {0.000312,0.000108,3.53e-05,1.78e-05,6.6e-06,4.25e-06,2e-06,1.2e-06,9e-07,4e-07,1.6e-07,9e-08}
1592        root:myGlobals:Attenuators:NGBatt10 = {8.5e-05,2.61e-05,8.24e-06,4.47e-06,2.53e-06,9e-07,5e-07,3e-07,2e-07,1e-07,4e-08,2e-08}
1593
1594  // percent errors as measured, MAY 2013 values
1595  // zero error for zero attenuators, large values put in for unknown values (either 2% or 5%)
1596        root:myGlobals:Attenuators:NGBatt0_err = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1597        root:myGlobals:Attenuators:NGBatt1_err = {0.174,0.256,0.21,0.219,0.323,0.613,0.28,0.135,0.195,0.216,0.214,19.8}
1598        root:myGlobals:Attenuators:NGBatt2_err = {0.261,0.458,0.388,0.419,0.354,0.668,0.321,0.206,0.302,0.305,0.315,31.1}
1599        root:myGlobals:Attenuators:NGBatt3_err = {0.319,0.576,0.416,0.448,0.431,0.688,0.37,0.247,0.368,0.375,0.41,50.6}
1600        root:myGlobals:Attenuators:NGBatt4_err = {0.41,0.611,0.479,0.515,0.461,0.715,0.404,0.277,0.416,0.436,0.576,111}
1601        root:myGlobals:Attenuators:NGBatt5_err = {0.549,0.684,0.503,0.542,0.497,0.735,0.428,0.3,0.456,0.538,1.08,274}
1602        root:myGlobals:Attenuators:NGBatt6_err = {0.61,0.712,0.528,0.571,0.52,0.749,0.446,0.333,0.515,0.836,2.28,5}
1603        root:myGlobals:Attenuators:NGBatt7_err = {0.693,0.76,0.556,0.607,0.554,0.774,0.516,0.56,0.924,5,5,5}
1604        root:myGlobals:Attenuators:NGBatt8_err = {0.771,0.813,0.59,0.657,0.612,0.867,0.892,1.3,5,5,5,5}
1605        root:myGlobals:Attenuators:NGBatt9_err = {0.837,0.867,0.632,0.722,0.751,1.21,5,5,5,5,5,5}
1606        root:myGlobals:Attenuators:NGBatt10_err = {0.892,0.921,0.715,0.845,1.09,5,5,5,5,5,5,5} 
1607
1608
1609//// (old) New calibration, Jan 2013 John Barker
1610//      root:myGlobals:Attenuators:NGBatt0 = {1,1,1,1,1,1,1,1,1,1,1,1,1}       
1611//      root:myGlobals:Attenuators:NGBatt1 = {0.522,0.476,0.42007,0.39298,0.36996,0.35462,0.31637,0.29422,0.27617,0.24904,0.22263,0.18525,0.15}
1612//      root:myGlobals:Attenuators:NGBatt2 = {0.27046,0.21783,0.17405,0.15566,0.13955,0.1272,0.10114,0.087289,0.077363,0.063607,0.051098,0.0357,0.023}
1613//      root:myGlobals:Attenuators:NGBatt3 = {0.12601,0.090906,0.064869,0.054644,0.046916,0.041169,0.028926,0.023074,0.019276,0.014244,0.01021,0.006029,0.0033}
1614//      root:myGlobals:Attenuators:NGBatt4 = {0.057782,0.037886,0.024727,0.019499,0.015719,0.013041,0.0080739,0.0059418,0.0046688,0.0031064,0.0020001,0.0010049,0.0005}
1615//      root:myGlobals:Attenuators:NGBatt5 = {0.026627,0.016169,0.0096679,0.0071309,0.0052982,0.0040951,0.0021809,0.001479,0.001096,0.00066564,0.00039384,0.0002,9e-05}
1616//      root:myGlobals:Attenuators:NGBatt6 = {0.0091671,0.0053041,0.0029358,0.0019376,0.0013125,0.00096946,0.00042126,0.0002713,0.00019566,0.00011443,5e-05,3e-05,1.2e-05}
1617//      root:myGlobals:Attenuators:NGBatt7 = {0.0017971,0.00089679,0.00040572,0.0002255,0.00013669,8.7739e-05,3.3373e-05,2.0759e-05,1.5624e-05,1e-05,8e-06,4e-06,2.1e-06}
1618//      root:myGlobals:Attenuators:NGBatt8 = {0.00033646,0.00012902,4.6033e-05,2.414e-05,1.4461e-05,9.4644e-06,4.8121e-06,4e-06,3e-06,2e-06,1e-06,7e-07,3.3e-07}
1619//      root:myGlobals:Attenuators:NGBatt9 = {7e-05,2e-05,8.2796e-06,4.5619e-06,3.1543e-06,2.6216e-06,8e-07,6e-07,4e-07,3e-07,2e-07,1e-07,5e-08}
1620////    root:myGlobals:Attenuators:NGBatt10 = {}
1621//
1622//  // percent errors as measured, Jan 2013 values
1623//  // zero error for zero attenuators, large values put in for unknown values (either 2% or 5%)
1624//      root:myGlobals:Attenuators:NGBatt0_err = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1625//      root:myGlobals:Attenuators:NGBatt1_err = {0.12116,0.111059,0.150188,0.15168,0.174434,0.218745,0.0938678,0.144216,0.2145,0.141995,0.153655,0.157188,5}
1626//      root:myGlobals:Attenuators:NGBatt2_err = {0.183583,0.19981,0.278392,0.286518,0.336599,0.240429,0.190996,0.178529,0.266807,0.23608,0.221334,0.245336,5}
1627//      root:myGlobals:Attenuators:NGBatt3_err = {0.271054,0.326341,0.30164,0.31008,0.364188,0.296638,0.1914,0.22433,0.340313,0.307021,0.279339,0.319965,5}
1628//      root:myGlobals:Attenuators:NGBatt4_err = {0.333888,0.361023,0.356208,0.368968,0.437084,0.322955,0.248284,0.260956,0.402069,0.368168,0.337252,0.454958,5}
1629//      root:myGlobals:Attenuators:NGBatt5_err = {0.365745,0.433845,0.379735,0.394999,0.470603,0.357534,0.290938,0.291193,0.455465,0.426855,0.434639,2,5}
1630//      root:myGlobals:Attenuators:NGBatt6_err = {0.402066,0.470239,0.410136,0.432342,0.523241,0.389247,0.333352,0.325301,0.517036,0.539386,2,2,5}
1631//      root:myGlobals:Attenuators:NGBatt7_err = {0.542334,0.549954,0.45554,0.497426,0.624473,0.454971,0.432225,0.464043,0.752858,2,5,5,5}
1632//      root:myGlobals:Attenuators:NGBatt8_err = {0.704775,0.673556,0.537178,0.62027,0.814375,0.582449,0.662811,2,2,5,5,5,5}
1633//      root:myGlobals:Attenuators:NGBatt9_err = {2,2,0.583513,0.685477,0.901413,0.767115,2,5,5,5,5,5,5}
1634////    root:myGlobals:Attenuators:NGBatt10_err = {} 
1635 
1636End
1637
1638//returns the transmission of the attenuator (at NG3) given the attenuator number
1639//which must be an integer(to select the wave) and given the wavelength.
1640//the wavelength may be any value between 4 and 20 (A), and is interpolated
1641//between calibrated wavelengths for a given attenuator
1642//
1643// Mar 2010 - abs() added to attStr to account for ICE reporting -0.0001 as an attenuator position, which truncates to "-0"
1644Function LookupAttenNG3(lambda,attenNo,atten_err)
1645        Variable lambda, attenNo, &atten_err
1646       
1647        Variable trans
1648        String attStr="root:myGlobals:Attenuators:ng3att"+num2str(trunc(abs(attenNo)))
1649        String attErrWStr="root:myGlobals:Attenuators:ng3att"+num2str(trunc(abs(attenNo)))+"_err"
1650        String lamStr = "root:myGlobals:Attenuators:ng3lambda"
1651       
1652        if(attenNo == 0)
1653                return (1)              //no attenuation, return trans == 1
1654        endif
1655       
1656        if( (lambda < 4) || (lambda > 20 ) )
1657                Abort "Wavelength out of calibration range (4,20). You must manually enter the absolute parameters"
1658        Endif
1659       
1660        if(!(WaveExists($attStr)) || !(WaveExists($lamStr)) || !(WaveExists($attErrWStr)))
1661                Execute "MakeNG3AttenTable()"
1662        Endif
1663        //just in case creating the tables fails....
1664        if(!(WaveExists($attStr)) || !(WaveExists($lamStr)) )
1665                Abort "Attenuator lookup waves could not be found. You must manually enter the absolute parameters"
1666        Endif
1667       
1668        //lookup the value by interpolating the wavelength
1669        //the attenuator must always be an integer
1670        Wave att = $attStr
1671        Wave attErrW = $attErrWStr
1672        Wave lam = $lamstr
1673        trans = interp(lambda,lam,att)
1674        atten_err = interp(lambda,lam,attErrW)
1675
1676// the error in the tables is % error. return the standard deviation instead
1677        atten_err = trans*atten_err/100
1678               
1679//      Print "trans = ",trans
1680//      Print "trans err = ",atten_err
1681       
1682        return trans
1683End
1684
1685//returns the transmission of the attenuator (at NG7) given the attenuator number
1686//which must be an integer(to select the wave) and given the wavelength.
1687//the wavelength may be any value between 4 and 20 (A), and is interpolated
1688//between calibrated wavelengths for a given attenuator
1689//
1690// this set of tables is also used for NG5 (NG1) SANS instrument - as the attenuator has never been calibrated
1691//
1692// local function
1693//
1694// Mar 2010 - abs() added to attStr to account for ICE reporting -0.0001 as an attenuator position, which truncates to "-0"
1695Function LookupAttenNG7(lambda,attenNo,atten_err)
1696        Variable lambda, attenNo, &atten_err
1697       
1698        Variable trans
1699        String attStr="root:myGlobals:Attenuators:ng7att"+num2str(trunc(abs(attenNo)))
1700        String attErrWStr="root:myGlobals:Attenuators:ng7att"+num2str(trunc(abs(attenNo)))+"_err"
1701        String lamStr = "root:myGlobals:Attenuators:ng7lambda"
1702       
1703        if(attenNo == 0)
1704                return (1)              //no attenuation, return trans == 1
1705        endif
1706       
1707        if( (lambda < 4) || (lambda > 20 ) )
1708                Abort "Wavelength out of calibration range (4,20). You must manually enter the absolute parameters"
1709        Endif
1710       
1711        if(!(WaveExists($attStr)) || !(WaveExists($lamStr)) || !(WaveExists($attErrWStr)))
1712                Execute "MakeNG7AttenTable()"
1713        Endif
1714        //just in case creating the tables fails....
1715        if(!(WaveExists($attStr)) || !(WaveExists($lamStr)) )
1716                Abort "Attenuator lookup waves could not be found. You must manually enter the absolute parameters"
1717        Endif
1718       
1719        //lookup the value by interpolating the wavelength
1720        //the attenuator must always be an integer
1721        Wave att = $attStr
1722        Wave attErrW = $attErrWStr
1723        Wave lam = $lamstr
1724        trans = interp(lambda,lam,att)
1725        atten_err = interp(lambda,lam,attErrW)
1726
1727// the error in the tables is % error. return the standard deviation instead
1728        atten_err = trans*atten_err/100
1729       
1730//      Print "trans = ",trans
1731//      Print "trans err = ",atten_err
1732       
1733        return trans
1734
1735End
1736
1737//returns the transmission of the attenuator (at NGB) given the attenuator number
1738//which must be an integer(to select the wave) and given the wavelength.
1739//the wavelength may be any value between 3 and 30 (A), and is interpolated
1740//between calibrated wavelengths for a given attenuator
1741//
1742// local function
1743//
1744// Mar 2010 - abs() added to attStr to account for ICE reporting -0.0001 as an attenuator position, which truncates to "-0"
1745//
1746// JAN 2013 -- now correct, NGB table has been added, allowing for 3A to 30A
1747//
1748Function LookupAttenNGB(lambda,attenNo,atten_err)
1749        Variable lambda, attenNo, &atten_err
1750       
1751        Variable trans
1752        String attStr="root:myGlobals:Attenuators:NGBatt"+num2str(trunc(abs(attenNo)))
1753        String attErrWStr="root:myGlobals:Attenuators:NGBatt"+num2str(trunc(abs(attenNo)))+"_err"
1754        String lamStr = "root:myGlobals:Attenuators:NGBlambda"
1755       
1756        if(attenNo == 0)
1757                return (1)              //no attenuation, return trans == 1
1758        endif
1759       
1760        if( (lambda < 3) || (lambda > 30 ) )
1761                Abort "Wavelength out of calibration range (3,30). You must manually enter the absolute parameters"
1762        Endif
1763       
1764        if(!(WaveExists($attStr)) || !(WaveExists($lamStr)) || !(WaveExists($attErrWStr)))
1765                Execute "MakeNGBAttenTable()"
1766        Endif
1767        //just in case creating the tables fails....
1768        if(!(WaveExists($attStr)) || !(WaveExists($lamStr)) )
1769                Abort "Attenuator lookup waves could not be found. You must manually enter the absolute parameters"
1770        Endif
1771       
1772        //lookup the value by interpolating the wavelength
1773        //the attenuator must always be an integer
1774        Wave att = $attStr
1775        Wave attErrW = $attErrWStr
1776        Wave lam = $lamstr
1777        trans = interp(lambda,lam,att)
1778        atten_err = interp(lambda,lam,attErrW)
1779
1780// the error in the tables is % error. return the standard deviation instead
1781        atten_err = trans*atten_err/100
1782       
1783//      Print "trans = ",trans
1784//      Print "trans err = ",atten_err
1785       
1786        return trans
1787
1788End
1789
1790// a utility function so that I can get the values from the command line
1791// since the atten_err is PBR
1792//
1793Function PrintAttenuation(instr,lam,attenNo)
1794        String instr
1795        Variable lam,attenNo
1796       
1797        Variable atten_err, attenFactor
1798       
1799        // 22 FEB 2013 - not sure what changed with the writeout of ICE data files... but ....
1800        // to account for ICE occasionally writing out "3" as 2.9998, make sure I can construct
1801        // a single digit -> string "3" to identify the proper wave in the lookup table
1802       
1803        attenNo = round(attenNo)
1804       
1805        strswitch(instr)
1806                case "CGB":
1807                case "NG3":
1808                        attenFactor = LookupAttenNG3(lam,attenNo,atten_err)
1809                        break
1810                case "NG5":
1811                        //using NG7 lookup Table
1812                        attenFactor = LookupAttenNG7(lam,attenNo,atten_err)
1813                        break
1814                case "NG7":
1815                        attenFactor = LookupAttenNG7(lam,attenNo,atten_err)
1816                        break
1817                case "NGA":
1818                case "NGB":
1819                        attenFactor = LookupAttenNGB(lam,attenNo,atten_err)
1820                        break
1821                default:                                                       
1822                        //return error?
1823                        DoAlert 0, "No matching instrument -- PrintAttenuation"
1824                        attenFactor=1
1825        endswitch
1826
1827        Print "atten, err = ", attenFactor, atten_err
1828       
1829        return(0)
1830End
1831
1832
1833
1834//returns the proper attenuation factor based on the instrument (NG3, NG5, or NG7)
1835//NG5 values are taken from the NG7 tables (there is very little difference in the
1836//values, and NG5 attenuators have not been calibrated (as of 8/01)
1837//
1838// filestr is passed from TextRead[3] = the default directory
1839// lam is passed from RealsRead[26]
1840// AttenNo is passed from ReaslRead[3]
1841//
1842// Attenuation factor as defined here is <= 1
1843//
1844// HFIR can pass ("",1,attenuationFactor) and have this function simply
1845// spit back the attenuationFactor (that was read into rw[3])
1846//
1847// called by Correct.ipf, ProtocolAsPanel.ipf, Transmission.ipf
1848//
1849//
1850// as of March 2011, returns the error (one standard deviation) in the attenuation factor as the last parameter, by reference
1851Function AttenuationFactor(fileStr,lam,attenNo,atten_err)
1852        String fileStr
1853        Variable lam,attenNo, &atten_err
1854       
1855        Variable attenFactor=1,loc
1856        String instr=fileStr[1,3]       //filestr is "[NGnSANSn] " or "[NGnSANSnn]" (11 characters total)
1857
1858
1859        // 22 FEB 2013 - not sure what changed with the writeout of ICE data files... but ....
1860        // to account for ICE occasionally writing out "3" as 2.9998, make sure I can construct
1861        // a single digit -> string "3" to identify the proper wave in the lookup table
1862       
1863        attenNo = round(attenNo)
1864       
1865               
1866        strswitch(instr)
1867                case "CGB":
1868                case "NG3":
1869                        attenFactor = LookupAttenNG3(lam,attenNo,atten_err)
1870                        break
1871                case "NG5":
1872                        //using NG7 lookup Table
1873                        attenFactor = LookupAttenNG7(lam,attenNo,atten_err)
1874                        break
1875                case "NG7":
1876                        attenFactor = LookupAttenNG7(lam,attenNo,atten_err)
1877                        break
1878                case "NGA":
1879                case "NGB":
1880                        attenFactor = LookupAttenNGB(lam,attenNo,atten_err)
1881                        break
1882                default:                                                       
1883                        //return error?
1884                        DoAlert 0, "No matching instrument -- PrintAttenuation"
1885                        attenFactor=1
1886        endswitch
1887//      print "instr, lambda, attenNo,attenFactor = ",instr,lam,attenNo,attenFactor
1888        return(attenFactor)
1889End
1890
1891//function called by the popups to get a file list of data that can be sorted
1892// this procedure simply removes the raw data files from the string - there
1893//can be lots of other junk present, but this is very fast...
1894//
1895// could also use the alternate procedure of keeping only file with the proper extension
1896//
1897// another possibility is to get a listing of the text files, but is unreliable on
1898// Windows, where the data file must be .txt (and possibly OSX)
1899//
1900// called by FIT_Ops.ipf, NSORT.ipf, PlotUtils.ipf
1901//
1902Function/S ReducedDataFileList(ctrlName)
1903        String ctrlName
1904
1905        String list="",newList="",item=""
1906        Variable num,ii
1907       
1908        //check for the path
1909        PathInfo catPathName
1910        if(V_Flag==0)
1911                DoAlert 0, "Data path does not exist - pick the data path from the button on the main panel"
1912                Return("")
1913        Endif
1914       
1915        list = IndexedFile(catpathName,-1,"????")
1916       
1917        list = RemoveFromList(ListMatch(list,"*.SA1*",";"), list, ";", 0)
1918        list = RemoveFromList(ListMatch(list,"*.SA2*",";"), list, ";", 0)
1919        list = RemoveFromList(ListMatch(list,"*.SA3*",";"), list, ";", 0)
1920        list = RemoveFromList(ListMatch(list,"*.SA4*",";"), list, ";", 0)               // added JAN 2013 for new guide hall
1921        list = RemoveFromList(ListMatch(list,"*.SA5*",";"), list, ";", 0)
1922        list = RemoveFromList(ListMatch(list,".*",";"), list, ";", 0)
1923        list = RemoveFromList(ListMatch(list,"*.pxp",";"), list, ";", 0)
1924        list = RemoveFromList(ListMatch(list,"*.DIV",";"), list, ";", 0)
1925        list = RemoveFromList(ListMatch(list,"*.GSP",";"), list, ";", 0)
1926        list = RemoveFromList(ListMatch(list,"*.MASK",";"), list, ";", 0)
1927
1928        //remove VAX version numbers
1929        list = RemoveVersNumsFromList(List)
1930        //sort
1931        newList = SortList(List,";",0)
1932
1933        return newlist
1934End
1935
1936// returns a list of raw data files in the catPathName directory on disk
1937// - list is SEMICOLON-delimited
1938//
1939// does it the "cheap" way, simply finding the ".SAn" in the file name
1940// = does not check for proper byte length.
1941//
1942// called by PatchFiles.ipf, Tile_2D.ipf
1943//
1944Function/S GetRawDataFileList()
1945       
1946        //make sure that path exists
1947        PathInfo catPathName
1948        if (V_flag == 0)
1949                Abort "Folder path does not exist - use Pick Path button on Main Panel"
1950        Endif
1951       
1952        String list=IndexedFile(catPathName,-1,"????")
1953        String newList="",item=""
1954        Variable num=ItemsInList(list,";"),ii
1955        for(ii=0;ii<num;ii+=1)
1956                item = StringFromList(ii, list  ,";")
1957                if( stringmatch(item,"*.sa1*") )
1958                        newlist += item + ";"
1959                endif
1960                if( stringmatch(item,"*.sa2*") )
1961                        newlist += item + ";"
1962                endif
1963                if( stringmatch(item,"*.sa3*") )
1964                        newlist += item + ";"
1965                endif
1966                if( stringmatch(item,"*.sa4*") )                // added JAN 2013 for new guide hall
1967                        newlist += item + ";"
1968                endif
1969                if( stringmatch(item,"*.sa5*") )
1970                        newlist += item + ";"
1971                endif
1972                //print "ii=",ii
1973        endfor
1974        newList = SortList(newList,";",0)
1975        return(newList)
1976End
1977
1978// Return the filename that represents the previous or next file.
1979// Input is current filename and increment.
1980// Increment should be -1 or 1
1981// -1 => previous file
1982// 1 => next file
1983Function/S GetPrevNextRawFile(curfilename, prevnext)
1984        String curfilename
1985        Variable prevnext
1986
1987        String filename
1988       
1989        //get the run number
1990        Variable num = GetRunNumFromFile(curfilename)
1991               
1992        //find the next specified file by number
1993        fileName = FindFileFromRunNumber(num+prevnext)
1994
1995        if(cmpstr(fileName,"")==0)
1996                //null return, do nothing
1997                fileName = FindFileFromRunNumber(num)
1998        Endif
1999
2000//      print "in FU "+filename
2001
2002        Return filename
2003End
2004
2005
Note: See TracBrowser for help on using the repository browser.