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

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

Added a new, simpler procedure to do a global fit of two data sets with a single model. This is for the most common case of USANS+SANS data. This now appears as a new Package "Simple Global Fit". Still in testing mode, many features are intentionally NOT there. This is supposed to be simple. Not all features will be added.

Includes, GlobalFit? changed to accomodate the new procedure, and provide better formatted report.

Main_USANS changed to repair display glitch on main panel in the status listbox

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