source: sans/Dev/trunk/NCNR_User_Procedures/Reduction/SANS/RealTimeUpdate_RT.ipf @ 1016

Last change on this file since 1016 was 1016, checked in by srkline, 6 years ago

changes to the calls to GBLoadWave to now use a path and only the file name. Previously I use the full path:name to construct the execute statement.

this is being done to try to act as a workaround for network neighborhood paths in windows 10 (where drives can't be mapped)

File size: 36.6 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=5.0
3#pragma IgorVersion=6.1
4
5//*****************************
6// Vers. 1.0 100401
7//
8// hook function and associated procedures that interact with the user
9// and the RealTime_SANS window
10// -displays pixel counts
11// - displays Q, qx, qy values
12// - displays q axes and pixel axes
13//
14// - of course, displays the detector image, w/ nice colors, legend, sliders to adjust color mapping
15// and a control bar to let the user adjust scaling, do averaging...
16//
17// as of 110101, the help file has not been written
18//
19//
20//
21// for Summer School 2011 --- a fake update
22// 1) set the flag
23// Variable/G root:myGlobals:gFakeUpdate=1
24// 2) load any data file as the RT data
25// 3) get SASCALC set up to the correct configuration
26// 4) run ClearRTFolder() to empty out the SAS folder, and update the display
27// 5) start the updating
28//
29// -- generate a script that will (from scratch) open everything needed, open/hide windows
30// as needed, and be sure that all of the files, varaibles, etc. that are needed are actually there.
31//
32// --needs SASCALC + an analysis model for it to work, and still some details to work out for
33// smooth initialization of the process, but it should work.
34//
35//
36//
37Proc Init_FakeRT()
38        pInit_FakeRT()
39End
40
41Proc Clear_RT_Folder()
42        ClearRTFolder()
43End
44
45//
46//
47//*****************************
48
49// takes care of all of the necessary initialization for the RT control process
50// creates the folders, etc. that are needed for the SANS reduction package as well, but the end user
51// doesn't need to see this.
52//
53// only used for testing - as this will re-initialize everything, including globals used as preferences
54//
55Proc Init_for_RealTime()
56        // initialize the reduction folders as for normal SANS Reduction, but don't draw the main Reduction control panel
57        DoWindow/K RT_Panel
58        InitFolders()
59        InitFakeProtocols()
60        InitGlobals()
61        InitFacilityGlobals()
62
63        // specific for RealTime display
64        //set the current display type to RealTime
65        String/G root:myGlobals:gDataDisplayType = "RealTime"
66        // draw the RealTime control panel
67        Show_RealTime_Panel()
68End
69
70// Proc to bring the RT control panel to the front, always initializes the panel
71// - always initialize to make sure that the background task is properly set
72//
73Proc Show_RealTime_Panel()
74        Init_RT()               //always init, data folders and globals are created here
75        DoWindow/F RT_Panel
76        if(V_flag==0)
77                RT_Panel()
78        Endif
79End
80
81// folder and globals that are needed ONLY for the RT process
82//
83Function Init_RT()
84        //create folders
85        NewDataFolder/O root:Packages:NIST:RealTime
86        NewDataFolder/O/S root:myGlobals:RT
87        //create default globals only if they don't already exist, so you don't overwrite user-entered values.
88        NVAR/Z xCtr=xCtr
89        if(NVAR_Exists(xctr)==0)
90                Variable/G xCtr=110                     //pixels
91        endif
92        NVAR/Z yCtr=yCtr
93        if(NVAR_Exists(yCtr)==0)
94                Variable/G yCtr=64
95        endif
96        NVAR/Z SDD=SDD
97        if(NVAR_Exists(SDD)==0)
98                Variable/G SDD=3.84                                     //in meters
99        endif
100        NVAR/Z lambda=lambda
101        if(NVAR_Exists(lambda)==0)
102                Variable/G lambda=6                             //angstroms
103        endif
104        NVAR/Z updateInt=updateInt
105        if(NVAR_Exists(updateInt)==0)
106                Variable/G updateInt=5                  //seconds
107        endif
108        NVAR/Z timeout=timeout
109        if(NVAR_Exists(timeout)==0)
110                Variable/G timeout=300          //seconds
111        endif
112        NVAR/Z elapsed=elapsed
113        if(NVAR_Exists(elapsed)==0)
114                Variable/G elapsed=0
115        endif
116        NVAR/Z totalCounts=totalCounts          //total detector counts
117        if(NVAR_Exists(totalCounts)==0)
118                Variable/G totalCounts=0
119        endif
120        NVAR/Z countTime = root:myGlobals:RT:countTime
121        if(NVAR_Exists(countTime)==0)
122                Variable/G countTime = 0
123        endif
124        NVAR/Z countRate = root:myGlobals:RT:countRate
125        if(NVAR_Exists(countRate)==0)
126                Variable/G countRate = 0
127        endif
128        NVAR/Z monitorCountRate = root:myGlobals:RT:monitorCountRate
129        if(NVAR_Exists(monitorCountRate)==0)
130                Variable/G monitorCountRate = 0
131        endif
132        NVAR/Z monitorCounts = root:myGlobals:RT:monitorCounts
133        if(NVAR_Exists(monitorCounts)==0)
134                Variable/G monitorCounts = 0
135        endif
136       
137        // set the explicit path to the data file on "relay" computer (the user will be propmted for this)
138        SVAR/Z RT_fileStr=RT_fileStr
139        if(SVAR_Exists(RT_fileStr)==0)
140                String/G RT_fileStr=""
141        endif
142
143        // set the background task
144        AssignBackgroundTask()
145       
146        SetDataFolder root:
147End
148
149//sets the background task and period (in ticks)
150//
151Function AssignBackgroundTask()
152
153        Variable updateInt=NumVarOrDefault("root:myGlobals:RT:updateInt",5)
154        // set the background task
155        SetBackground BkgUpdateHST()
156        CtrlBackground period=(updateInt*60),noBurst=0          //noBurst prevents rapid "catch-up calls
157        return(0)
158End
159
160//draws the RT panel and enforces bounds on the SetVariable controls for update period and timeout
161//
162Proc RT_Panel()
163        PauseUpdate; Silent 1           // building window...
164        NewPanel /W=(300,350,602,580) /K=2
165        DoWindow/C RT_Panel
166        DoWindow/T RT_Panel,"Real Time Display Controls"
167        ModifyPanel cbRGB=(65535,52428,6168)
168        SetDrawLayer UserBack
169        SetDrawEnv fstyle= 1
170        DrawText 26,21,"Enter values for real-time display"
171        Button bkgStart,pos={171,54},size={120,20},proc=UpdateHSTButton,title="Start Updating"
172        Button bkgStart,help={"Starts or stops the updating of the real-time SANS image"}
173//      SetVariable setvar_0,pos={15,29},size={100,15},proc=RT_Param_SetVarProc,title="X Center"
174//      SetVariable setvar_0,help={"Set this to the current beamcenter x-coordinate (in pixels)"}
175//      SetVariable setvar_0,limits={0,128,0},value= root:myGlobals:RT:xCtr
176//      SetVariable setvar_1,pos={14,46},size={100,15},proc=RT_Param_SetVarProc,title="Y Center"
177//      SetVariable setvar_1,help={"Set this to the current beamcenter y-coordinate (in pixels)"}
178//      SetVariable setvar_1,limits={0,128,0},value= root:myGlobals:RT:yCtr
179//      SetVariable setvar_2,pos={14,64},size={100,15},proc=RT_Param_SetVarProc,title="SDD (m)"
180//      SetVariable setvar_2,help={"Set this to the sample-to-detector distance of the current instrument configuration"}
181//      SetVariable setvar_2,limits={0,1600,0},value= root:myGlobals:RT:SDD
182//      SetVariable setvar_3,pos={15,82},size={100,15},proc=RT_Param_SetVarProc,title="Lambda (A)"
183//      SetVariable setvar_3,help={"Set this to the wavelength of the current instrument configuration"}
184//      SetVariable setvar_3,limits={0,30,0},value= root:myGlobals:RT:lambda
185        SetVariable setvar_4,pos={11,31},size={150,20},proc=UpdateInt_SetVarProc,title="Update Interval (s)"
186        SetVariable setvar_4,help={"This is the period of the update"}
187        SetVariable setvar_4,limits={1,3600,0},value= root:myGlobals:RT:updateInt
188//      SetVariable setvar_5,pos={11,56},size={150,20},title="Timeout Interval (s)"
189//      SetVariable setvar_5,help={"After the timeout interval has expired, the update process will automatically stop"}
190//      SetVariable setvar_5,limits={1,3600,0},value= root:myGlobals:RT:timeout
191        Button button_1,pos={170,29},size={120,20},proc=LoadRTButtonProc,title="Load Live Data"
192        Button button_1,help={"Load the data file for real-time display"}
193        Button button_2,pos={250,2},size={30,20},proc=RT_HelpButtonProc,title="?"
194        Button button_2,help={"Display the help file for real-time controls"}
195        //Button button_3,pos={230,80},size={60,20},proc=RT_DoneButtonProc,title="Done"
196        //Button button_3,help={"Closes the panel and stops the updating process"}
197        SetVariable setvar_6,pos={11,105},size={250,20},title="Total Detector Counts"
198        SetVariable setvar_6,help={"Total counts on the detector, as displayed"},noedit=1
199        SetVariable setvar_6,limits={0,Inf,0},value= root:myGlobals:RT:totalCounts
200        SetVariable setvar_7,pos={11,82},size={250,20},title="                  Count Time"
201        SetVariable setvar_7,help={"Count time, as displayed"},noedit=1
202        SetVariable setvar_7,limits={0,Inf,0},value= root:myGlobals:RT:countTime
203        SetVariable setvar_8,pos={11,127},size={250,20},title="  Detector Count Rate"
204        SetVariable setvar_8,help={"Count rate, as displayed"},noedit=1
205        SetVariable setvar_8,limits={0,Inf,0},value= root:myGlobals:RT:countRate
206        SetVariable setvar_9,pos={11,149},size={250,20},title="           Monitor Counts"
207        SetVariable setvar_9,help={"Count rate, as displayed"},noedit=1
208        SetVariable setvar_9,limits={0,Inf,0},value= root:myGlobals:RT:monitorCounts
209        SetVariable setvar_10,pos={11,171},size={250,20},title="    Monitor Count Rate"
210        SetVariable setvar_10,help={"Count rate, as displayed"},noedit=1
211        SetVariable setvar_10,limits={0,Inf,0},value= root:myGlobals:RT:monitorCountRate
212EndMacro
213
214//
215Proc RT_HelpButtonProc(ctrlName) : ButtonControl
216        String ctrlName
217//      DoAlert 0,"the help file has not been written yet :-("
218        DisplayHelpTopic/Z/K=1 "SANS Data Reduction Tutorial[Real Time Data Display]"
219End
220
221//close the panel gracefully, and stop the background task if necessary
222//
223Proc RT_DoneButtonProc(ctrlName) : ButtonControl
224        String ctrlName
225       
226        BackgroundInfo
227        if(V_Flag==2)           //task is currently running
228                CtrlBackground stop
229        endif
230        DoWindow/K RT_Panel
231End
232
233//prompts for the RT data file - only needs to be set once, then the user can start/stop
234//
235Function LoadRTButtonProc(ctrlName) : ButtonControl
236        String ctrlName
237
238        DoAlert 0,"The RealTime detector image is located on charlotte"
239        Read_RT_File("Select the Live Data file")
240        return(0)
241End
242
243// Sets "fake" header information to allow qx,qy scales on the graph, and to allow
244// averaging to be done on the real-time dataset
245//
246// keep in mind that only the select bits of header information that is USER-SUPPLIED
247// on the panel is available for calculations. The RT data arrives at the relay computer
248// with NO header, only the 128x128 data....
249//
250// see also FillFakeHeader() for a few constant header values ...
251//
252//
253// check on a case-by-case basis
254Function RT_Param_SetVarProc(ctrlName,varNum,varStr,varName) : SetVariableControl
255        String ctrlName
256        Variable varNum
257        String varStr
258        String varName
259
260        Wave rw=$"root:Packages:NIST:RealTime:RealsRead"
261        if(WaveExists(rw)==0)
262                return(1)
263        Endif
264        strswitch(ctrlName)     // string switch
265                case "setvar_0":                //xCtr
266                        rw[16]=varNum
267                        break   
268                case "setvar_1":                //yCtr
269                        rw[17]=varNum
270                        break   
271                case "setvar_2":                //SDD
272                        rw[18]=varNum
273                        break
274                case "setvar_3":                //lambda
275                        rw[26]=varNum
276                        break
277        endswitch
278        //only update the graph if it is open, and is a RealTime display...
279        if(WinType("SANS_Data")==0)
280                return(0) //SANS_Data window not open
281        Endif
282        SVAR type=root:myGlobals:gDataDisplayType
283        if(cmpstr("RealTime",type)!=0)
284                return(0)               //display not RealTime
285        Endif
286        fRawWindowHook()                //force a redraw of the graph
287        DoWindow/F RT_Panel             //return panel to the front
288        return(0)
289End
290
291// (re)-sets the period of the update background task
292//
293Function UpdateInt_SetVarProc(ctrlName,varNum,varStr,varName) : SetVariableControl
294        String ctrlName
295        Variable varNum
296        String varStr
297        String varName
298
299//      BackgroundInfo
300//      if(V_flag==2)
301//              CtrlBackground stop
302//      Endif
303
304        // quite surprised that you can change the period of repeat while the task is active
305        CtrlBackground period=(varNum*60),noBurst=1
306        return(0)
307End
308
309
310/////////////////////////////
311//simple, main entry procedure that will load a HST sans data file (not a work file)
312//into the RealTime dataFolder
313//(typically called from main panel button)
314//
315//(ununsed)
316Proc Load_RT_Data()
317        String msgStr = "Select a RT Ordela data file"
318        Read_RT_File(msgStr)
319End
320
321//function called by the main entry procedure (the load button)
322//sets global display variable, reads in the data, and displays it
323//aborts if no file was selected
324//
325//(re)-sets the GLOBAL path:filename of the RT file to update
326// also resets the path to the RT file, so that the dialog brings you back to the right spot
327//
328// reads the data in if all is OK
329//
330Function Read_RT_File(msgStr)
331        String msgStr
332
333        String filename="",pathStr=""
334        Variable refnum
335
336        //check for the path
337        PathInfo RT_Path
338        If(V_Flag==1)           //      /D does not open the file
339                Open/D/R/T="????"/M=(msgStr)/P=RT_Path refNum
340        else
341                Open/D/R/T="????"/M=(msgStr) refNum
342        endif
343        filename = S_FileName           //get the filename, or null if canceled from dialog
344        if(strlen(filename)==0)
345                //user cancelled, abort
346                SetDataFolder root:
347                Abort "No file selected, action aborted"
348        Endif
349        //set the globals and reset the RT_Path value
350        pathStr = GetPathStrFromfullName(filename)
351        NewPath/O RT_Path,pathStr
352        Variable/G root:Packages:NIST:RealTime:gIsLogScale = 0          //force data to linear scale (1st read)
353        String/G root:myGlobals:RT:RT_fileStr=filename  //full path:file of the Run.hst file to re-read
354        //read in the data
355        //ReadOrdelaHST(filename)
356       
357        //ReadHeaderAndData(filename)
358        //Raw_to_Work("RealTime")
359        ReadRTAndData(filename)
360
361        //the calling macro must change the display type
362        String/G root:myGlobals:gDataDisplayType="RealTime"             //displayed data type is RealTime
363       
364        //FillFakeHeader()              //uses info on the panel, if available
365
366        //data is displayed here, and needs header info
367        WAVE data = $"root:Packages:NIST:RealTime:data"
368        NVAR totCounts = root:myGlobals:RT:totalCounts
369        NVAR countTime = root:myGlobals:RT:countTime
370        NVAR countRate = root:myGlobals:RT:countRate
371        NVAR monitorCounts = root:myGlobals:RT:monitorCounts
372        NVAR monitorCountRate = root:myGlobals:RT:monitorCountRate
373        SVAR/Z title = root:myGlobals:gCurDispFile
374       
375        title="Real-Time : "+filename
376        //sum the total counts, global variable will automatically update
377        WAVE/Z linear_data = $"root:Packages:NIST:RealTime:linear_data"
378        if(WaveExists(linear_data))
379                totCounts = sum(linear_data, -Inf, Inf )
380        else
381                WAVE/Z data = $"root:Packages:NIST:RealTime:data"
382                totCounts = sum(data, -Inf, Inf )
383        endif
384        //Update other live values
385        Wave intw = root:Packages:NIST:RealTime:IntegersRead
386        Wave realw = root:Packages:NIST:RealTime:RealsRead
387        countTime = intw[2]
388        countRate = totCounts/countTime
389        monitorCounts = realw[0]
390        monitorCountRate = monitorCounts/countTime
391
392        fRawWindowHook()
393       
394        // set the SANS_Data graph to "live" mode to allow fast updating
395        //fRawWindowHook just drew the graph, so it should exist
396        ModifyGraph/W=SANS_Data live=1          //not much speed help...
397       
398        return(0)
399End
400
401//function that does the guts of reading the binary data file
402//fname is the full path:name;vers required to open the file
403//The final root:Packages:NIST:RealTime:data wave is the real
404//neutron counts and can be directly used
405//
406//returns 0 if read was ok
407//returns 1 if there was an error
408Function ReadOrdelaHST(fname)
409        String fname
410        //this function is for reading in RealTime data only, so it will always put data in RealTime folder
411        SetDataFolder "root:Packages:NIST:RealTime"     
412        //keep a string with the filename in the RealTime folder
413        String/G root:Packages:NIST:RealTime:fileList = "Real-Time Data Display"
414        //get log/linear state based on SANS_Data window
415        Variable isLogScale=NumVarOrDefault("root:Packages:NIST:RealTime:gIsLogScale", 0)
416        Variable/G root:Packages:NIST:RealTime:gIsLogScale = isLogScale         //creates if needed, "sets" to cur val if already exists
417       
418        Variable refNum=0,ii,p1,p2,tot,num=128
419        String str=""
420        Make/O/T/N=11 hdrLines
421        Make/O/I/N=(num*num) a1         // /I flag = 32 bit integer data
422       
423        //full filename and path is now passed in...
424        //actually open the file
425        Open/R/Z refNum as fname                // /Z flag means I must handle open errors
426        if(refnum==0)           //FNF error, get out
427                DoAlert 0,"Could not find file: "+fname
428                Close/A
429                return(1)
430        endif
431        if(V_flag!=0)
432                DoAlert 0,"File open error: V_flag="+num2Str(V_Flag)
433                Close/A
434                return(1)
435        Endif
436        // as of 12MAY03, the run.hst for real-time display has no header lines (M. Doucet)
437//      for(ii=0;ii<11;ii+=1)           //read (or skip) 11 header lines
438//              FReadLine refnum,str
439//              hdrLines[ii]=str
440//      endfor
441        // 4-byte integer binary data follows, num*num integer values
442        FBinRead/B=3/F=3 refnum,a1
443        //     
444        Close refnum
445       
446        //we want only the first [0,127][0,127] quadrant of the 256x256 image
447        // this is done most quickly by two successive redimension operations
448        // (the duplicate is for testing only)
449        //final redimension can make the data FP if desired..
450        //Redimension/N=(256,256) a1
451        Redimension/N=(128,128) a1
452
453        if(exists("root:Packages:NIST:RealTime:data")!=1)               //wave DN exist
454                Make/O/N=(128,128) $"root:Packages:NIST:RealTime:data"
455        endif
456        WAVE data=$"root:Packages:NIST:RealTime:data"
457        Duplicate/O data,$"root:Packages:NIST:RealTime:linear_data"
458        WAVE lin_data=$"root:Packages:NIST:RealTime:linear_data"
459        lin_data=a1
460        if(isLogScale)
461                data=log(a1)
462        else
463                data=a1
464        Endif
465       
466        KillWaves/Z a1 
467       
468        //return the data folder to root
469        SetDataFolder root:
470       
471        Return 0
472End
473
474// fills the "default" fake header so that the SANS Reduction machinery does not have to be altered
475// pay attention to what is/not to be trusted due to "fake" information
476//
477Function FillFakeHeader()
478
479        Make/O/N=23 $"root:Packages:NIST:RealTime:IntegersRead"
480        Make/O/N=52 $"root:Packages:NIST:RealTime:RealsRead"
481        Make/O/T/N=11 $"root:Packages:NIST:RealTime:TextRead"
482       
483        Wave intw=$"root:Packages:NIST:RealTime:IntegersRead"
484        Wave realw=$"root:Packages:NIST:RealTime:RealsRead"
485        Wave/T textw=$"root:Packages:NIST:RealTime:TextRead"
486       
487        //Put in appropriate "fake" values
488        // first 4 are user-defined on the Real Time control panel, so user has the opportunity to change these values.
489        //
490        realw[16]=NumVarOrDefault("root:myGlobals:RT:xCtr", 64.5)               //xCtr(pixels)
491        realw[17]=NumVarOrDefault("root:myGlobals:RT:yCtr", 64.5)               //yCtr (pixels)
492        realw[18]=NumVarOrDefault("root:myGlobals:RT:SDD", 5)           //SDD (m)
493        realw[26]=NumVarOrDefault("root:myGlobals:RT:lambda", 6)                //wavelength (A)
494        //
495        // necessary values
496        realw[10]=5                     //detector calibration constants, needed for averaging
497        realw[11]=10000
498        realw[13]=5
499        realw[14]=10000
500        //
501        // used in the resolution calculation, ONLY here to keep the routine from crashing
502        realw[20]=65            //det size
503        realw[27]=0.15  //delta lambda
504        realw[21]=50.8  //BS size
505        realw[23]=50            //A1
506        realw[24]=12.7  //A2
507        realw[25]=8.57  //A1A2 distance
508        realw[4]=1              //trans
509        realw[3]=0              //atten
510        realw[5]=0.1            //thick
511        //
512        //
513        realw[0]=1e8            //def mon cts
514
515        // fake values to get valid deadtime and detector constants
516        //
517        textw[9]="ORNL  "               //6 characters
518        textw[3]="[NGxSANS00]"  //11 chars, NGx will return default values for atten trans, deadtime...
519       
520        return(0)
521End
522
523// action procedure to start/stop the updating process.
524//checks for update display graph, current background task, etc..
525// then update the button and at last controls the background task
526//
527Function UpdateHSTButton(ctrlName) : ButtonControl
528        String ctrlName
529       
530        //check that the RT window is open, and that the display type is "RealTime"
531        if(WinType("SANS_Data")==0)
532                return(1) //SANS_Data window not open
533        Endif
534        SVAR type=root:myGlobals:gDataDisplayType
535        if(cmpstr("RealTime",type)!=0)
536                return(1)               //display not RealTime
537        Endif
538        //check the current state of the background task
539        BackgroundInfo          //returns 0 if no task defined, 1 if idle, 2 if running
540        if(V_flag==0)
541                AssignBackgroundTask()
542        Endif
543       
544        String Str=""
545        //control the task, and update the button text
546        if (cmpstr(ctrlName,"bkgStart") == 0)
547                Button $ctrlName,win=RT_Panel,title="Stop Updating",rename=bkgStop             
548        //      Start the updating - BkgUpdateHST() has been designated as the background task
549                CtrlBackground start
550        else
551                Button $ctrlName,win=RT_Panel,title="Start Updating",rename=bkgStart
552                NVAR elapsed=root:myGlobals:RT:elapsed
553                elapsed=0       //reset the timer
554        //      Stop the updating
555                CtrlBackground stop
556        endif
557        return(0)
558End
559
560
561// THIS IS THE BACKGROUND TASK
562//
563// simply re-reads the designated .hst file (which can be located anywhere, as long as it
564// appears as a local disk)
565// return value of 0 continues background execution
566// return value of 1 turns background task off
567//
568Function BkgUpdateHST()
569
570        WAVE data = $"root:Packages:NIST:RealTime:data"
571        Wave intw = root:Packages:NIST:RealTime:IntegersRead
572        Wave realw = root:Packages:NIST:RealTime:RealsRead
573        Wave/T textw = root:Packages:NIST:RealTime:TextRead
574
575        NVAR elapsed=root:myGlobals:RT:elapsed
576        NVAR timeout=root:myGlobals:RT:timeout
577        NVAR updateInt=root:myGlobals:RT:updateInt
578        NVAR totCounts = root:myGlobals:RT:totalCounts
579        NVAR countTime = root:myGlobals:RT:countTime
580        NVAR countRate = root:myGlobals:RT:countRate
581        NVAR monitorCounts = root:myGlobals:RT:monitorCounts
582        NVAR monitorCountRate = root:myGlobals:RT:monitorCountRate
583        SVAR/Z title=root:myGlobals:gCurDispFile
584        SVAR sampledesc=root:myGlobals:gCurTitle
585                       
586        Variable err=0
587//      Variable t1=ticks
588        SVAR RT_fileStr=root:myGlobals:RT:RT_fileStr
589       
590        elapsed += updateInt
591//      get the new data by re-reading the datafile from the relay computer
592//      if(elapsed<timeout)
593       
594                if(WinType("SANS_Data")==0)
595                        Button $"bkgStop",win=RT_Panel,title="Start Updating",rename=bkgStart
596                        return(1) //SANS_Data window not open
597                Endif
598                SVAR type=root:myGlobals:gDataDisplayType
599                if(cmpstr("RealTime",type)!=0)
600                        Button $"bkgStop",win=RT_Panel,title="Start Updating",rename=bkgStart
601                        return(1)               //display not RealTime
602                Endif
603                title="Reading new data..."
604                ControlUpdate/W=SANS_Data/A
605               
606                //Copy file from ICE server
607                //ExecuteScriptText/B "\"C:\\Documents and Settings\\user\\Desktop\\ICE Test\\getdata.bat\""
608               
609                //err = ReadOrdelaHST(RT_fileStr)
610                //err = ReadHeaderAndData(RT_fileStr)
611                NVAR/Z gFakeUpdate = root:myGlobals:gFakeUpdate
612                if(NVAR_Exists(gFakeUpdate) && gFakeUpdate == 1)
613                        err = FakeUpdate()
614                else
615                        err = ReadRTAndData(RT_fileStr)
616                endif
617               
618                if(err==1)
619                        Button $"bkgStop",win=RT_Panel,title="Start Updating",rename=bkgStart
620                        return(err)     //file not found
621                Endif
622                //Raw_to_work("RealTime")
623                // for testing only...
624//              data += abs(enoise(data))
625                //
626                MapSliderProc("reset", 0, 1)
627               
628                title=textw[0]
629                sampledesc=textw[6]
630                //sum the total counts, global variable will automatically update
631                WAVE/Z linear_data = $"root:Packages:NIST:RealTime:linear_data"
632                if(WaveExists(linear_data))
633                        totCounts = sum(linear_data, -Inf, Inf )
634                else
635                        WAVE/Z data = $"root:Packages:NIST:RealTime:data"
636                        totCounts = sum(data, -Inf, Inf )
637                endif
638                //Update other live values
639                countTime = intw[2]
640                countRate = totCounts/countTime
641                monitorCounts = realw[0]
642                monitorCountRate = monitorCounts/countTime
643               
644                //if the 1D plot is open, update this too
645                // make sure folders exist first
646                if(!DataFolderExists("root:myGlobals:Drawing"))
647                        Execute "InitializeAveragePanel()"
648                endif
649               
650                // check for the mask, generate one? Two pixels all around
651                if(WaveExists($"root:Packages:NIST:MSK:data") == 0)
652                        Print "There is no mask file loaded (WaveExists)- the data is not masked"
653                        Make/O/N=(128,128) root:Packages:NIST:MSK:data
654                        Wave mask = root:Packages:NIST:MSK:data
655                        mask[0][] = 1
656                        mask[1][] = 1
657                        mask[126][] = 1
658                        mask[127][] = 1
659                       
660                        mask[][0] = 1
661                        mask[][1] = 1
662                        mask[][126] = 1
663                        mask[][127] = 1
664                endif
665               
666                // update the 1d plot
667                if(WinType("Plot_1d")==1)               //if the 1D graph exists
668                        Panel_DoAverageButtonProc("")   
669                        DoWindow/F SANS_Data   
670                endif
671                ///////
672               
673//              print "Bkg task time (s) =",(ticks-t1)/60.15
674                return 0                //keep the process going
675//      else
676//              //timeout, stop the process, reset the button label
677//              elapsed=0
678//              Button $"bkgStop",win=RT_Panel,title="Start Updating",rename=bkgStart
679//              return(1)
680//      endif
681       
682End
683
684Function ReadRTAndData(fname)
685        String fname
686        //this function is for reading in RAW data only, so it will always put data in RAW folder
687        String curPath = "root:Packages:NIST:RealTime:"
688        SetDataFolder curPath           //use the full path, so it will always work
689        //Variable/G root:Packages:NIST:RAW:gIsLogScale = 0             //initial state is linear, keep this in RAW folder
690        Variable isLogScale=NumVarOrDefault("root:Packages:NIST:RealTime:gIsLogScale", 0)
691        Variable/G root:Packages:NIST:RealTime:gIsLogScale = isLogScale
692       
693        Variable refNum,integer,realval
694        String sansfname,textstr
695       
696        Make/O/N=23 $"root:Packages:NIST:RealTime:IntegersRead"
697        Make/O/N=52 $"root:Packages:NIST:RealTime:RealsRead"
698        Make/O/T/N=11 $"root:Packages:NIST:RealTime:TextRead"
699        Make/O/N=7 $"root:Packages:NIST:RealTime:LogicalsRead"
700
701       
702        Wave intw=$"root:Packages:NIST:RealTime:IntegersRead"
703        Wave realw=$"root:Packages:NIST:RealTime:RealsRead"
704        Wave/T textw=$"root:Packages:NIST:RealTime:TextRead"
705        Wave logw=$"root:Packages:NIST:RealTime:LogicalsRead"
706       
707        //***NOTE ****
708        // the "current path" gets mysteriously reset to "root:" after the SECOND pass through
709        // this read routine, after the open dialog is presented
710        // the "--read" waves end up in the correct folder, but the data does not! Why?
711        //must re-set data folder before writing data array (done below)
712       
713        //full filename and path is now passed in...
714        //actually open the file
715        Open/R refNum as fname
716        //skip first two bytes (VAX record length markers, not needed here)
717        FSetPos refNum, 2
718        //read the next 21 bytes as characters (fname)
719        FReadLine/N=21 refNum,textstr
720        textw[0]= textstr
721        //read four i*4 values  /F=3 flag, B=3 flag
722        FBinRead/F=3/B=3 refNum, integer
723        intw[0] = integer
724        //
725        FBinRead/F=3/B=3 refNum, integer
726        intw[1] = integer
727        //
728        FBinRead/F=3/B=3 refNum, integer
729        intw[2] = integer
730        //
731        FBinRead/F=3/B=3 refNum, integer
732        intw[3] = integer
733        // 6 text fields
734        FSetPos refNum,55               //will start reading at byte 56
735        FReadLine/N=20 refNum,textstr
736        textw[1]= textstr
737        FReadLine/N=3 refNum,textstr
738        textw[2]= textstr
739        FReadLine/N=11 refNum,textstr
740        textw[3]= textstr
741        FReadLine/N=1 refNum,textstr
742        textw[4]= textstr
743        FReadLine/N=8 refNum,textstr
744        textw[5]= textstr
745        FReadLine/N=60 refNum,textstr
746        textw[6]= textstr
747       
748        //3 integers
749        FSetPos refNum,174
750        FBinRead/F=3/B=3 refNum, integer
751        intw[4] = integer
752        FBinRead/F=3/B=3 refNum, integer
753        intw[5] = integer
754        FBinRead/F=3/B=3 refNum, integer
755        intw[6] = integer
756       
757        //2 integers, 3 text fields
758        FSetPos refNum,194
759        FBinRead/F=3/B=3 refNum, integer
760        intw[7] = integer
761        FBinRead/F=3/B=3 refNum, integer
762        intw[8] = integer
763        FReadLine/N=6 refNum,textstr
764        textw[7]= textstr
765        FReadLine/N=6 refNum,textstr
766        textw[8]= textstr
767        FReadLine/N=6 refNum,textstr
768        textw[9]= textstr
769       
770        //2 integers
771        FSetPos refNum,244
772        FBinRead/F=3/B=3 refNum, integer
773        intw[9] = integer
774        FBinRead/F=3/B=3 refNum, integer
775        intw[10] = integer
776       
777        //2 integers
778        FSetPos refNum,308
779        FBinRead/F=3/B=3 refNum, integer
780        intw[11] = integer
781        FBinRead/F=3/B=3 refNum, integer
782        intw[12] = integer
783       
784        //2 integers
785        FSetPos refNum,332
786        FBinRead/F=3/B=3 refNum, integer
787        intw[13] = integer
788        FBinRead/F=3/B=3 refNum, integer
789        intw[14] = integer
790       
791        //3 integers
792        FSetPos refNum,376
793        FBinRead/F=3/B=3 refNum, integer
794        intw[15] = integer
795        FBinRead/F=3/B=3 refNum, integer
796        intw[16] = integer
797        FBinRead/F=3/B=3 refNum, integer
798        intw[17] = integer
799       
800        //1 text field - the file association for transmission are the first 4 bytes
801        FSetPos refNum,404
802        FReadLine/N=42 refNum,textstr
803        textw[10]= textstr
804       
805        //1 integer
806        FSetPos refNum,458
807        FBinRead/F=3/B=3 refNum, integer
808        intw[18] = integer
809       
810        //4 integers
811        FSetPos refNum,478
812        FBinRead/F=3/B=3 refNum, integer
813        intw[19] = integer
814        FBinRead/F=3/B=3 refNum, integer
815        intw[20] = integer
816        FBinRead/F=3/B=3 refNum, integer
817        intw[21] = integer
818        FBinRead/F=3/B=3 refNum, integer
819        intw[22] = integer
820       
821        //Get Logicals 
822        //Read logicals as int - ICE is writing integers here
823        FSetPos refNum,304
824        FBinRead/F=3/B=3 refNum, integer
825        logw[0] = integer
826        FSetPos refNum,316
827        FBinRead/F=3/B=3 refNum, integer
828        logw[1] = integer       
829        FSetPos refNum,340
830        FBinRead/F=3/B=3 refNum, integer
831        logw[2] = integer
832        FSetPos refNum,344
833        FBinRead/F=3/B=3 refNum, integer
834        logw[3] = integer               
835        FSetPos refNum,446
836        FBinRead/F=3/B=3 refNum, integer
837        logw[4] = integer
838        FSetPos refNum,462
839        FBinRead/F=3/B=3 refNum, integer
840        logw[5] = integer
841        FSetPos refNum,466
842        FBinRead/F=3/B=3 refNum, integer
843        logw[6] = integer               
844
845       
846        Close refNum
847       
848        //now get all of the reals
849        //
850        //Do all the GBLoadWaves at the end
851        //
852        //FBinRead Cannot handle 32 bit VAX floating point
853        //GBLoadWave, however, can properly read it
854        String GBLoadStr="GBLoadWave/O/N=tempGBwave/T={2,2}/J=2/W=1/Q/P=catPathName"
855        String strToExecute
856        //append "/S=offset/U=numofreals" to control the read
857        // then append fname to give the full file path
858        // then execute
859       
860        Variable a=0,b=0
861       
862        SetDataFolder curPath
863       
864        // 4 R*4 values
865        strToExecute = GBLoadStr + "/S=39/U=4" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
866        Execute/Z strToExecute
867        Wave w=$"root:Packages:NIST:RealTime:tempGBWave0"
868        b=4     //num of reals read
869        realw[a,a+b-1] = w[p-a]
870        a+=b
871       
872        // 4 R*4 values
873        SetDataFolder curPath
874        strToExecute = GBLoadStr + "/S=158/U=4" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
875        Execute/Z strToExecute
876        b=4     
877        realw[a,a+b-1] = w[p-a]
878        a+=b
879
880///////////
881        // 2 R*4 values
882        SetDataFolder curPath
883        strToExecute = GBLoadStr + "/S=186/U=2" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
884        Execute/Z strToExecute
885        b=2     
886        realw[a,a+b-1] = w[p-a]
887        a+=b
888
889        // 6 R*4 values
890        SetDataFolder curPath
891        strToExecute = GBLoadStr + "/S=220/U=6" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
892        Execute/Z strToExecute
893        b=6     
894        realw[a,a+b-1] = w[p-a]
895        a+=b
896       
897        // 13 R*4 values
898        SetDataFolder curPath
899        strToExecute = GBLoadStr + "/S=252/U=13" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
900        Execute/Z strToExecute
901        b=13
902        realw[a,a+b-1] = w[p-a]
903        a+=b
904       
905        // 3 R*4 values
906        SetDataFolder curPath
907        strToExecute = GBLoadStr + "/S=320/U=3" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
908        Execute/Z strToExecute
909        b=3     
910        realw[a,a+b-1] = w[p-a]
911        a+=b
912       
913        // 7 R*4 values
914        SetDataFolder curPath
915        strToExecute = GBLoadStr + "/S=348/U=7" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
916        Execute/Z strToExecute
917        b=7
918        realw[a,a+b-1] = w[p-a]
919        a+=b
920       
921        // 4 R*4 values
922        SetDataFolder curPath
923        strToExecute = GBLoadStr + "/S=388/U=4" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
924        Execute/Z strToExecute
925        b=4     
926        realw[a,a+b-1] = w[p-a]
927        a+=b
928       
929        // 2 R*4 values
930        SetDataFolder curPath
931        strToExecute = GBLoadStr + "/S=450/U=2" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
932        Execute/Z strToExecute
933        b=2
934        realw[a,a+b-1] = w[p-a]
935        a+=b
936       
937        // 2 R*4 values
938        SetDataFolder curPath
939        strToExecute = GBLoadStr + "/S=470/U=2" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
940        Execute/Z strToExecute
941        b=2
942        realw[a,a+b-1] = w[p-a]
943        a+=b
944       
945        // 5 R*4 values
946        SetDataFolder curPath
947        strToExecute = GBLoadStr + "/S=494/U=5" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
948        Execute/Z strToExecute
949        b=5     
950        realw[a,a+b-1] = w[p-a]
951       
952        //if the binary VAX data ws transferred to a MAC, all is OK
953        //if the data was trasnferred to an Intel machine (IBM), all the real values must be
954        //divided by 4 to get the correct floating point values
955        // I can't find any combination of settings in GBLoadWave or FBinRead to read data in correctly
956        // on an Intel machine.
957        //With the corrected version of GBLoadWave XOP (v. 1.43 or higher) Mac and PC both read
958        //VAX reals correctly, and no checking is necessary 12 APR 99
959        //if(cmpstr("Macintosh",IgorInfo(2)) == 0)
960                //do nothing
961        //else
962                //either Windows or Windows NT
963                //realw /= 4
964        //endif
965       
966        SetDataFolder curPath
967        //read in the data
968        strToExecute = "GBLoadWave/O/N=tempGBwave/B/T={16,2}/S=514/Q/P=catPathName" + "\"" + ParseFilePath(0, fname, ":", 1, 0) + "\""
969        Execute/Z strToExecute
970
971        SetDataFolder curPath           //use the full path, so it will always work
972       
973        Make/O/N=16384 $"root:Packages:NIST:RealTime:data"
974        WAVE data=$"root:Packages:NIST:RealTime:data"
975        SkipAndDecompressVAX(w,data)
976        Redimension/N=(128,128) data                    //NIST raw data is 128x128 - do not generalize
977       
978        Duplicate/O data,$"root:Packages:NIST:RealTime:linear_data"
979        WAVE lin_data=$"root:Packages:NIST:RealTime:linear_data"
980        if(isLogScale)
981                data=log(lin_data)
982        else
983                data=lin_data
984        Endif
985       
986        //keep a string with the filename in the RAW folder
987        String/G root:Packages:NIST:RealTime:fileList = textw[0]
988       
989        //set the globals to the detector dimensions (pixels)
990        Variable/G root:myGlobals:gNPixelsX=128         //default for Ordela data (also set in Initialize/NCNR_Utils.ipf)
991        Variable/G root:myGlobals:gNPixelsY=128
992//      if(cmpstr(textW[9],"ILL   ")==0)                //override if OLD Cerca data
993//              Variable/G root:myGlobals:gNPixelsX=64
994//              Variable/G root:myGlobals:gNPixelsY=64
995//      endif
996       
997        //clean up - get rid of w = $"root:Packages:NIST:RAW:tempGBWave0"
998        KillWaves/Z w
999       
1000        //return the data folder to root
1001        SetDataFolder root:
1002       
1003        Return 0
1004
1005End
1006
1007/////not used////
1008// function control a background task of "live" image updating
1009//
1010Function UpdateImage(ctrlName) : ButtonControl
1011        String ctrlName
1012       
1013        if (cmpstr(ctrlName,"bStart") == 0)
1014                Button $ctrlName,title="Stop",rename=bStop
1015        //      Start the updating - FakeUpdate() has been designated as the background task
1016                CtrlBackground period=60,start
1017        else
1018                Button $ctrlName,title="Start",rename=bStart
1019        //      Stop the updating
1020                CtrlBackground stop
1021        endif
1022End
1023
1024
1025// puts a "clean" instance of SAS into RealTime
1026Function ClearRTFolder()
1027
1028        String  RTPath = "root:Packages:NIST:RealTime"
1029        String  SimPath = "root:Packages:NIST:SAS"
1030       
1031
1032        Duplicate/O $(SimPath + ":data"),$(RTPath+":data")
1033        Duplicate/O $(SimPath + ":linear_data"),$(RTPath+":linear_data")
1034        Duplicate/O $(SimPath + ":textread"),$(RTPath+":textread")
1035        Duplicate/O $(SimPath + ":integersread"),$(RTPath+":integersread")
1036        Duplicate/O $(SimPath + ":realsread"),$(RTPath+":realsread")
1037       
1038        WAVE RT_rw = $(RTPath+":RealsRead")
1039        WAVE RT_iw = $(RTPath+":IntegersRead")
1040       
1041        RT_iw[2] = 0
1042        RT_rw[0] = 0
1043
1044        Wave RTData = $(RTPath+":data")
1045        Wave RTLinData = $(RTPath+":linear_data")
1046        RTLinData = 0
1047        RTData = 0
1048
1049        // get the right Q axes on the display
1050        //add the qx and qy axes
1051        Wave q_x_axis=$"root:myGlobals:q_x_axis"
1052        Wave q_y_axis=$"root:myGlobals:q_y_axis"
1053        Set_Q_Axes(q_x_axis,q_y_axis,RTPath)
1054
1055        return(0)
1056End
1057
1058//not used, but useful for real-time display of the detector
1059//old, and likely not up-to-date with the present data folder structure
1060Function FakeUpdate()
1061
1062        //get the current displayed data (so the correct folder is used)
1063        SVAR cur_folder=root:myGlobals:gDataDisplayType
1064
1065        STRUCT WMButtonAction ba
1066        ba.eventCode = 2                        //fake mouse click on button
1067        MC_DoItButtonProc(ba)
1068
1069// would copy the work contents, but I want to add the MC results + times, etc.
1070//      Execute "CopyWorkFolder(\"Simulation\",\"RealTime\")"
1071       
1072        //check for existence of data in oldtype
1073        // if the desired workfile doesn't exist, let the user know, and abort
1074        String RTPath,SimPath
1075        if(WaveExists($("root:Packages:NIST:RealTime:data")) == 0)
1076                ClearRTFolder()
1077//              Print "There is no work file in "+"SAS"+"--Aborting"
1078//              Return(1)               //error condition
1079        Endif
1080       
1081        //check for log-scaling of the "type" data and adjust if necessary
1082//      ConvertFolderToLinearScale("SAS")
1083//      ConvertFolderToLinearScale("RealTime")
1084//      Fix_LogLinButtonState(0)                //make sure the button reflects the new linear scaling
1085        //then continue
1086
1087        //copy from current dir (type)=destPath to newtype, overwriting newtype contents
1088        SimPath = "root:Packages:NIST:SAS"
1089        RTPath = "root:Packages:NIST:RealTime"
1090//      Duplicate/O $(SimPath + ":textread"),$(RTPath+":textread")
1091//      Duplicate/O $(SimPath + ":integersread"),$(RTPath+":integersread")
1092//      Duplicate/O $(SimPath + ":realsread"),$(RTPath+":realsread")
1093//      Duplicate/O $(SimPath + ":linear_data_error"),$(RTPath+":linear_data_error")
1094
1095        WAVE RT_rw = $(RTPath+":RealsRead")
1096        WAVE Sim_rw = $(SimPath+":RealsRead")
1097        WAVE RT_iw = $(RTPath+":IntegersRead")
1098        WAVE Sim_iw = $(SimPath+":IntegersRead")
1099       
1100        // accumulate the count time and monitor counts
1101        RT_iw[2] += Sim_iw[2]
1102        RT_rw[0] += Sim_rw[0]
1103
1104// accumulate the data
1105        Wave RTData = $(RTPath+":data")
1106        Wave RTLinData = $(RTPath+":linear_data")       
1107        Wave SimLinData = $(SimPath+":linear_data")     
1108        RTLinData += SimLinData
1109
1110        NVAR gIsLogScale = $(RTPath + ":gIsLogScale")
1111        if(gIsLogScale)
1112                RTData = log(RTLinData)
1113        else
1114                RTData = RTLinData
1115        endif
1116       
1117//      Execute  "ChangeDisplay(\"RealTime\")"
1118        //just need to update the color bar
1119//      MapSliderProc("both",0,0)
1120
1121        //alter the raw data
1122//      linear_data += abs(enoise(1)) + abs(cos(p*q))
1123//      data = linear_data
1124       
1125
1126        //back to root folder
1127        SetDataFolder root:
1128       
1129        return 0
1130End
1131
1132//
1133//
1134//
1135// to use, first load in the analysis and reduction packages
1136// -- then, load in the sphere model
1137//
1138// load sphere model
1139//      Execute/P "INSERTINCLUDE \"Sphere_v40\""
1140//      Execute/P "COMPILEPROCEDURES "
1141//     
1142//
1143Function pInit_FakeRT()
1144
1145
1146
1147// plot sphere model
1148        String cmdStr,funcStr
1149        funcStr = "SphereForm"
1150        sprintf cmdStr, "Plot%s()",funcStr
1151        Execute cmdStr
1152       
1153// close graph (top) and table
1154        String topGraph= WinName(0,1)   //this is the topmost graph     
1155        String topTable= WinName(0,2)   //this is the topmost table
1156        KillWindow $topGraph
1157        KillWindow $topTable
1158               
1159// change coef_sf[0] = 0.01
1160        Wave coef_sf = root:coef_sf
1161        coef_sf[0] = 0.01
1162       
1163       
1164
1165// open SASCALC
1166        Execute "SASCALC()"
1167       
1168// open MC simulation window
1169        DoWindow/F MC_SASCALC
1170        if(V_flag==0)
1171                Execute "MC_SASCALC()"          //sets the variable
1172                AutoPositionWindow/M=1/R=SASCALC MC_SASCALC
1173        endif
1174        NVAR doSim = root:Packages:NIST:SAS:doSimulation
1175        doSim=1
1176       
1177// set model
1178        SVAR gStr = root:Packages:NIST:SAS:gFuncStr
1179        gStr = "SphereForm"
1180        String listStr = MC_FunctionPopupList()
1181        Variable item = WhichListItem("SphereForm", listStr )
1182        PopupMenu MC_popup0,win=MC_SASCALC,mode=(item+1)
1183       
1184// set ct time to 5 s
1185        STRUCT WMSetVariableAction sva
1186        NVAR ctTime = root:Packages:NIST:SAS:gCntTime
1187        ctTime = 5
1188        sva.eventCode = 3               //update
1189        sva.dval = ctTime               //5 seconds
1190        CountTimeSetVarProc(sva)
1191       
1192// be sure check boxes are raw_cts / BS in / XOP
1193        NVAR cts = root:Packages:NIST:SAS:gRawCounts
1194        NVAR BSin = root:Packages:NIST:SAS:gBeamStopIn
1195        NVAR xop = root:Packages:NIST:SAS:gUse_MC_XOP
1196        cts = 1
1197        BSin = 1
1198        xop = 1
1199       
1200// run 1 simulation to "set" things
1201        DoWindow/F MC_SASCALC
1202        STRUCT WMButtonAction ba
1203        ba.eventCode = 2                        //fake mouse click on button
1204        MC_DoItButtonProc(ba)
1205
1206
1207// set RT fake flag
1208        Variable/G root:myGlobals:gFakeUpdate=1
1209
1210// open RT window
1211
1212// load (any) data file
1213
1214// ClearFolder
1215
1216
1217
1218
1219End
Note: See TracBrowser for help on using the repository browser.