source: sans/Dev/trunk/NCNR_User_Procedures/Analysis/Packages/GlobalFit/SimpleGlobalFit_NCNR_v40.ipf @ 477

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

Added save/restore buttons to SimpleGlobal? fit to be able to restore the state of the checkboxes if possible. Checkboxes are reset when new data sets are selected.

Typos in SANSRedn help file have been corrected.

Error bar styles have been changed to /T=0, a vertical line with no horizontal bar. My preference - I got tired of seeing more of the horizontal bar than the actual data.

File size: 16.6 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2
3
4// panel meant to make it easier to fit two data sets with a single model
5// typically (but not necessarily) U+S, resolution smeared
6//
7// Uses a lot of the functionality from the Wrapper Panel - so be careful
8// if the behavior of that panel changes - especially the popup menus
9//
10// currently unsupported:
11// mask
12// constraints
13// epsilon (used, set behind the scenes but is not user-settable)
14//
15// ** some of the other assumptions/behaviors are:
16// - if a global variable is held by one set, it is (must be) held for the other set
17//   even though I don't automatically check the other box
18// - global parameter values are set from SET A. values in set B are overwritten during
19//   the fit
20// - upon initialization of the coefficients, coef_A and coef_B are set to those from the
21//   first data set (A). So the appropriate model must be plotted for set A. It does not
22//   need to be plotted for set B, although if you fit the sets separately, each fit can
23//   be used as a good first guess for the global fitting by cut/pase into the table.
24// - reports are always generated and automatically saved. Beware overwriting.
25// - weighting waves are automatically selected, as usual, since I know the data sets
26// - both data sets should be on the top graph. The fit, when finished, will try to append
27//   the results of the fit on the top graph.
28//
29// SRK FEB 2009
30
31// these waves feed the WM NewGlobalFit package, and must have the proper
32// names, locations, *and* dimLabels to work properly. But then it can be run
33// through all of the same machinery.
34
35//      Make/O/T/N=(numDataSets) root:Packages:NewGlobalFit:NewGF_FitFuncNames = ""
36//      Wave/T FitFuncNames = root:Packages:NewGlobalFit:NewGF_FitFuncNames
37
38//Make/O/T/N=(numDataSets, 2) root:Packages:NewGlobalFit:NewGF_DataSetsList
39//      Wave/T DataSets = root:Packages:NewGlobalFit:NewGF_DataSetsList
40
41//      Make/N=(numDataSets, numLinkageCols)/O root:Packages:NewGlobalFit:NewGF_LinkageMatrix
42//      Wave LinkageMatrix = root:Packages:NewGlobalFit:NewGF_LinkageMatrix
43
44//      Make/O/D/N=(nRealCoefs, 3) root:Packages:NewGlobalFit:NewGF_CoefWave
45//      Wave coefWave = root:Packages:NewGlobalFit:NewGF_CoefWave
46//      SetDimLabel 1,1,Hold,coefWave
47//      SetDimLabel 1,2,Epsilon,coefWave
48//      Make/O/T/N=(nRealCoefs) root:Packages:NewGlobalFit:NewGF_CoefficientNames
49//      Wave/T CoefNames = root:Packages:NewGlobalFit:NewGF_CoefficientNames   
50
51//Wave/T/Z ConstraintWave = root:Packages:NewGlobalFit:GFUI_GlobalFitConstraintWave
52// or $""
53
54
55 
56Proc OpenSimpleGlobalFit()
57        Init_SimpleGlobalFit()
58End
59
60Menu "SANS Models"
61//      "Global Fit", InitGlobalFitPanel()
62        Submenu "Packages"
63                "Unload Simple Global Fit",  UnloadSimpleGlobalFit()
64        End
65end
66
67Function Init_SimpleGlobalFit()
68        //make sure that folders exist - this is the first initialization to be called
69        NewDataFolder/O root:Packages
70        NewDataFolder/O root:Packages:NewGlobalFit
71       
72        DoWindow/F SimpGFPanel
73        if(V_flag==0)
74                SetDataFolder root:Packages:NewGlobalFit
75                // create waves for the list box, or for the embedded table?
76                Make/O/T/N=(10,4) listW
77                Make/O/B/N=(10,4) selW
78                Make/O/T/N=4 titles
79                titles[0] = "Coef #"
80                titles[1] = "Global?"
81                titles[2] = "Hold for Set A?"
82                titles[3] = "Hold for Set B?"
83               
84                listW[][0] = num2str(p)
85                selW[][0] = 0
86                selW[][1] = 2^5         // column is a checkbox
87                selW[][2] = 2^5
88                selW[][3] = 2^5
89               
90                Execute "SimpGFPanel()"
91                setDataFolder root:
92        endif
93End
94
95Window SimpGFPanel() : Panel
96        PauseUpdate; Silent 1           // building window...
97        NewPanel/W=(689,526,1318,1035)/K=1/N=SimpGFPanel as "Simple Global Fit Setup"
98        ModifyPanel cbRGB=(65535,65534,49151)
99       
100        GroupBox grpBox_0,pos={18,11},size={310,129}
101
102        PopupMenu popup_0a,pos={30,21},size={218,20},title="Data Set A "
103        PopupMenu popup_0a,mode=1,value= #"W_DataSetPopupList()"
104        PopupMenu popup_0b,pos={30,49},size={218,20},title="Data Set B "
105        PopupMenu popup_0b,mode=1,value= #"W_DataSetPopupList()"
106        PopupMenu popup_1,pos={30,80},size={136,20},title="Function"
107        PopupMenu popup_1,mode=1,value= #"W_FunctionPopupList()"
108        PopupMenu popup_2,pos={30,110},size={123,20},title="Coefficients"
109        PopupMenu popup_2,mode=1,value= #"SGF_CoefPopupList()",proc=SGF_CoefPopMenuProc
110        ListBox list0,pos={355,195},size={260,288},listWave=root:Packages:NewGlobalFit:listW
111        ListBox list0 selWave=root:Packages:NewGlobalFit:selW,proc=SGF_ListBoxProc
112        ListBox list0 titleWave=root:Packages:NewGlobalFit:titles//,userColumnResize=1
113        ListBox list0 widths={30,50,80,80}
114       
115        Button button_0,pos={344,13},size={100,20},title="Do Fit"
116        Button button_0 proc=SGF_DoFitButtonProc
117        Button button_1,pos={369,173},size={50,20},proc=SaveCheckStateButtonProc,title="Save"
118        Button button_2,pos={429,173},size={70,20},proc=RestoreCheckStateButtonProc,title="Restore"
119       
120        Edit/W=(14,174,348,495)/HOST=#
121        ModifyTable format(Point)=1,width(Point)=34
122        RenameWindow #,T0
123        SetActiveSubwindow ##
124       
125EndMacro
126
127// save the state of the checkboxes
128Function SaveCheckStateButtonProc(ba) : ButtonControl
129        STRUCT WMButtonAction &ba
130
131        switch( ba.eventCode )
132                case 2: // mouse up
133                        // click code here
134                        Duplicate/O root:Packages:NewGlobalFit:selW, root:Packages:NewGlobalFit:selW_saved
135                        break
136        endswitch
137
138        return 0
139End
140
141//restore the state of the checkboxes if the number of rows is correct
142Function RestoreCheckStateButtonProc(ba) : ButtonControl
143        STRUCT WMButtonAction &ba
144
145        switch( ba.eventCode )
146                case 2: // mouse up
147                        // click code here
148                        Wave sw_cur = root:Packages:NewGlobalFit:selW
149                        Wave sw_sav = root:Packages:NewGlobalFit:selW_saved
150
151                        Variable num_cur,num_sav
152                        num_cur = DimSize(sw_cur,0)
153                        num_sav = DimSize(sw_sav,0)
154
155                        if(num_cur == num_sav)
156                                sw_cur = sw_sav
157                        endif
158                       
159                        break
160        endswitch
161
162        return 0
163End
164
165
166
167
168// show the appropriate coefficient waves
169//
170// also need to search the folder listed in "data set" popup
171// for smeared coefs
172//
173// - or - restrict the coefficient list based on the model function
174// - new way, filter the possible values based on the data folder and function
175Function/S SGF_CoefPopupList()
176
177        String notPlotted="Please plot the function"
178        ControlInfo/W=SimpGFPanel popup_1
179        String funcStr=S_Value
180        String coefStr=getFunctionCoef(funcStr)
181       
182        if(cmpstr(coefStr,"")==0)               //no correspondence in the KW string
183                return(notPlotted)
184        endif
185       
186       
187        //found a coefficient wave - only two places to look
188        // is it in the root folder?
189        if(exists("root:"+coefStr) != 0)
190                return(coefStr)
191        endif
192       
193        // is it in the data folder? (this only checks "a")
194        ControlInfo/W=SimpGFPanel popup_0a
195        String folderStr=S_Value
196        if(exists("root:"+folderStr+":"+coefStr) != 0)
197                return(coefStr)
198        endif
199
200        return(notPlotted)
201End
202
203Function SGF_CoefPopMenuProc(pa) : PopupMenuControl
204        STRUCT WMPopupAction &pa
205
206        switch( pa.eventCode )
207                case 2: // mouse up
208                        Variable popNum = pa.popNum
209                        String popStr = pa.popStr
210                       
211                        //////
212                        String suffix = getModelSuffix(popStr)
213                        ControlInfo/W=SimpGFPanel popup_0a
214                        String folderStr_a=S_Value
215                       
216                        ControlInfo/W=SimpGFPanel popup_0b
217                        String folderStr_b=S_Value
218                       
219                        if(cmpstr(popStr,"Please plot the function")==0)
220//                              Print "function not plotted"
221                                return(0)
222                        endif
223
224// this if/else/endif should not ever return an error alert     
225// it should simply set the data folder properly
226//
227// !! works only with folder/set A     
228                        if(DataFolderExists("root:"+folderStr_a))
229                                SetDataFolder $("root:"+folderStr_a)
230                                if(!exists(popStr))
231                                        // must be unsmeared model, work in the root folder
232                                        SetDataFolder root:                             
233                                        if(!exists(popStr))             //this should be fine if the coef filter is working, but check anyhow
234                                                DoAlert 0,"the coefficient and data sets do not match (1)"
235                                                return 0
236                                        endif
237                                endif
238                        else
239                                // must be unsmeared model, work in the root folder
240                                SetDataFolder root:     
241                                if(!exists(popStr))             //this should be fine if the coef filter is working, but check anyhow
242                                        DoAlert 0,"the coefficient and data sets do not match (2)"
243                                        return 0
244                                endif
245                        endif
246//                     
247                        // farm the work out to another function?
248                        Variable num=numpnts($popStr)
249                        // make the necessary waves, overwriting anything that exists?
250                       
251// duplicate the coefficient waves, A/B
252                        Duplicate/O $(popStr) root:Packages:NewGlobalFit:coef_A,root:Packages:NewGlobalFit:coef_B
253                        Wave coef_A = root:Packages:NewGlobalFit:coef_A
254                        Wave coef_B = root:Packages:NewGlobalFit:coef_B
255                       
256                        if(exists("Hold_"+suffix) == 0)
257                                Make/O/D/N=(num) $("epsilon_"+suffix),$("Hold_"+suffix)
258                                Make/O/T/N=(num) $("LoLim_"+suffix),$("HiLim_"+suffix)
259                                Wave eps = $("epsilon_"+suffix)
260                                Wave coef=$popStr
261                                if(eps[0] == 0)         //if eps already if filled, don't change it
262                                        eps = abs(coef*1e-4) + 1e-10                    //default eps is proportional to the coefficients
263                                endif
264                        endif
265                        // default epsilon values, sometimes needed for the fit
266                       
267                        WAVE/T LoLim = $("LoLim_"+suffix)
268                        WAVE/T HiLim = $("HiLim_"+suffix)
269                       
270                        // clear the table (a subwindow)
271                        DoWindow/F SimpGFPanel                          // ?? had to add this in during all of the cursor meddling...
272                        KillWindow SimpGFPanel#T0
273                        Edit/W=(14,174,348,495)/HOST=SimpGFPanel
274                        RenameWindow #,T0
275                        // get them onto the table
276                        // how do I get the parameter name?
277                        String param = WaveList("*parameters_"+suffix, "", "TEXT:1," )          //this is *hopefully* one wave
278                        AppendtoTable/W=SimpGFPanel#T0 $param
279                        AppendToTable/W=SimpGFPanel#T0 coef_A,coef_B
280//                      AppendToTable/W=SimpGFPanel#T0 $("Hold_"+suffix),$("LoLim_"+suffix),$("HiLim_"+suffix),$("epsilon_"+suffix)
281                        ModifyTable/W=SimpGFPanel#T0 width(Point)=34
282                       
283                        SetDataFolder root:
284                       
285// resize the list boxes based on the number of coefficients                   
286                        WAVE/T lw=root:Packages:NewGlobalFit:listW
287                        WAVE sw=root:Packages:NewGlobalFit:selW
288                        Redimension/N=(num,4) lw
289                        Redimension/N=(num,4) sw
290                        lw[][0] = num2str(p)
291                        sw[][0] = 0
292                        sw[][1] = 2^5           // column is a checkbox
293                        sw[][2] = 2^5
294                        sw[][3] = 2^5
295                        ///////
296                       
297                       
298                        break
299        endswitch
300
301        return 0
302End
303
304// tricky logic here - to make sure that selections are all in-sync and the coefficients too.
305//
306// maybe better to not do anything here, just update states after parsing the details of the selections
307//
308// bit 4 (0x10) is checkbox state
309Function SGF_ListBoxProc(lba) : ListBoxControl
310        STRUCT WMListboxAction &lba
311
312        Variable row = lba.row
313        Variable col = lba.col
314        WAVE/T/Z listWave = lba.listWave
315        WAVE/Z selWave = lba.selWave
316
317        //Print "event code = ",lba.eventCode
318
319        switch( lba.eventCode )
320                case -1: // control being killed
321                        break
322                case 1: //mouse down
323                        //if( (selWave[row][col] & 0x10) != 0)                  //test here is BEFORE the state changes
324                        //      Print "row,col is checked ",row,col
325                        //endif
326                        break
327                case 3: // double click
328                        break
329                case 4: // cell selection
330                case 5: // cell selection plus shift key
331                        break
332                case 6: // begin edit
333                        break
334                case 7: // finish edit
335                        break
336        endswitch
337
338        return 0
339End
340
341// first, it must parse everything for "OK-ness"
342// then construct the waves that GlobalFit needs
343// then dispatch
344// then do something with the results
345//
346Function SGF_DoFitButtonProc(ba) : ButtonControl
347        STRUCT WMButtonAction &ba
348
349        variable err=0
350        switch( ba.eventCode )
351                case 2: // mouse up
352                        // parse
353                        err = ParseSGFPanel()
354                        if(err)
355                                Print "Parse Error"
356                                break
357                        endif
358                       
359                        //wave construct (Waves exist if no parse errors)
360                        WAVE/T FitFuncNames = root:Packages:NewGlobalFit:NewGF_FitFuncNames
361                        Wave/T DataSets = root:Packages:NewGlobalFit:NewGF_DataSetsList
362                        Wave CoefDataSetLinkage = root:Packages:NewGlobalFit:NewGF_LinkageMatrix
363                        WAVE CoefWave = root:Packages:NewGlobalFit:NewGF_CoefWave
364                       
365                        //dispatch
366                        Variable options=105            //=64+32+16+1
367                        Variable FitCurvePoints = 200
368                        Variable DoAlertsOnError = 1
369                       
370                        err = DoNewGlobalFit(FitFuncNames, DataSets, CoefDataSetLinkage, CoefWave, $"", $"", Options, FitCurvePoints, DoAlertsOnError)
371                        //post-process results
372                        //Print "err = ",err
373                        // put results back into coef_a and coef_b
374                        UpdateSGFCoefs(CoefWave)
375                                               
376                        break
377        endswitch
378
379        return 0
380End
381
382// parse the panel and generate the necessary waves
383//
384Function ParseSGFPanel()
385
386        Variable err=0
387        SetDataFolder root:Packages:NewGlobalFit
388       
389//////Fitfunc names
390        ControlInfo/W=SimpGFPanel popup_1
391        String funcStr=S_Value
392        Make/O/T/N=1 NewGF_FitFuncNames
393        WAVE/T FitFuncNames = NewGF_FitFuncNames
394        FitFuncNames[0] = funcStr
395       
396////// data sets
397        ControlInfo/W=SimpGFPanel popup_2
398        String popStr=S_Value
399        String suffix = getModelSuffix(popStr)
400
401       
402        ControlInfo/W=SimpGFPanel popup_0a
403        String folderStr_a=S_Value
404       
405        ControlInfo/W=SimpGFPanel popup_0b
406        String folderStr_b=S_Value
407        Make/O/T/N=(2,4) NewGF_DataSetsList
408        Wave/T DataSets = NewGF_DataSetsList
409        // full paths to the waves
410        DataSets[0][0] = "root:"+folderStr_a+":"+folderStr_a + "_i"
411        DataSets[1][0] = "root:"+folderStr_b+":"+folderStr_b + "_i"
412        DataSets[0][1] = "root:"+folderStr_a+":"+folderStr_a + "_q"
413        DataSets[1][1] = "root:"+folderStr_b+":"+folderStr_b + "_q"
414        DataSets[0][2] = "root:"+folderStr_a+":"+folderStr_a + "_s"
415        DataSets[1][2] = "root:"+folderStr_b+":"+folderStr_b + "_s"
416        SetDimLabel 1, 2, Weights, DataSets
417// column [3] is the mask wave, not supported here
418        DataSets[0][3] = ""
419        DataSets[1][3] = ""
420       
421////// coefficient linkage matrix
422        Wave coef_A = coef_A
423        Wave coef_b = coef_b
424        Variable nc = numpnts(coef_A)
425       
426        Make/O/D/N=(2,nc+4) NewGF_LinkageMatrix
427        Wave CoefDataSetLinkage = NewGF_LinkageMatrix
428
429        WAVE selW = selW
430        Variable nRealCoefs = 0         // accumulates the number of independent coefficients (that is, non-link coefficients)
431        Variable ii,jj,numDataSets=2
432       
433        CoefDataSetLinkage[0][0] = 0            //function number, same for both
434        CoefDataSetLinkage[1][0] = 0
435        CoefDataSetLinkage[0][1] = 0            //first/last data pt numbers, set to zero on input
436        CoefDataSetLinkage[1][1] = 0            //first/last data pt numbers, set to zero on input
437        CoefDataSetLinkage[0][2] = 0            //first/last data pt numbers, set to zero on input
438        CoefDataSetLinkage[1][2] = 0            //first/last data pt numbers, set to zero on input
439        CoefDataSetLinkage[0][3] = nc           //number of coefficients
440        CoefDataSetLinkage[1][3] = nc           //number of coefficients
441       
442        //loop through coefs for first data set [0][]
443        // ! everything hits here - all coefficients are used...
444        Variable offset=4
445        for(ii=0;ii < nc; ii+=1)
446                CoefDataSetLinkage[0][ii+offset] = ii           
447        endfor
448        nRealCoefs = nc
449        // now 2nd data set may have some links
450        for(ii=0;ii < nc; ii+=1)
451                if (selW[ii][1] & 0x10)         //global coefficient
452                        CoefDataSetLinkage[1][ii+offset] = ii
453                else
454                        CoefDataSetLinkage[1][ii+offset] = nRealCoefs
455                        nRealCoefs +=1
456                endif
457        endfor
458       
459//// Cumulative coefficient wave and coefficient names
460// coefficient wave also contains hold[][1] and epsilon[][2]
461// do nothing with epsilon right now
462
463        Make/O/T/N=(nRealCoefs) NewGF_CoefficientNames=""
464        Make/O/D/N=(nRealCoefs,3) NewGF_CoefWave=0
465        Wave coefWave = NewGF_CoefWave
466        Wave/T CoefNames = NewGF_CoefficientNames
467        SetDimLabel 1,1,Hold,coefWave
468//      SetDimLabel 1,2,Epsilon,coefWave
469
470       
471//      String param = WaveList("*parameters_"+suffix, "", "TEXT:1," )          //this is *hopefully* one wave
472//      print "Param = ",param
473       
474        // take the global values from the coef_A wave
475        for(ii=0;ii < nc; ii+=1)
476                CoefWave[ii][0] = coef_a[ii]
477                if(selW[ii][2] & 0x10)          //held
478                        coefWave[ii][1] = 1
479                endif
480//              CoefNames[ii] =                 
481        endfor
482        // now 2nd data set may have some links
483        for(ii=0;ii < nc; ii+=1)
484                if (coefDataSetLinkage[0][ii+offset] == CoefDataSetLinkage[1][ii+offset])               //global coefficient
485                        //do nothing to set the coefficients
486                else
487                        CoefWave[CoefDataSetLinkage[1][ii+offset]][0] = coef_b[ii]                      //take non-global value from b
488                endif
489                if(selW[ii][3] & 0x10)          //global held, "b" checked
490                        coefWave[CoefDataSetLinkage[1][ii+offset]][1] = 1
491                endif
492        endfor
493
494//// constraint wave is not currently supported
495
496
497//// that's all of the waves
498
499        setDataFolder root:
500       
501        return(err)
502end
503
504Function UpdateSGFCoefs(CoefWave)
505        Wave CoefWave
506       
507        SetDataFolder root:Packages:NewGlobalFit
508        Wave coef_a=coef_a
509        Wave coef_b=coef_b
510        Variable nc = numpnts(coef_A)
511        Variable nTotal = DimSize(CoefWave, 0)
512       
513        Wave CoefDataSetLinkage=NewGF_LinkageMatrix
514        //loop through coefs for first data set [0][]
515        // ! everything hits here - all coefficients are used...
516        Variable ii,offset=4,index
517        for(ii=0;ii < nc; ii+=1)
518                coef_a[ii] = CoefWave[ii][0]   
519        endfor
520        // now 2nd data set may have some duplicates from globals
521        for(ii=0;ii < nc; ii+=1)
522                index = CoefDataSetLinkage[1][ii+offset]
523                coef_b[ii] = coefWave[index][0]
524        endfor
525       
526        SetDataFolder root:
527        return(0)
528End
529
530// clean up after itself, don't kill any data folder
531Function UnloadSimpleGlobalFit()
532        if (WinType("SimpGFPanel") == 7)
533                DoWindow/K SimpGFPanel
534        endif
535        if (WinType("GlobalFitGraph") != 0)
536                DoWindow/K GlobalFitGraph
537        endif
538
539        SVAR fileVerExt=root:Packages:NIST:SANS_ANA_EXTENSION
540        String fname="SimpleGlobalFit_NCNR"
541        Execute/P "DELETEINCLUDE \""+fname+fileVerExt+"\""
542        Execute/P "COMPILEPROCEDURES "
543        KillWaves/Z root:Packages:NewGlobalFit:listW
544        KillWaves/Z root:Packages:NewGlobalFit:selW
545        KillWaves/Z root:Packages:NewGlobalFit:titles
546       
547//      KillDataFolder/Z root:Packages:NewGlobalFit
548       
549       
550end
Note: See TracBrowser for help on using the repository browser.