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

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

Added a procedure file that does the necessary wrapping for GenCurveFit?, since it's not a perfect drop-in replacement for FuncFit?. Required modification of the FitWrapper? to switch to GenCurveFit? as needed.
Switch between regular L-M and GenOp? using a menu item.a (sets a gobal)
Still ridiculously slow to use.
Can't yet be used with global fitting. Would be a real pain to implement. Can't imagine how slow that would be to use...

Bug fixes in PatchFiles? (default button for filter type) and Correct (use tolerance of +/- 0.01 pixel for determining of what is a "mismatch" of the beam centers. Problem cropped up with ICE, but should be fixed anyways)

File size: 17.1 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 The 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        Button button_3,pos={500,13},size={100,20},proc=SGFitHelpButtonProc,title="Help"
120       
121        Edit/W=(14,174,348,495)/HOST=#
122        ModifyTable format(Point)=1,width(Point)=34
123        RenameWindow #,T0
124        SetActiveSubwindow ##
125       
126EndMacro
127
128//open the Help file for the Simple Global Fit
129Function SGFitHelpButtonProc(ba) : ButtonControl
130        STRUCT WMButtonAction &ba
131
132        switch( ba.eventCode )
133                case 2: // mouse up
134                        // click code here
135                        DisplayHelpTopic/Z/K=1 "Simple Global Fit"
136                        if(V_flag !=0)
137                                DoAlert 0,"The Simple Global Fit Help file could not be found"
138                        endif
139                        break
140        endswitch
141
142        return 0
143End
144
145
146// save the state of the checkboxes
147Function SaveCheckStateButtonProc(ba) : ButtonControl
148        STRUCT WMButtonAction &ba
149
150        switch( ba.eventCode )
151                case 2: // mouse up
152                        // click code here
153                        Duplicate/O root:Packages:NewGlobalFit:selW, root:Packages:NewGlobalFit:selW_saved
154                        break
155        endswitch
156
157        return 0
158End
159
160//restore the state of the checkboxes if the number of rows is correct
161Function RestoreCheckStateButtonProc(ba) : ButtonControl
162        STRUCT WMButtonAction &ba
163
164        switch( ba.eventCode )
165                case 2: // mouse up
166                        // click code here
167                        Wave sw_cur = root:Packages:NewGlobalFit:selW
168                        Wave sw_sav = root:Packages:NewGlobalFit:selW_saved
169
170                        Variable num_cur,num_sav
171                        num_cur = DimSize(sw_cur,0)
172                        num_sav = DimSize(sw_sav,0)
173
174                        if(num_cur == num_sav)
175                                sw_cur = sw_sav
176                        endif
177                       
178                        break
179        endswitch
180
181        return 0
182End
183
184
185
186
187// show the appropriate coefficient waves
188//
189// also need to search the folder listed in "data set" popup
190// for smeared coefs
191//
192// - or - restrict the coefficient list based on the model function
193// - new way, filter the possible values based on the data folder and function
194Function/S SGF_CoefPopupList()
195
196        String notPlotted="Please plot the function"
197        ControlInfo/W=SimpGFPanel popup_1
198        String funcStr=S_Value
199        String coefStr=getFunctionCoef(funcStr)
200       
201        if(cmpstr(coefStr,"")==0)               //no correspondence in the KW string
202                return(notPlotted)
203        endif
204       
205       
206        //found a coefficient wave - only two places to look
207        // is it in the root folder?
208        if(exists("root:"+coefStr) != 0)
209                return(coefStr)
210        endif
211       
212        // is it in the data folder? (this only checks "a")
213        ControlInfo/W=SimpGFPanel popup_0a
214        String folderStr=S_Value
215        if(exists("root:"+folderStr+":"+coefStr) != 0)
216                return(coefStr)
217        endif
218
219        return(notPlotted)
220End
221
222Function SGF_CoefPopMenuProc(pa) : PopupMenuControl
223        STRUCT WMPopupAction &pa
224
225        switch( pa.eventCode )
226                case 2: // mouse up
227                        Variable popNum = pa.popNum
228                        String popStr = pa.popStr
229                       
230                        //////
231                        String suffix = getModelSuffix(popStr)
232                        ControlInfo/W=SimpGFPanel popup_0a
233                        String folderStr_a=S_Value
234                       
235                        ControlInfo/W=SimpGFPanel popup_0b
236                        String folderStr_b=S_Value
237                       
238                        if(cmpstr(popStr,"Please plot the function")==0)
239//                              Print "function not plotted"
240                                return(0)
241                        endif
242
243// this if/else/endif should not ever return an error alert     
244// it should simply set the data folder properly
245//
246// !! works only with folder/set A     
247                        if(DataFolderExists("root:"+folderStr_a))
248                                SetDataFolder $("root:"+folderStr_a)
249                                if(!exists(popStr))
250                                        // must be unsmeared model, work in the root folder
251                                        SetDataFolder root:                             
252                                        if(!exists(popStr))             //this should be fine if the coef filter is working, but check anyhow
253                                                DoAlert 0,"the coefficient and data sets do not match (1)"
254                                                return 0
255                                        endif
256                                endif
257                        else
258                                // must be unsmeared model, work in the root folder
259                                SetDataFolder root:     
260                                if(!exists(popStr))             //this should be fine if the coef filter is working, but check anyhow
261                                        DoAlert 0,"the coefficient and data sets do not match (2)"
262                                        return 0
263                                endif
264                        endif
265//                     
266                        // farm the work out to another function?
267                        Variable num=numpnts($popStr)
268                        // make the necessary waves, overwriting anything that exists?
269                       
270// duplicate the coefficient waves, A/B
271                        Duplicate/O $(popStr) root:Packages:NewGlobalFit:coef_A,root:Packages:NewGlobalFit:coef_B
272                        Wave coef_A = root:Packages:NewGlobalFit:coef_A
273                        Wave coef_B = root:Packages:NewGlobalFit:coef_B
274                       
275                        if(exists("Hold_"+suffix) == 0)
276                                Make/O/D/N=(num) $("epsilon_"+suffix),$("Hold_"+suffix)
277                                Make/O/T/N=(num) $("LoLim_"+suffix),$("HiLim_"+suffix)
278                                Wave eps = $("epsilon_"+suffix)
279                                Wave coef=$popStr
280                                if(eps[0] == 0)         //if eps already if filled, don't change it
281                                        eps = abs(coef*1e-4) + 1e-10                    //default eps is proportional to the coefficients
282                                endif
283                        endif
284                        // default epsilon values, sometimes needed for the fit
285                       
286                        WAVE/T LoLim = $("LoLim_"+suffix)
287                        WAVE/T HiLim = $("HiLim_"+suffix)
288                       
289                        // clear the table (a subwindow)
290                        DoWindow/F SimpGFPanel                          // ?? had to add this in during all of the cursor meddling...
291                        KillWindow SimpGFPanel#T0
292                        Edit/W=(14,174,348,495)/HOST=SimpGFPanel
293                        RenameWindow #,T0
294                        // get them onto the table
295                        // how do I get the parameter name?
296                        String param = WaveList("*parameters_"+suffix, "", "TEXT:1," )          //this is *hopefully* one wave
297                        AppendtoTable/W=SimpGFPanel#T0 $param
298                        AppendToTable/W=SimpGFPanel#T0 coef_A,coef_B
299//                      AppendToTable/W=SimpGFPanel#T0 $("Hold_"+suffix),$("LoLim_"+suffix),$("HiLim_"+suffix),$("epsilon_"+suffix)
300                        ModifyTable/W=SimpGFPanel#T0 width(Point)=34
301                       
302                        SetDataFolder root:
303                       
304// resize the list boxes based on the number of coefficients                   
305                        WAVE/T lw=root:Packages:NewGlobalFit:listW
306                        WAVE sw=root:Packages:NewGlobalFit:selW
307                        Redimension/N=(num,4) lw
308                        Redimension/N=(num,4) sw
309                        lw[][0] = num2str(p)
310                        sw[][0] = 0
311                        sw[][1] = 2^5           // column is a checkbox
312                        sw[][2] = 2^5
313                        sw[][3] = 2^5
314                        ///////
315                       
316                       
317                        break
318        endswitch
319
320        return 0
321End
322
323// tricky logic here - to make sure that selections are all in-sync and the coefficients too.
324//
325// maybe better to not do anything here, just update states after parsing the details of the selections
326//
327// bit 4 (0x10) is checkbox state
328Function SGF_ListBoxProc(lba) : ListBoxControl
329        STRUCT WMListboxAction &lba
330
331        Variable row = lba.row
332        Variable col = lba.col
333        WAVE/T/Z listWave = lba.listWave
334        WAVE/Z selWave = lba.selWave
335
336        //Print "event code = ",lba.eventCode
337
338        switch( lba.eventCode )
339                case -1: // control being killed
340                        break
341                case 1: //mouse down
342                        //if( (selWave[row][col] & 0x10) != 0)                  //test here is BEFORE the state changes
343                        //      Print "row,col is checked ",row,col
344                        //endif
345                        break
346                case 3: // double click
347                        break
348                case 4: // cell selection
349                case 5: // cell selection plus shift key
350                        break
351                case 6: // begin edit
352                        break
353                case 7: // finish edit
354                        break
355        endswitch
356
357        return 0
358End
359
360// first, it must parse everything for "OK-ness"
361// then construct the waves that GlobalFit needs
362// then dispatch
363// then do something with the results
364//
365Function SGF_DoFitButtonProc(ba) : ButtonControl
366        STRUCT WMButtonAction &ba
367
368        variable err=0
369        switch( ba.eventCode )
370                case 2: // mouse up
371                        // parse
372                        err = ParseSGFPanel()
373                        if(err)
374                                Print "Parse Error"
375                                break
376                        endif
377                       
378                        //wave construct (Waves exist if no parse errors)
379                        WAVE/T FitFuncNames = root:Packages:NewGlobalFit:NewGF_FitFuncNames
380                        Wave/T DataSets = root:Packages:NewGlobalFit:NewGF_DataSetsList
381                        Wave CoefDataSetLinkage = root:Packages:NewGlobalFit:NewGF_LinkageMatrix
382                        WAVE CoefWave = root:Packages:NewGlobalFit:NewGF_CoefWave
383                       
384                        //dispatch
385                        Variable options=105            //=64+32+16+1
386                        Variable FitCurvePoints = 200
387                        Variable DoAlertsOnError = 1
388                       
389                        err = DoNewGlobalFit(FitFuncNames, DataSets, CoefDataSetLinkage, CoefWave, $"", $"", Options, FitCurvePoints, DoAlertsOnError)
390                        //post-process results
391                        //Print "err = ",err
392                        // put results back into coef_a and coef_b
393                        UpdateSGFCoefs(CoefWave)
394                                               
395                        break
396        endswitch
397
398        return 0
399End
400
401// parse the panel and generate the necessary waves
402//
403Function ParseSGFPanel()
404
405        Variable err=0
406        SetDataFolder root:Packages:NewGlobalFit
407       
408//////Fitfunc names
409        ControlInfo/W=SimpGFPanel popup_1
410        String funcStr=S_Value
411        Make/O/T/N=1 NewGF_FitFuncNames
412        WAVE/T FitFuncNames = NewGF_FitFuncNames
413        FitFuncNames[0] = funcStr
414       
415////// data sets
416        ControlInfo/W=SimpGFPanel popup_2
417        String popStr=S_Value
418        String suffix = getModelSuffix(popStr)
419
420       
421        ControlInfo/W=SimpGFPanel popup_0a
422        String folderStr_a=S_Value
423       
424        ControlInfo/W=SimpGFPanel popup_0b
425        String folderStr_b=S_Value
426        Make/O/T/N=(2,4) NewGF_DataSetsList
427        Wave/T DataSets = NewGF_DataSetsList
428        // full paths to the waves
429        DataSets[0][0] = "root:"+folderStr_a+":"+folderStr_a + "_i"
430        DataSets[1][0] = "root:"+folderStr_b+":"+folderStr_b + "_i"
431        DataSets[0][1] = "root:"+folderStr_a+":"+folderStr_a + "_q"
432        DataSets[1][1] = "root:"+folderStr_b+":"+folderStr_b + "_q"
433        DataSets[0][2] = "root:"+folderStr_a+":"+folderStr_a + "_s"
434        DataSets[1][2] = "root:"+folderStr_b+":"+folderStr_b + "_s"
435        SetDimLabel 1, 2, Weights, DataSets
436// column [3] is the mask wave, not supported here
437        DataSets[0][3] = ""
438        DataSets[1][3] = ""
439       
440////// coefficient linkage matrix
441        Wave coef_A = coef_A
442        Wave coef_b = coef_b
443        Variable nc = numpnts(coef_A)
444       
445        Make/O/D/N=(2,nc+4) NewGF_LinkageMatrix
446        Wave CoefDataSetLinkage = NewGF_LinkageMatrix
447
448        WAVE selW = selW
449        Variable nRealCoefs = 0         // accumulates the number of independent coefficients (that is, non-link coefficients)
450        Variable ii,jj,numDataSets=2
451       
452        CoefDataSetLinkage[0][0] = 0            //function number, same for both
453        CoefDataSetLinkage[1][0] = 0
454        CoefDataSetLinkage[0][1] = 0            //first/last data pt numbers, set to zero on input
455        CoefDataSetLinkage[1][1] = 0            //first/last data pt numbers, set to zero on input
456        CoefDataSetLinkage[0][2] = 0            //first/last data pt numbers, set to zero on input
457        CoefDataSetLinkage[1][2] = 0            //first/last data pt numbers, set to zero on input
458        CoefDataSetLinkage[0][3] = nc           //number of coefficients
459        CoefDataSetLinkage[1][3] = nc           //number of coefficients
460       
461        //loop through coefs for first data set [0][]
462        // ! everything hits here - all coefficients are used...
463        Variable offset=4
464        for(ii=0;ii < nc; ii+=1)
465                CoefDataSetLinkage[0][ii+offset] = ii           
466        endfor
467        nRealCoefs = nc
468        // now 2nd data set may have some links
469        for(ii=0;ii < nc; ii+=1)
470                if (selW[ii][1] & 0x10)         //global coefficient
471                        CoefDataSetLinkage[1][ii+offset] = ii
472                else
473                        CoefDataSetLinkage[1][ii+offset] = nRealCoefs
474                        nRealCoefs +=1
475                endif
476        endfor
477       
478//// Cumulative coefficient wave and coefficient names
479// coefficient wave also contains hold[][1] and epsilon[][2]
480// do nothing with epsilon right now
481
482        Make/O/T/N=(nRealCoefs) NewGF_CoefficientNames=""
483        Make/O/D/N=(nRealCoefs,3) NewGF_CoefWave=0
484        Wave coefWave = NewGF_CoefWave
485        Wave/T CoefNames = NewGF_CoefficientNames
486        SetDimLabel 1,1,Hold,coefWave
487//      SetDimLabel 1,2,Epsilon,coefWave
488
489       
490//      String param = WaveList("*parameters_"+suffix, "", "TEXT:1," )          //this is *hopefully* one wave
491//      print "Param = ",param
492       
493        // take the global values from the coef_A wave
494        for(ii=0;ii < nc; ii+=1)
495                CoefWave[ii][0] = coef_a[ii]
496                if(selW[ii][2] & 0x10)          //held
497                        coefWave[ii][1] = 1
498                endif
499//              CoefNames[ii] =                 
500        endfor
501        // now 2nd data set may have some links
502        for(ii=0;ii < nc; ii+=1)
503                if (coefDataSetLinkage[0][ii+offset] == CoefDataSetLinkage[1][ii+offset])               //global coefficient
504                        //do nothing to set the coefficients
505                else
506                        CoefWave[CoefDataSetLinkage[1][ii+offset]][0] = coef_b[ii]                      //take non-global value from b
507                endif
508                if(selW[ii][3] & 0x10)          //global held, "b" checked
509                        coefWave[CoefDataSetLinkage[1][ii+offset]][1] = 1
510                endif
511        endfor
512
513//// constraint wave is not currently supported
514
515
516//// that's all of the waves
517
518        setDataFolder root:
519       
520        return(err)
521end
522
523Function UpdateSGFCoefs(CoefWave)
524        Wave CoefWave
525       
526        SetDataFolder root:Packages:NewGlobalFit
527        Wave coef_a=coef_a
528        Wave coef_b=coef_b
529        Variable nc = numpnts(coef_A)
530        Variable nTotal = DimSize(CoefWave, 0)
531       
532        Wave CoefDataSetLinkage=NewGF_LinkageMatrix
533        //loop through coefs for first data set [0][]
534        // ! everything hits here - all coefficients are used...
535        Variable ii,offset=4,index
536        for(ii=0;ii < nc; ii+=1)
537                coef_a[ii] = CoefWave[ii][0]   
538        endfor
539        // now 2nd data set may have some duplicates from globals
540        for(ii=0;ii < nc; ii+=1)
541                index = CoefDataSetLinkage[1][ii+offset]
542                coef_b[ii] = coefWave[index][0]
543        endfor
544       
545        SetDataFolder root:
546        return(0)
547End
548
549// clean up after itself, don't kill any data folder
550Function UnloadSimpleGlobalFit()
551        if (WinType("SimpGFPanel") == 7)
552                DoWindow/K SimpGFPanel
553        endif
554        if (WinType("GlobalFitGraph") != 0)
555                DoWindow/K GlobalFitGraph
556        endif
557
558        SVAR fileVerExt=root:Packages:NIST:SANS_ANA_EXTENSION
559        String fname="SimpleGlobalFit_NCNR"
560        Execute/P "DELETEINCLUDE \""+fname+fileVerExt+"\""
561        Execute/P "COMPILEPROCEDURES "
562        KillWaves/Z root:Packages:NewGlobalFit:listW
563        KillWaves/Z root:Packages:NewGlobalFit:selW
564        KillWaves/Z root:Packages:NewGlobalFit:titles
565       
566//      KillDataFolder/Z root:Packages:NewGlobalFit
567       
568       
569end
Note: See TracBrowser for help on using the repository browser.