source: sans/Dev/trunk/NCNR_User_Procedures/Reduction/SANS/RawWindowHook.ipf @ 459

Last change on this file since 459 was 459, checked in by srkline, 14 years ago

Fixes from Lionel's bug in the calculation of Qx and Qy. Qx and Qy were not being properly calculated as components of Q and phi (azimuthal angle). Only an effect at the largest q-values (> 0.3) and even then, only in the 3rd decimal place.This incorrect calculation was only visible on the 2D data display, and in the QxQy? ASCII export. Not a terrible bug, not worth immediate release of a patch.

File size: 14.8 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=5.0
3#pragma IgorVersion=6.0
4
5//*****************************
6// Vers. 1.2 092101
7//
8// hook function and associated procedures that interact with the user
9// and the SANS_Data 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// allows the display default to be set to log scaling
18//*****************************
19
20
21//main procedure for display of SANS data files
22//uses "hook" functions to interact witht the user to get live cursor readout
23//based on the IGOR Pro Demo experiment- "SimpleDemoHook" - see the original
24//demo for more details of implementation
25//
26Function fRawWindowHook()
27        //globals for the main data display window are kept in root:myGlobals
28        Variable/G root:myGlobals:gXPos=0
29        Variable/G root:myGlobals:gYPos=0
30        Variable/G root:myGlobals:gQX=0
31        Variable/G root:myGlobals:gQY=0
32        Variable/G root:myGlobals:gQQ=0
33        Variable/G root:myGlobals:gNCounts=0
34        String/G root:myGlobals:gCurDispFile = "default string"
35        String/G root:myGlobals:gCurTitle = ""
36        Make/O/N=2 root:myGlobals:q_x_axis,root:myGlobals:q_y_axis
37       
38        NVAR pixelsX = root:myGlobals:gNPixelsX
39        NVAR pixelsY = root:myGlobals:gNPixelsY
40       
41        //get the current displayed data (so the correct folder is used)
42        SVAR cur_folder=root:myGlobals:gDataDisplayType
43        SVAR cur_title = root:myGlobals:gCurTitle
44        String curPath = "root:Packages:NIST:"+cur_folder
45        Wave/T tw=$(curPath+":TextRead")
46        cur_title = tw[6]                       //always update the title string
47       
48        DoWindow/F SANS_Data
49        if( V_Flag==0 )
50                //no SANS_Data window - make one
51
52                //Create NIH colors if needed
53                if(!WaveExists($"root:myGlobals:NIHColors"))
54                        NIHColorIndex()
55                Endif
56               
57                //window creation stuff
58                Display /W=(10,50,400,490) /K=1 //K=1 flag suppresses saveMacro dialog
59                DoWindow/C SANS_Data
60                DoWindow/T SANS_Data,cur_folder
61                SetWindow SANS_Data,hook=RawWindowHook,hookevents=2
62                ControlBar 100
63
64                SetVariable xpos,pos={7,5},size={50,17},title="X"
65                SetVariable xpos,limits={-Inf,Inf,0},value= root:myGlobals:gXPos
66                SetVariable xpos,help={"x-position on the detector"},frame=0,noedit=1
67                SetVariable ypos,pos={7,29},size={50,17},title="Y"
68                SetVariable ypos,limits={-Inf,Inf,0},value= root:myGlobals:gYPos
69                SetVariable ypos,help={"y-position on the detector"},frame=0,noedit=1
70                SetVariable counts,pos={7,59},size={150,17},title="Counts"
71                SetVariable counts,limits={-Inf,Inf,0},value= root:myGlobals:gNCounts
72                SetVariable counts,help={"Neutron counts"},frame=0,noedit=1
73                Button bisLin,pos={230,23},size={50,20},proc=Log_Lin,title="isLin"
74                Button bisLin,help={"\"isLin\" means the counts displayed are on linear scale. \"isLog\" means the counts displayed are on log(base10) scale."}
75                SetVariable qxval,pos={68,2},size={85,17},title="qX"
76                SetVariable qxval,help={"q value in the x-direction on the detector"},frame=0,noedit=1
77                SetVariable qxval,format="%+7.5f",limits={-Inf,Inf,0},value= root:myGlobals:gQX
78                SetVariable qyval,pos={68,21},size={85,17},title="qY"
79                SetVariable qyval,help={"q value in the y-direction on the detector"},frame=0,noedit=1
80                SetVariable qyval,format="%+7.5f",limits={-Inf,Inf,0},value= root:myGlobals:gQY
81                SetVariable q_pos,pos={68,40},size={85,17},title="q "
82                SetVariable q_pos,help={"q-value on the detector at (x,y)"},format="%+7.5f"
83                SetVariable q_pos,limits={-Inf,Inf,0},value= root:myGlobals:gQQ,frame=0,noedit=1
84                SetVariable CurFile,pos={170,4},size={210,17},title="File"
85                SetVariable CurFile,help={"Currently displayed file"},frame=0,noedit=1
86                SetVariable CurFile,limits={-Inf,Inf,0},value= root:myGlobals:gCurDispFile
87               
88                SetVariable CurTitle,pos={4,81},size={260,17},title=" "//,title="LABEL:"
89                SetVariable CurTitle,help={"Title string for currently displayed file"},frame=0,noedit=1
90                SetVariable CurTitle,fstyle=1,limits={-Inf,Inf,0},value= root:myGlobals:gCurTitle
91                Button Print_status,pos={170,23},size={50,20},proc=StatusButton,title="Status"
92                Button Print_status,help={"Print out information about the currently displayed file into the history window"}
93                Button maskButton size={84,20}, pos={170,53}, proc=maskButtonProc,title="Show Mask"
94                Button maskButton help={"If a mask has been loaded this will overlay it on the current plot"}
95               
96                GroupBox slideGrp,pos={268,46},size={124,48},title="Color Map"
97                //draw after the group box so these are on "top" of the group box
98                Button doAve,pos={290,23},size={50,20},proc=ShowAvgPanel_SANSData,title="I vs. Q"
99                Button doAve,help={"This will circularly average the data to I vs. Q"}
100                Slider loSlide,pos={280,77},size={100,16},proc=MapSliderProc
101                Slider loSlide,limits={0,1,0.01},value= 0,vert= 0,ticks= 0
102                Slider loSlide,help={"Adjust the low threshold of the color map"}
103                Slider hiSlide,pos={280,60},size={100,16},proc=MapSliderProc
104                Slider hiSlide,limits={0,1,0.01},value= 1,vert= 0,ticks= 0
105                Slider hiSlide,help={"Adjust the high threshold of the color map"}
106
107        endif
108       
109        //window was already open, or has just been created, add (or remove)
110        //controls specific for RAW data (specified by the current folder)
111        if(cmpstr(cur_folder,"RAW")==0)
112                //show the "next" buttons
113                //these buttons should only be available in RAW data type
114                Button backOne size={20,20},pos={350,23},proc=BackOneFileButtonProc,title="<"
115                Button backOne help={"Display the previous RAW data file run number"}
116                Button forwardOne size={20,20},pos={375,23},proc=ForwardOneFileButtonProc,title=">"
117                Button forwardOne help={"Display the next RAW data file run number"}
118                //
119        else
120                //kill them
121                KillControl backOne
122                KillControl forwardOne
123        Endif
124       
125        //reset the slider values to 0,1
126        Slider loSlide,value=0
127        Slider hiSlide,value=1
128       
129        //remove old data and add new data to it
130        //data display/modification stuff
131        RemoveImage/Z data
132        WAVE data = $(curPath + ":data")
133        WAVE NIHColors = $"root:myGlobals:NIHColors"
134        AppendImage data
135        WaveStats/Q $(curPath + ":data")
136        if(cmpstr(cur_folder,"MSK")==0)
137                ModifyImage data ctab={0,1,BlueRedGreen,0}
138   else
139                //Call the procedure that would normally be called if the sliders were moved
140//              MapSliderProc("both", 0, 1)
141                MapSliderProc("reset", 0, 1)
142    //  ScaleColorsToData(V_min, V_max, NIHColors)
143         //  ModifyImage data cindex=NIHColors
144        endif
145        //make the pixels square, color the backgrounds
146        ModifyGraph width={plan,1,bottom,left},mirror=0
147        ModifyGraph axisenab(bottom)={0,0.7}
148        ModifyGraph axOffset(left)=-3
149        ModifyGraph standoff=0
150        ModifyGraph wbRGB=(65535,54611,49151),gbRGB=(65535,54611,49151),cbRGB=(1,52428,52428)
151       
152        //add the qx and qy axes
153        Wave q_x_axis=$"root:myGlobals:q_x_axis"
154        Wave q_y_axis=$"root:myGlobals:q_y_axis"
155        Set_Q_Axes(q_x_axis,q_y_axis,curPath)
156        RemoveFromGraph/Z q_x_axis,q_y_axis
157        AppendToGraph/T q_x_axis
158        AppendToGraph/R=Right_Q q_y_axis                                //plot on a free axis, crossing at x=127 (pixelsX)
159        ModifyGraph freePos(Right_q)={pixelsX-1,bottom}
160        ModifyGraph minor(top)=1,minor(Right_Q)=1,lowTrip(top)=1e-05,lowTrip(Right_Q)=1e-05
161        ModifyGraph mode(q_x_axis)=2,mode(q_y_axis)=2           //dots
162        ModifyGraph axisEnab(top)={0,0.7}
163
164        //add the color bar
165        ColorScale/N=colBar/A=RT/X=-3/Y=-1.5/Z=1 image=data, heightPct=100, widthPct=4,notation=1
166        ColorScale/C/N=colBar/B=(65535,60076,49151)
167       
168        //update the displayed filename, using FileList in the current data folder
169        SVAR FileList = $(curPath + ":FileList")
170        String/G root:myGlobals:gCurDispFile = FileList
171       
172        //update the window title
173        DoWindow/T SANS_Data,cur_folder
174       
175        // reset the initial state of the "isLin" button if it is reading "isLog", since the initial data state is
176        //always set to linear
177        //re-draw the data on the graph to make sure "data" from the current folder is being used
178        ControlInfo bisLog
179        if(V_flag ==1)  //if bisLog exists, this will return true
180                Button bisLog,title="isLin",rename=bisLin
181        endif
182        //now that button state and data are sure to match (both are linear)
183        // set the display to log scale, if the global has been set
184        NVAR gLogScalingAsDefault=root:myGlobals:gLogScalingAsDefault
185        if(gLogScalingAsDefault)
186                Log_lin("bisLin")
187        endif
188       
189        //force an update of everything in the window
190        DoUpdate
191       
192        //return data folder to root before exiting (redundant)
193        SetDataFolder root:     
194End
195
196//this is the hook function that is associated with the SANS_Data graph window
197//only mouse moved events are processed, although much more could be done
198//for more elaborate interaction with the user.
199//- sets globals (that are displayed in the control bar of the graph) for the
200//x and y positions (in Detector coordinates (1,128))
201//qx, qy, and q (in Angstroms)
202//and the actual neutron counts (if raw)
203//or the data array value
204//
205Function RawWindowHook(s)
206        String s
207       
208        //get the current displayed data (so the correct folder is used)
209        SVAR cur_folder=root:myGlobals:gDataDisplayType
210        SetDataFolder "root:Packages:NIST:"+cur_folder          //use the full path, so it will always work
211        String curPath = "root:Packages:NIST:" + cur_folder
212        NVAR dataIsLog=$(curPath + ":gIsLogScale")              //now a global variable in the current folder, not the globals folder
213        if (dataIsLog)
214                wave w=$(curPath + ":linear_data")
215        else
216                wave w=$(curPath + ":data")
217      endif
218        wave reals=$(curPath + ":realsread")
219       
220        String/G root:myGlobals:gHookStr= s
221        Variable xpix,ypix,xaxval,yaxval,xint,yint,rawval
222        String msg
223       
224        NVAR pixelsX = root:myGlobals:gNPixelsX
225        NVAR pixelsY = root:myGlobals:gNPixelsY
226       
227        //only do something for mousemoved events
228        if( StrSearch(s,"EVENT:mousemoved;",0) > 0 )
229                xpix= NumberByKey("MOUSEX",s)
230                ypix= NumberByKey("MOUSEY",s)
231                xaxval= AxisValFromPixel("","bottom",xpix)
232                yaxval= AxisValFromPixel("","left",ypix)
233                xint = round(xaxval)
234                yint = round(yaxval)
235               
236                if((xint<0) || (xint>pixelsX-1) || (yint<0) || (yint>pixelsY-1))        //make sure cursor is on the image
237                        rawval = 0
238                else
239                        rawval = w[xint][yint] 
240                        //update q, qX, and qY
241                        if(cmpstr(cur_folder,"MSK")!=0)
242                                Variable xctr=reals[16],yctr=reals[17],sdd=reals[18],lam=reals[26],pixSize=reals[13]/10
243                                Variable/G root:myGlobals:gQQ = CalcQval(xaxval+1,yaxval+1,xctr,yctr,sdd,lam,pixSize)
244                                Variable/G root:myGlobals:gQX = CalcQX(xaxval+1,yaxval+1,xctr,yctr,sdd,lam,pixSize)
245                                Variable/G root:myGlobals:gQY = CalcQY(xaxval+1,yaxval+1,xctr,yctr,sdd,lam,pixSize)
246                        else
247                                Variable/G root:myGlobals:gQQ = 0
248                                Variable/G root:myGlobals:gQX = 0
249                                Variable/G root:myGlobals:gQY = 0
250                        endif
251                        //add one to the x and y values to get from IGOR array indexing 0->127 to 1->128 detector
252                        Variable/G root:myGlobals:gXPos=xint+1
253                        Variable/G root:myGlobals:gYPos=yint+1
254                        Variable/G root:myGlobals:gNCounts=rawval
255                endif
256        endif
257       
258        //set data folder back to root
259        SetDataFolder root:
260       
261        return 0
262end
263       
264//function to calculate the overall q-value, given all of the necesary trig inputs
265//NOTE: detector locations passed in are pixels = 0.5cm real space on the detector
266//and are in detector coordinates (1,128) rather than axis values
267//the pixel locations need not be integers, reals are ok inputs
268//sdd is in meters
269//wavelength is in Angstroms
270//
271//returned magnitude of Q is in 1/Angstroms
272//
273// repaired the dumb error of incorrect qx and qy calculation 3 dec 08 SRK (Lionel...)
274//
275Function CalcQval(xaxval,yaxval,xctr,yctr,sdd,lam,pixSize)
276        Variable xaxval,yaxval,xctr,yctr,sdd,lam,pixSize
277       
278        Variable dx,dy,qval,theta,dist
279       
280        Variable pixSizeX=pixSize
281        Variable pixSizeY=pixSize
282       
283        sdd *=100               //convert to cm
284        dx = (xaxval - xctr)*pixSizeX           //delta x in cm
285        dy = (yaxval - yctr)*pixSizeY           //delta y in cm
286        dist = sqrt(dx^2 + dy^2)
287       
288        theta = atan(dist/sdd)
289
290        qval = 4*Pi/lam*sin(theta/2)
291       
292        return qval
293End
294
295//calculates just the q-value in the x-direction on the detector
296//input/output is the same as CalcQval()
297//ALL inputs are in detector coordinates
298//
299//NOTE: detector locations passed in are pixel = 0.5cm real space on the Ordela detector
300//sdd is in meters
301//wavelength is in Angstroms
302//
303// repaired the dumb error of incorrect qx and qy calculation 3 dec 08 SRK (Lionel...)
304//
305Function CalcQX(xaxval,yaxval,xctr,yctr,sdd,lam,pixSize)
306        Variable xaxval,yaxval,xctr,yctr,sdd,lam,pixSize
307
308        Variable qx,qval,phi,dx,dy
309       
310        qval = CalcQval(xaxval,yaxval,xctr,yctr,sdd,lam,pixSize)
311       
312        sdd *=100               //convert to cm
313        dx = (xaxval - xctr)*pixSize            //delta x in cm
314        dy = (yaxval - yctr)*pixSize            //delta y in cm
315        phi = FindPhi(dx,dy)
316       
317        qx = qval*cos(phi)
318       
319        return qx
320End
321
322//calculates just the q-value in the y-direction on the detector
323//input/output is the same as CalcQval()
324//ALL inputs are in detector coordinates
325//NOTE: detector locations passed in are pixel = 0.5cm real space on the Ordela detector
326//sdd is in meters
327//wavelength is in Angstroms
328//
329// repaired the dumb error of incorrect qx and qy calculation 3 dec 08 SRK (Lionel...)
330//
331Function CalcQY(xaxval,yaxval,xctr,yctr,sdd,lam,pixSize)
332        Variable xaxval,yaxval,xctr,yctr,sdd,lam,pixSize
333       
334        Variable dy,qval,dx,phi,qy
335       
336        qval = CalcQval(xaxval,yaxval,xctr,yctr,sdd,lam,pixSize)
337       
338        sdd *=100               //convert to cm
339        dx = (xaxval - xctr)*pixSize            //delta x in cm
340        dy = (yaxval - yctr)*pixSize            //delta y in cm
341        phi = FindPhi(dx,dy)
342       
343        qy = qval*sin(phi)
344       
345        return qy
346End
347
348
349//phi is defined from +x axis, proceeding CCW around [0,2Pi]
350Threadsafe Function FindPhi(vx,vy)
351        variable vx,vy
352       
353        variable phi
354       
355        phi = atan(vy/vx)               //returns a value from -pi/2 to pi/2
356       
357        // special cases
358        if(vx==0 && vy > 0)
359                return(pi/2)
360        endif
361        if(vx==0 && vy < 0)
362                return(3*pi/2)
363        endif
364        if(vx >= 0 && vy == 0)
365                return(0)
366        endif
367        if(vx < 0 && vy == 0)
368                return(pi)
369        endif
370       
371       
372        if(vx > 0 && vy > 0)
373                return(phi)
374        endif
375        if(vx < 0 && vy > 0)
376                return(phi + pi)
377        endif
378        if(vx < 0 && vy < 0)
379                return(phi + pi)
380        endif
381        if( vx > 0 && vy < 0)
382                return(phi + 2*pi)
383        endif
384       
385        return(phi)
386end
387
388
389//function to set the q-axis scaling after the data has been read in
390// - needs the location of the currently displayed data to get the header information
391// to be able to calculate q-values at the edges of the detector
392//** assumes a linear correspondence between pixel->q-values (which should bea a really
393// safe bet, since we're using the small -angle approximation...)
394//
395// actually re-scales the qy wave that is on the SANS_Data image
396// the qy dataset is 2 values, plotted as "dots", nearly invisible...
397// but does an adequate job of getting ticks on the right and top axes
398//
399Function Set_Q_Axes(qx,qy,curPath)
400        Wave qx,qy
401        String curPath
402
403        NVAR pixelsX = root:myGlobals:gNPixelsX
404        NVAR pixelsY = root:myGlobals:gNPixelsY
405       
406        WAVE reals=$(curPath + ":realsread")
407        Variable xctr=reals[16],yctr=reals[17],sdd=reals[18],lam=reals[26]
408        Variable pixSize=reals[13]/10           //pixel size in cm to pass
409        Variable maxX,minX,maxY,minY
410       
411        minX = CalcQX(1,yctr,xctr,yctr,sdd,lam,pixSize)
412        maxX = CalcQX(pixelsX,yctr,xctr,yctr,sdd,lam,pixSize)
413        SetScale/I x minX,maxX,"",qx
414       
415        minY = CalcQY(xctr,1,xctr,yctr,sdd,lam,pixSize)
416        maxY = CalcQY(xctr,pixelsY,xctr,yctr,sdd,lam,pixSize)
417        qy[0] = minY
418        qy[1] = maxY
419       
420        return(0)
421End
422
423Function ToggleDefaultMapping()
424        NVAR value = root:myGlobals:gLogScalingAsDefault
425        value = !(value)
426End
Note: See TracBrowser for help on using the repository browser.