source: sans/Dev/trunk/NCNR_User_Procedures/Analysis/Packages/Wrapper_v40.ipf @ 856

Last change on this file since 856 was 856, checked in by srkline, 11 years ago

Added a menu option in the SANS Models ->1D to map chi-squared as a function of a chosen parameter. Instructive to see how if varies for any parameter, or to see if you're really at a minimum. Right now shows only a single parameter, could be made fancier in the future if anyone cares.

File size: 50.0 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=4.10
3#pragma IgorVersion=6.1
4
5
6//Macro OpenWrapperPanel()
7//      Init_WrapperPanel()
8//End
9
10Function Init_WrapperPanel()
11
12        if(itemsinlist(WinList("SA_includes_v400.ipf", ";","INCLUDE:6"),";") != 0)
13                //must be opening a v4.00 or earlier template
14                DoAlert 0,"This experiment was created with an old version (v4.0) of the macros. I'll try to make this work, but please start new work with a current version"
15        endif
16       
17        //make sure that folders exist - this is the first initialization to be called
18        NewDataFolder/O root:Packages
19        NewDataFolder/O root:Packages:NIST
20
21        //Create useful globals
22        Variable/G root:Packages:NIST:SANS_ANA_VERSION=4.10
23        String/G root:Packages:NIST:SANS_ANA_EXTENSION="_v40"
24        //Set this variable to 1 to force use of trapezoidal integration routine for USANS smearing
25        Variable/G root:Packages:NIST:USANSUseTrap = 0
26        Variable/G root:Packages:NIST:USANS_dQv = 0.117
27        Variable/G root:Packages:NIST:gUseGenCurveFit = 0                       //set to 1 to use genetic optimization
28                       
29        //Ugly. Put this here to make sure things don't break
30        String/G root:Packages:NIST:gXMLLoader_Title
31       
32       
33        //initializes preferences. this includes XML y/n, and SANS Reduction items.
34        // if they already exist, they won't be overwritten
35        Execute "Initialize_Preferences()"             
36       
37        DoWindow/F WrapperPanel
38        if(V_flag==0)
39                if(exists("root:Packages:NIST:coefKWStr")==0)
40                        String/G root:Packages:NIST:coefKWStr=""
41                endif
42                if(exists("root:Packages:NIST:suffixKWStr")==0)
43                        String/G root:Packages:NIST:suffixKWStr=""
44                endif
45                if(exists("root:Packages:NIST:paramKWStr")==0)
46                        String/G root:Packages:NIST:paramKWStr=""
47                endif
48                Execute "WrapperPanel()"
49        endif
50End
51
52////////
53//
54// if model is Smeared, search the DF for coefficients
55// if new DF chosen, need to reset
56// if new model function, need to reset table
57//
58// create hold_mod (0/1), constr_low_mod, constr_hi_mod
59// in either DF (smeared) or in root: (normal)
60// and put these in the table as needed
61//
62Window WrapperPanel()
63        PauseUpdate; Silent 1           // building window...
64        NewPanel /W=(459,44,1113,499)/N=wrapperPanel/K=1 as "Curve Fit Setup"
65        ModifyPanel fixedSize=1
66       
67        GroupBox grpBox_0,pos={18,11},size={390,113}
68        GroupBox grpBox_1,pos={426,10},size={207,113}
69        GroupBox grpBox_2 title="No Fit",pos={10,130},size={0,0},frame=1,fSize=10,fstyle=1,fColor=(39321,1,1)
70        GroupBox grpBox_3 title="",pos={10,150},size={0,0},frame=1,fSize=10,fstyle=1,fColor=(39321,1,1)
71
72        Button button_1,pos={280,57},size={120,20},proc=PlotModelFunction,title="Plot 1D Function"
73        Button button_2,pos={300,93},size={100,20},proc=AppendModelToTarget,title="Append 1D"
74        Button button_3,pos={300,20},size={100,20},proc=W_LoadDataButtonProc,title="Load 1D Data"
75        PopupMenu popup_0,pos={30,21},size={218,20},title="Data Set",proc=DataSet_PopMenuProc
76        PopupMenu popup_0,mode=1,value= #"W_DataSetPopupList()"
77        PopupMenu popup_1,pos={30,57},size={136,20},title="Function"
78        PopupMenu popup_1,mode=1,value= #"W_FunctionPopupList()",proc=Function_PopMenuProc
79        PopupMenu popup_2,pos={30,93},size={123,20},title="Coefficients"
80        PopupMenu popup_2,mode=1,value= #"W_CoefPopupList()",proc=Coef_PopMenuProc
81        CheckBox check_0,pos={430,19},size={79,14},title="Use Cursors?",value= 0
82        CheckBox check_0,proc=UseCursorsWrapperProc
83        CheckBox check_1,pos={430,42},size={74,14},title="Use Epsilon?",value= 0
84        CheckBox check_2,pos={430,65},size={95,14},title="Use Constraints?",value= 0
85        CheckBox check_3,pos={530,18},size={72,14},title="2D Functions?",value= 0
86        CheckBox check_3 proc=Toggle2DControlsCheckProc
87        CheckBox check_4,pos={430,85},size={72,14},title="Report?",value= 0
88        CheckBox check_5,pos={444,103},size={72,14},title="Save it?",value= 0
89        CheckBox check_6,pos={530,42},size={72,14},title="Use Residuals?",value= 0
90        CheckBox check_6,proc=UseResidualsCheckProc
91        CheckBox check_7,pos={530,65},size={72,14},title="Info Box?",value= 0
92        CheckBox check_7,proc=UseInfoTextBoxCheckProc
93        //change draw order to put button over text of checkbox
94        Button button_0,pos={520,93},size={100,20},proc=DoTheFitButton,title="Do 1D Fit"
95        Button button_4,pos={520,126},size={100,20},proc=FeedbackButtonProc,title="Feedback"
96        Button button_5,pos={520,150},size={100,20},proc=FitHelpButtonProc,title="Help"
97
98        Edit/W=(20,174,634,435)/HOST=# 
99        ModifyTable width(Point)=0
100        RenameWindow #,T0
101        SetActiveSubwindow ##
102EndMacro
103
104//open the Help file for the Fit Manager
105Function FitHelpButtonProc(ba) : ButtonControl
106        STRUCT WMButtonAction &ba
107
108        switch( ba.eventCode )
109                case 2: // mouse up
110                        // click code here
111                        DisplayHelpTopic/Z/K=1 "Fit Manager"
112                        if(V_flag !=0)
113                                DoAlert 0,"The Fit Manager Help file could not be found"
114                        endif
115                        break
116        endswitch
117
118        return 0
119End
120
121
122//open the trac page for feedback
123Function FeedbackButtonProc(ba) : ButtonControl
124        STRUCT WMButtonAction &ba
125
126        switch( ba.eventCode )
127                case 2: // mouse up
128                        // click code here
129                        OpenTracTicketPage()
130                        break
131        endswitch
132
133        return 0
134End
135
136
137//obvious use, now finds the most recent data loaded, finds the folder, and pops the menu with that selection...
138//
139Function W_LoadDataButtonProc(ba) : ButtonControl
140        STRUCT WMButtonAction &ba
141
142        switch( ba.eventCode )
143                case 2: // mouse up
144                        // click code here
145                        String  topGraph= WinName(0,1)
146                        if(strlen(topGraph) != 0)
147                                DoWindow/F $topGraph                    //so that the panel is not on top
148                        endif
149                        Execute "A_LoadOneDData()"
150                       
151                        ControlUpdate/W=WrapperPanel popup_0
152                        //instead of a simple controlUpdate, better to pop the menu to make sure that the other menus follow
153                        // convoluted method to find the right item and pop the menu.
154
155                        // data is plotted, so get the "new" top graph
156                        topGraph= WinName(0,1)  //this is the topmost graph, and should exist, but...
157                        if(cmpstr(topGraph,"")==0)
158                                return(0)
159                        endif
160                        String list,folderStr
161                        Variable num
162                        list = TraceNameList(topGraph,";",1)            //want the last item in the list
163                        num= ItemsInList(list)
164                        FolderStr = StringFromList(num-1,list,";")
165                        folderStr = folderStr[0,strlen(folderStr)-3]            //remove the "_i" that the loader enforced
166                        list = W_DataSetPopupList()
167                        num=WhichListItem(folderStr,list,";",0,0)
168                        if(num != -1)
169                                PopupMenu popup_0,mode=num+1,win=WrapperPanel
170                                ControlUpdate/W=WrapperPanel popup_0
171                               
172                                // fake mouse up to pop the menu
173                                Struct WMPopupAction ps
174                                ps.eventCode = 2                //fake mouse up
175                                DataSet_PopMenuProc(ps)
176                        endif
177                        break
178        endswitch
179       
180        return 0
181End
182
183
184// is there a simpler way to do this? I don't think so.
185Function/S W_DataSetPopupList()
186
187        String str=GetAList(4)
188
189        if(strlen(str)==0)
190                str = "No data loaded"
191        endif
192        str = SortList(str)
193       
194        return(str)
195End
196
197
198// show the available models
199// not the f*(cw,xw) point calculations
200// not the *X(cw,xw) XOPS
201//
202// KIND:10 should show only user-defined curve fitting functions
203// - not XOPs
204// - not other user-defined functions
205Function/S W_FunctionPopupList()
206        String list,tmp
207        //get every user defined curve fit function, remove everything the user doesn't need to see...
208        list = User_FunctionPopupList()         
209
210        if(strlen(list)==0)
211                list = "No functions plotted"
212        endif
213       
214        list = SortList(list)
215        return(list)
216End
217
218
219// show all the appropriate coefficient waves
220//
221// also need to search the folder listed in "data set" popup
222// for smeared coefs
223//
224// - or - restrict the coefficient list based on the model function
225// - new way, filter the possible values based on the data folder and function
226Function/S W_CoefPopupList()
227
228        String notPlotted="Please plot the function"
229        ControlInfo/W=wrapperpanel popup_1
230        String funcStr=S_Value
231        String coefStr=getFunctionCoef(funcStr)
232       
233        if(cmpstr(coefStr,"")==0)               //no correspondence in the KW string
234                return(notPlotted)
235        endif
236       
237       
238        //found a coefficient wave - only two places to look
239        // is it in the root folder?
240        if(exists("root:"+coefStr) != 0)
241                return(coefStr)
242        endif
243       
244        // is it in the data folder?
245        ControlInfo/W=wrapperpanel popup_0
246        String folderStr=S_Value
247        if(exists("root:"+folderStr+":"+coefStr) != 0)
248                return(coefStr)
249        endif
250
251        return(notPlotted)
252End
253
254// show all the appropriate coefficient waves
255//
256// also need to search the folder listed in "data set" popup
257// for smeared coefs
258//
259// - or - restrict the coefficient list based on the model function
260//
261// --old way
262//Function/S W_CoefPopupList()
263//      String list
264//      setDataFolder root:
265//      list = WaveList("coef*",";","")
266//     
267//      ControlInfo/W=wrapperpanel popup_0
268//      if(V_Value != 0)                //0== no items in menu
269//              if(DataFolderExists("root:"+S_Value))
270//                      SetDataFolder $("root:"+S_Value)
271//                      list += WaveList("*coef*",";","")
272//              endif
273//      endif
274//     
275//      // tmp coefficients that aren't being cleaned up from somewhere...
276//      list = RemoveFromList("temp_coef_1;temp_coef_2;", list  ,";")
277//
278//      if(strlen(list)==0)
279//              list = "No functions plotted"
280//      endif
281//      list = SortList(list)
282//     
283////    Print itemsinlist(list,";")
284//     
285//      setDataFolder root:
286//      return(list)
287//End
288
289// if the coefficients are changed, then update the table
290//
291//update the table
292// may be easier to just kill the subwindow (table) and create a new one
293// need to set/reset all of the waves in the table
294//
295// !! only respond to mouse up
296//
297Function Coef_PopMenuProc(pa) : PopupMenuControl
298        STRUCT WMPopupAction &pa
299
300        switch( pa.eventCode )
301                case 2: // mouse up
302                        Variable popNum = pa.popNum
303                        String popStr = pa.popStr
304                        ControlInfo/W=WrapperPanel popup_1
305                        String funcStr=S_Value
306                        String suffix = getModelSuffix(funcStr)
307                        ControlInfo/W=WrapperPanel popup_0
308                        String folderStr=S_Value
309                       
310                        if(cmpstr(popStr,"Please plot the function")==0)
311//                              Print "function not plotted"
312                                return(0)
313                        endif
314
315// this if/else/endif should not ever return an error alert     
316// it should simply set the data folder properly       
317                        if(DataFolderExists("root:"+folderStr))
318                                SetDataFolder $("root:"+folderStr)
319                                if(!exists(popStr))
320                                        // must be unsmeared model, work in the root folder
321                                        SetDataFolder root:                             
322                                        if(!exists(popStr))             //this should be fine if the coef filter is working, but check anyhow
323                                                DoAlert 0,"the coefficient and data sets do not match (1)"
324                                                return 0
325                                        endif
326                                endif
327                        else
328                                // must be unsmeared model, work in the root folder
329                                SetDataFolder root:     
330                                if(!exists(popStr))             //this should be fine if the coef filter is working, but check anyhow
331                                        DoAlert 0,"the coefficient and data sets do not match (2)"
332                                        return 0
333                                endif
334                        endif
335                       
336                        // farm the work out to another function?
337                        Variable num=numpnts($popStr)
338                        // make the necessary waves if they don't exist already
339                        if(exists("Hold_"+suffix) == 0)
340                                Make/O/D/N=(num) $("epsilon_"+suffix),$("Hold_"+suffix)
341                                Make/O/T/N=(num) $("LoLim_"+suffix),$("HiLim_"+suffix)
342                                Wave eps = $("epsilon_"+suffix)
343                                Wave coef=$popStr
344                                if(eps[0] == 0)         //if eps already if filled, don't change it
345                                        eps = abs(coef*1e-4) + 1e-10                    //default eps is proportional to the coefficients
346                                endif
347                        endif
348                        // default epsilon values, sometimes needed for the fit
349                       
350                        WAVE/T LoLim = $("LoLim_"+suffix)
351                        WAVE/T HiLim = $("HiLim_"+suffix)
352                       
353                        // clear the table (a subwindow)
354                        DoWindow/F WrapperPanel                         // ?? had to add this in during all of the cursor meddling...
355                        KillWindow wrapperPanel#T0
356                        Edit/W=(20,174,634,435)/HOST=wrapperPanel
357                        RenameWindow #,T0
358                        // get them onto the table
359                        // how do I get the parameter name?
360                        String param = getFunctionParams(funcStr)
361                        AppendtoTable/W=wrapperPanel#T0 $param,$(popStr)
362                        AppendToTable/W=wrapperPanel#T0 $("Hold_"+suffix),$("LoLim_"+suffix),$("HiLim_"+suffix),$("epsilon_"+suffix)
363                        ModifyTable/W=wrapperPanel#T0 width(Point)=0
364                       
365                        SetDataFolder root:
366                        break
367        endswitch
368
369        return 0
370End
371
372// if the Function is changed, then update the coef popup (if possible) and then the table (if possible)
373//
374// !! only respond to mouse up
375//
376Function Function_PopMenuProc(pa) : PopupMenuControl
377        STRUCT WMPopupAction &pa
378
379        switch( pa.eventCode )
380                case 2: // mouse up
381                        Variable popNum = pa.popNum
382                        String funcStr = pa.popStr
383                        String coefStr = W_CoefPopupList()
384                       
385//                      Print "coefStr = ",coefStr
386                       
387                        ControlInfo/W=WrapperPanel popup_0
388                        String folderStr=S_Value
389                       
390                        String listStr = W_CoefPopupList()
391                        Variable num=WhichListItem(coefStr, listStr, ";")
392                        String str=StringFromList(num, listStr  ,";")
393//                      print "str = ",str
394                        //set the item in the coef popup, and pop it
395                        PopupMenu popup_2 win=WrapperPanel,mode=(num+1)
396                       
397                        Struct WMPopupAction ps
398                        ps.eventCode = 2                //fake mouse up
399                        ps.popStr = str
400                        Coef_PopMenuProc(ps)
401                       
402                        SetDataFolder root:
403                        break
404        endswitch
405
406        return 0
407End
408
409// if the Data Set is changed, then update the function (if possible)
410// and the coef popup (if possible) and then the table (if possible)
411//
412// !! only respond to mouse up here, and simply send a fake mouse up
413// to the function pop, which will do what it can do
414//
415Function DataSet_PopMenuProc(pa) : PopupMenuControl
416        STRUCT WMPopupAction &pa
417       
418        switch( pa.eventCode )
419                case 2: // mouse up
420                        // make sure that the cursors are on/off appropriately
421                        // let the cursors checkbox decide what to do, sending the current state
422                        ControlInfo/W=WrapperPanel check_0
423                        STRUCT WMCheckboxAction cba
424                        cba.eventCode = 2
425                        cba.checked = V_Value
426                        UseCursorsWrapperProc(cba)
427                                       
428                        // then cascade the function/coefficient popups
429                        Struct WMPopupAction ps
430                        ps.eventCode = 2                //fake mouse up
431                        Function_PopMenuProc(ps)
432                       
433                        SetDataFolder root:
434                        break
435        endswitch
436
437        return 0
438End
439
440
441// always pass this the function string
442//
443// this is new in the 2009 release, so make sure that it generates itself as needed.
444// Two options: (1) search and construct as needed, ask for intervention if I need it.
445// (2) since I'm passed the function, try to replot it to re-run the function
446// to fill in the strings. (Being sure to save the coefficients)
447//
448// using method (1) to fill in what I need with no intervention
449//
450Function/S getFunctionParams(funcStr)
451        String funcStr
452
453        String paramStr=""
454        SVAR/Z listStr=root:Packages:NIST:paramKWStr
455
456        if(SVAR_Exists(listStr))
457                paramStr = StringByKey(funcStr, listStr  ,"=",";",0)
458                if(strlen(paramStr)!=0)                 //will drop out of loop if string can't be found
459                        return(paramStr)
460                endif
461        else    //global string does not exist, create it and fill it in
462                Variable/G root:Pacakges:NIST:gReconstructStrings = 1                   //coefficients old style and must be rebuilt too
463                String/G root:Packages:NIST:paramKWStr=""
464                SVAR/Z listStr=root:Packages:NIST:paramKWStr
465        endif   
466       
467        // find everything to rebuild only if the model has been plotted (if so, coefficients will exist)
468        String coef = getFunctionCoef(funcStr)
469        if(strlen(coef)==0)
470                //model not plotted, don't reconstruct, return null string
471                return(paramStr)
472        endif
473       
474        ///// NEED TO BE IN PROPER DATA FOLDER FOR SMEARED FUNCTIONS
475        // FUNCTION POP MENU WILL LOOK IN ROOT OTHERWISE
476        ControlInfo/W=WrapperPanel popup_0
477        String folderStr=S_Value
478        // this if/else/endif should not ever return an error alert     
479        // it should simply set the data folder properly       
480        if(Stringmatch(funcStr,"Smear*"))               //simple test for smeared function
481                if(DataFolderExists("root:"+folderStr))
482                        SetDataFolder $("root:"+folderStr)
483                else
484                        SetDataFolder root:
485                endif
486        else
487                SetDataFolder root:
488        endif
489       
490        // model was plotted, find the suffix to fill in the parameter wave
491        SVAR suffListStr=root:Packages:NIST:suffixKWStr
492        String suffix = StringByKey(coef, suffListStr  ,"=",";",0)
493       
494        String paramWave = WaveList("*par*"+suffix,"","TEXT:1")         //should be one wave name, no trailing semicolon
495        listStr += funcStr+"="+paramWave+";"
496
497        //now look it up again
498        paramStr = StringByKey(funcStr, listStr  ,"=",";",0)
499
500        return(paramStr)
501End
502
503// always pass this the function string
504//
505Function/S getFunctionCoef(funcStr)
506        String funcStr
507
508        SVAR listStr=root:Packages:NIST:coefKWStr
509        String coefStr = StringByKey(funcStr, listStr  ,"=",";",0)
510
511        return(coefStr)
512End
513
514// always pass this the Function string
515//
516// does NOT return the leading "_" as part of the suffix
517// may need to set the string correctly - so lost of messing around for back-compatibility
518Function/S getModelSuffix(funcStr)
519        String funcStr
520
521        SVAR listStr=root:Packages:NIST:suffixKWStr
522        String suffixStr = StringByKey(funcStr, listStr  ,"=",";",0)
523
524        if(strlen(suffixStr) !=0)               //found it, get out
525                return(suffixStr)
526        endif
527       
528        // was the model plotted?
529        String coef = getFunctionCoef(funcStr)
530        if(strlen(coef)==0)             
531                //nothing plotted
532                return("")
533        else
534                //plotted, find the coeff
535                String suffix = StringByKey(coef, ListStr  ,"=",";",0)
536       
537                // add to the suffix list in the new style, if it was found
538                if(strlen(suffix) !=0)
539                        listStr += funcStr+"="+suffix+";"
540                endif
541                return(suffix)
542        endif
543       
544        return("")
545End
546
547
548
549// - this is based on stringent "PlotNNN" naming requirements
550//
551//  ???
552// - how to kill the generated table and graph, that are not needed now
553//
554Function PlotModelFunction(ba) : ButtonControl
555        STRUCT WMButtonAction &ba
556
557        String folderStr,funcStr,coefStr,cmdStr=""
558        Variable useCursors,useEps,useConstr
559       
560        Variable killWhat=0             //kill nothing as default
561       
562        switch( ba.eventCode )
563                case 2: // mouse up
564                        ControlInfo/W=WrapperPanel popup_0
565                        folderStr=S_Value
566                       
567                        ControlInfo/W=WrapperPanel popup_1
568                        funcStr=S_Value
569                       
570                        // maybe nothing has been loaded yet...
571                        if(cmpstr(funcStr,"No functions plotted") == 0)
572                                break
573                        endif
574                       
575                        // check for smeared or smeared function
576                        if(stringmatch(funcStr, "Smear*" )==1)
577                                //it's a smeared model
578                                // check for the special case of RPA that has an extra parameter
579                                if(strsearch(funcStr, "RPAForm", 0 ,0) == -1)
580                                        sprintf cmdStr, "Plot%s(\"%s\")",funcStr,folderStr              //not RPA
581                                else
582                                        sprintf cmdStr, "Plot%s(\"%s\",)",funcStr,folderStr             //yes RPA, leave a comma for input
583                                endif
584                                killWhat = 1
585                        else
586                                // it's not,    don't kill the graph, just the table           
587                                sprintf cmdStr, "Plot%s()",funcStr
588                                killWhat = 2
589                        endif
590                       
591                        //Print cmdStr
592                        Execute cmdStr
593                       
594                        //pop the function menu to set the proper coefficients
595                        DoWindow/F WrapperPanel
596                        STRUCT WMPopupAction pa
597                        pa.popStr = funcStr
598                        pa.eventcode = 2
599                        Function_PopMenuProc(pa)
600       
601                        KillTopGraphAndTable(killWhat)          // crude
602       
603                        break
604        endswitch
605       
606        return 0
607End
608
609// passing 0 kills nothing
610// passing 1 kills the top graph and table
611// passing 2 kills the top table only
612//
613Function KillTopGraphAndTable(killwhat)
614        Variable killWhat
615       
616        String topGraph= WinName(0,1)   //this is the topmost graph     
617        String topTable= WinName(0,2)   //this is the topmost table
618
619        if(killWhat == 0)
620                return(0)
621        endif
622       
623        if(killWhat == 1)
624                KillWindow $topGraph
625                KillWindow $topTable
626        endif
627       
628        if(killWhat == 2)
629                KillWindow $topTable
630        endif
631       
632        return(0)
633End
634
635// How to bypass the step of plot and append?
636//
637// do it in two separate events
638//
639Function AppendModelToTarget(ba) : ButtonControl
640        STRUCT WMButtonAction &ba
641
642        String coefStr,suffix,yWStr,xWStr,folderStr,funcStr
643       
644        switch( ba.eventCode )
645                case 2: // mouse up                     
646                        ControlInfo/W=WrapperPanel popup_2
647                        coefStr=S_Value
648                       
649                        ControlInfo/W=WrapperPanel popup_1
650                        funcStr=S_Value
651                        suffix = getModelSuffix(funcStr)
652                       
653                        // check for smeared or smeared function
654                        if(stringmatch(coefStr, "smear*" )==1)
655                                //it's a smeared model
656                                ControlInfo/W=WrapperPanel popup_0
657                                folderStr=S_Value
658                                xWStr = "root:"+folderStr+":smeared_qvals"
659                                ywStr = "root:"+folderStr+":smeared_"+suffix
660                        else
661                                // it's not, so it's in the root folder
662                                xWStr = "xwave_"+suffix
663                                yWStr = "ywave_"+suffix
664                        endif
665                       
666                        Wave/Z yw = $yWStr
667                        Wave/Z xw = $xWStr
668                        if(WaveExists(yw) && WaveExists(xw))
669                                AppendtoGraph yw vs xw
670                        else
671                                DoAlert 0,"The selected model has not been plotted for the selected data set."
672                        endif
673                        break
674        endswitch
675       
676        return 0
677End
678
679
680// this should parse the panel and call the FitWrapper() function
681Function DoTheFitButton(ba) : ButtonControl
682        STRUCT WMButtonAction &ba
683
684        String folderStr,funcStr,coefStr
685        Variable useCursors,useEps,useConstr,useResiduals,useTextBox
686       
687        switch( ba.eventCode )
688                case 2: // mouse up
689                        ControlInfo/W=WrapperPanel popup_0
690                        folderStr=S_Value
691                       
692                        ControlInfo/W=WrapperPanel popup_1
693                        funcStr=S_Value
694                       
695                        ControlInfo/W=WrapperPanel popup_2
696                        coefStr=S_Value
697                       
698                        ControlInfo/W=WrapperPanel check_0
699                        useCursors=V_Value
700                        ControlInfo/W=WrapperPanel check_1
701                        useEps=V_Value
702                        ControlInfo/W=WrapperPanel check_2
703                        useConstr=V_Value
704                       
705                        ControlInfo/W=WrapperPanel check_6
706                        useResiduals=V_Value
707                       
708                        ControlInfo/W=WrapperPanel check_7
709                        useTextBox = V_Value
710                       
711                        if(!CheckFunctionAndCoef(funcStr,coefStr))
712                                DoAlert 0,"The coefficients and function type do not match. Please correct the selections in the popup menus."
713                                break
714                        endif
715                       
716                        FitWrapper(folderStr,funcStr,coefStr,useCursors,useEps,useConstr,useResiduals,useTextBox)
717                       
718                        //      DoUpdate (does not work!)
719                        //?? why do I need to force an update ??
720                        if(!exists("root:"+folderStr+":"+coefStr))
721                                Wave w=$coefStr
722                        else
723                                Wave w=$("root:"+folderStr+":"+coefStr) //smeared coefs in data folder
724                        endif
725                        w[0] += 1e-6
726                        w[0] -= 1e-6
727       
728                        break
729        endswitch
730       
731        return 0
732End
733
734Function CheckFunctionAndCoef(funcStr,coefStr)
735        String funcStr,coefStr
736       
737        SVAR listStr=root:Packages:NIST:coefKWStr
738        String properCoefStr = StringByKey(funcStr, listStr  ,"=",";",0)
739        if(cmpstr("",properCoefStr)==0)
740                return(0)               //false, no match found, so properCoefStr is returned null
741        endif
742        if(cmpstr(coefStr,properCoefStr)==0)
743                return(1)               //true, the coef is the correct match
744        endif
745        return(0)                       //false, wrong coef
746End
747
748/////////////////////////////////
749
750// wrapper to do the desired fit
751//
752// folderStr is the data folder for the desired data set
753//
754//
755Function FitWrapper(folderStr,funcStr,coefStr,useCursors,useEps,useConstr,useResiduals,useTextBox)
756        String folderStr,funcStr,coefStr
757        Variable useCursors,useEps,useConstr,useResiduals,useTextBox
758
759        String suffix=getModelSuffix(funcStr)
760       
761        SetDataFolder $("root:"+folderStr)
762        if(!exists(coefStr))
763                // must be unsmeared model, work in the root folder
764                SetDataFolder root:                             
765                if(!exists(coefStr))            //this should be fine if the coef filter is working, but check anyhow
766                        DoAlert 0,"the coefficient and data sets do not match"
767                        return 0
768                endif
769        endif
770               
771        WAVE cw=$(coefStr)     
772        Wave hold=$("Hold_"+suffix)
773        Wave/T lolim=$("LoLim_"+suffix)
774        Wave/T hilim=$("HiLim_"+suffix)
775       
776        if(useEps)
777                Wave eps=$("epsilon_"+suffix)
778        endif
779// fill a struct instance whether I need one or not
780        String DF="root:"+folderStr+":"
781       
782        Struct ResSmearAAOStruct fs
783        WAVE/Z resW = $(DF+folderStr+"_res")                    //these may not exist, if 3-column data is used
784        WAVE/Z fs.resW =  resW
785        WAVE yw=$(DF+folderStr+"_i")
786        WAVE xw=$(DF+folderStr+"_q")
787        WAVE sw=$(DF+folderStr+"_s")
788        Wave fs.coefW = cw
789        Wave fs.yW = yw
790        Wave fs.xW = xw
791       
792        Duplicate/O yw $(DF+"FitYw")
793        WAVE fitYw = $(DF+"FitYw")
794        fitYw = NaN
795       
796        Variable useResol=0,isUSANS=0,val
797        if(stringmatch(funcStr, "Smear*"))              // if it's a smeared function, need a struct
798                useResol=1
799        endif
800        if(dimsize(resW,1) > 4)
801                isUSANS=1
802        endif
803       
804        // do not construct constraints for any of the coefficients that are being held
805        // -- this will generate an "unknown error" from the curve fitting
806        // -- if constraints are not used, the constr wave is killed. This apparently
807        // confuses the /NWOK flag, since there is not even a null reference present. So generate one.
808        if(useConstr)
809                Make/O/T/N=0 constr
810                String constraintExpression
811                Variable i, nPnts=DimSize(lolim, 0),nextRow=0
812                for (i=0; i < nPnts; i += 1)
813                        if (strlen(lolim[i]) > 0 && hold[i] == 0)
814                                InsertPoints nextRow, 1, constr
815                                sprintf constraintExpression, "K%d > %s", i, lolim[i]
816                                constr[nextRow] = constraintExpression
817                                nextRow += 1
818                        endif
819                        if (strlen(hilim[i]) > 0 && hold[i] == 0)
820                                InsertPoints nextRow, 1, constr
821                                sprintf constraintExpression, "K%d < %s", i, hilim[i]
822                                constr[nextRow] = constraintExpression
823                                nextRow += 1
824                        endif
825                endfor
826        else
827                Wave/T/Z constr = constr
828                KillWaves/Z constr
829                Wave/T/Z constr = constr                //this is intentionally a null reference
830        endif
831
832        // 20JUN if useCursors is true, and there are no cursors on the specified data set, uncheck and set to false
833        // this is a last line of defense, and should never actually do anything...
834        if(useCursors)
835                useCursors = AreCursorsCorrect(folderStr)
836        endif
837        //if useCursors, and the data is USANS, need to recalculate the matrix if the range is new
838        Variable pt1,pt2,newN,mPt1,mPt2
839        String noteStr
840        if(useCursors && isUSANS )
841                //where are the cursors, and what is the status of the current matrix?
842                if(pcsr(A) > pcsr(B))
843                        pt1 = pcsr(B)
844                        pt2 = pcsr(A)
845                else
846                        pt1 = pcsr(A)
847                        pt2 = pcsr(B)
848                endif
849               
850                noteStr = note(resW)
851                mPt1 = NumberByKey("P1",noteStr,"=",";")
852                mPt2 = NumberByKey("P2",noteStr,"=",";")
853                if((mPt1 != pt1) || (mPt2 != pt2) )
854                        // need to recalculate
855                        USANS_RE_CalcWeights(folderStr,pt1,pt2)
856                        Print "Done recalculating the matrix"
857                endif
858               
859                Wave trimResW=$(DF+folderStr+"_res"+"t")        //put the trimmed resW in the struct for the fit!
860                Wave fs.resW=trimResW
861        endif
862        if(useCursors)
863                //find the points so that genetic optimization can use them
864                if(pcsr(A) > pcsr(B))
865                        pt1 = pcsr(B)
866                        pt2 = pcsr(A)
867                else
868                        pt1 = pcsr(A)
869                        pt2 = pcsr(B)
870                endif
871        else
872                //if cursors are not being used, find the first and last points of the data set, and pass them
873                pt1 = 0
874                pt2 = numpnts(yw)-1
875        endif
876               
877// create these variables so that FuncFit will set them on exit
878        Variable/G V_FitError=0                         //0=no err, 1=error,(2^1+2^0)=3=singular matrix
879        Variable/G V_FitQuitReason=0            //0=ok,1=maxiter,2=user stop,3=no chisq decrease
880
881        NVAR useGenCurveFit = root:Packages:NIST:gUseGenCurveFit
882// don't use the auto-destination with no flag, it doesn't appear to work correctly
883// dispatch the fit
884
885// currently, none of the fit functions are defined as threadsafe, so I don't think that the /NTHR flag really
886// does anything. The functions themselves can be threaded since they are AAO, and that is probably enough,
887// since it doesn't make much sense to thread threads. In addition, there is a little-publicized warning
888// in the WM help file that /C=texWave cannot be used to specify constraints for threadsafe functions!
889// The textwave would have to be parsed into a constraint matrix first, then passed as /C={cMat,cVec}.
890// -- just something to watch out for.
891
892// now two more flags... ,useResiduals,useTextBox
893        Variable tb = 1+2+4+8+16+256+512                //See CurveFit docs for bit settings for /TBOX flag
894
895        do
896                Variable t0 = stopMStimer(-2)           // corresponding print is at the end of the do-while loop (outside)
897
898
899                if(useGenCurveFit)
900               
901#if !(exists("GenCurveFit"))
902                        // XOP not available
903                        useGenCurveFit = 0
904                        Abort "Genetic Optimiztion XOP not available. Reverting to normal optimization."       
905#endif
906                        //send everything to a function, to reduce the clutter
907                        // useEps and useConstr are not needed
908                        // pass the structure to get the current waves, including the trimmed USANS matrix
909                        //
910                        // I don't know that GetCurveFit can do residuals, so I'm not passing that flag, or the text box flag
911                        //
912                        Variable chi,pt
913
914                        chi = DoGenCurveFit(useResol,useCursors,sw,fitYw,fs,funcStr,getHStr(hold),val,lolim,hilim,pt1,pt2)
915                        pt = val
916
917                        break
918                       
919                endif
920               
921                // now useCursors, useEps, and useConstr are all handled w/ /NWOK
922                // so there are only three conditions to test == 1 + 3 + 3 + 1 = 8 conditions
923               
924                if(useResol && useResiduals && useTextBox)              //do it all
925                        FuncFit/H=getHStr(hold) /M=2 /NTHR=0 /TBOX=(tb) $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /STRC=fs /R /NWOK
926                        break
927                endif
928               
929                if(useResol && useResiduals)            //res + resid
930                        FuncFit/H=getHStr(hold) /M=2 /NTHR=0 $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /STRC=fs /R /NWOK
931                        break
932                endif
933
934               
935                if(useResol && useTextBox)              //res + text
936                        FuncFit/H=getHStr(hold) /M=2 /NTHR=0 /TBOX=(tb) $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /STRC=fs /NWOK
937                        break
938                endif
939               
940                if(useResol)            //res only
941//                      Print "timing test for Cylinder_PolyRadius---"
942//                      Variable t0 = stopMStimer(-2)
943
944                        FuncFit/H=getHStr(hold) /M=2 /NTHR=0 $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /STRC=fs /NWOK
945                       
946//                      t0 = (stopMSTimer(-2) - t0)*1e-6
947//                      Printf  "CylPolyRad fit time using res and eps and /NTHR=0 time = %g seconds\r\r",t0
948//                      cw[0] = .01
949//                      cw[1] = 20
950//                      cw[2] = 400
951//                      cw[3] = 0.2
952//                      cw[4] = 3e-6
953//                      cw[5] = 0.0
954//                     
955//                      t0 = stopMSTimer(-2)
956//                      FuncFit/H=getHStr(hold) /NTHR=0 $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /STRC=fs /NWOK
957//                      t0 = (stopMSTimer(-2) - t0)*1e-6
958//                      Printf  "CylPolyRad fit time using res and eps and NO THREADING time = %g seconds\r\r",t0
959                        break
960                endif
961                       
962               
963               
964/////   same as above, but all without useResol (no /STRC flag)
965                if(useResiduals && useTextBox)          //resid+ text
966                        FuncFit/H=getHStr(hold) /M=2 /NTHR=0 /TBOX=(tb) $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /R /NWOK
967                        break
968                endif
969               
970                if(useResiduals)                //resid
971                        FuncFit/H=getHStr(hold) /M=2 /NTHR=0 $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /R /NWOK
972                        break
973                endif
974
975               
976                if(useTextBox)          //text
977                        FuncFit/H=getHStr(hold) /M=2 /NTHR=0 /TBOX=(tb) $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /NWOK
978                        break
979                endif
980               
981                //just a plain vanilla fit
982
983                FuncFit/H=getHStr(hold) /M=2 /NTHR=0 $funcStr cw, yw[pt1,pt2] /X=xw /W=sw /I=1 /E=eps /D=fitYw /C=constr /NWOK
984               
985        while(0)
986       
987        t0 = (stopMSTimer(-2) - t0)*1e-6
988        Printf  "fit time = %g seconds\r\r",t0
989       
990       
991        // append the fit
992        // need to manage duplicate copies
993        // Don't plot the full curve if cursors were used (set fitYw to NaN on entry...)
994        String traces=TraceNameList("", ";", 1 )                //"" as first parameter == look on the target graph
995        if(strsearch(traces,"FitYw",0) == -1)
996                if(useGenCurveFit && useCursors)
997                        WAVE trimX = trimX
998                        AppendtoGraph fitYw vs trimX
999                else
1000                        AppendToGraph FitYw vs xw
1001                endif
1002        else
1003                RemoveFromGraph FitYw
1004                if(useGenCurveFit && useCursors)
1005                        WAVE trimX = trimX
1006                        AppendtoGraph fitYw vs trimX
1007                else
1008                        AppendToGraph FitYw vs xw
1009                endif
1010        endif
1011        ModifyGraph lsize(FitYw)=2,rgb(FitYw)=(0,0,0)
1012       
1013        DoUpdate                //force update of table and graph with fitted values (why doesn't this work? - the table still does not update)
1014       
1015        // report the results (to the panel?)
1016        if(useGenCurveFit)
1017                V_chisq = chi
1018                V_npnts = pt
1019        endif
1020        print "V_chisq = ",V_chisq
1021        print cw
1022        WAVE/Z w_sigma
1023        print w_sigma
1024        String resultStr=""
1025       
1026        if(waveexists(W_sigma))
1027                //append it to the table, if it's not already there
1028                CheckDisplayed/W=WrapperPanel#T0 W_sigma
1029                if(V_flag==0)
1030                        //not there, append it
1031                        AppendtoTable/W=wrapperPanel#T0 W_sigma
1032                else
1033                        //remove it, and put it back on to make sure it's the right one (do I need to do this?)
1034                        // -- not really, since any switch of the function menu takes W_Sigma off
1035                endif
1036        endif
1037       
1038        //now re-write the results
1039        sprintf resultStr,"Chi^2 = %g  Sqrt(X^2/N) = %g",V_chisq,sqrt(V_chisq/V_Npnts)
1040        resultStr = PadString(resultStr,63,0x20)
1041        GroupBox grpBox_2 title=resultStr
1042        ControlUpdate/W=WrapperPanel grpBox_2
1043        sprintf resultStr,"FitErr = %s : FitQuit = %s",W_ErrorMessage(V_FitError),W_QuitMessage(V_FitQuitReason)
1044        resultStr = PadString(resultStr,63,0x20)
1045        GroupBox grpBox_3 title=resultStr
1046        ControlUpdate/W=WrapperPanel grpBox_3
1047       
1048        Variable yesSave=0,yesReport=0
1049        ControlInfo/W=WrapperPanel check_4
1050        yesReport = V_Value
1051        ControlInfo/W=WrapperPanel check_5
1052        yesSave = V_Value
1053       
1054       
1055        if(yesReport)
1056                String parStr=GetWavesDataFolder(cw,1)+ WaveList("*param*"+"_"+suffix, "", "TEXT:1," )          // this is *hopefully* one wave
1057                String topGraph= WinName(0,1)   //this is the topmost graph
1058       
1059                DoUpdate                //force an update of the graph before making a copy of it for the report
1060
1061                //if GenCurveFit used, V_startRow and V_endRow may not exist - so read the cursors? but the cursors may not be used, so
1062                // there won't be anything on the graph... but pt1 and pt2 are set and passed!. The V_ variables are more foolproof
1063                // so keep these for the "normal" report
1064                //
1065                if(useGenCurveFit)     
1066                        W_GenerateReport(funcStr,folderStr,$parStr,cw,yesSave,V_chisq,W_sigma,V_npnts,V_FitError,V_FitQuitReason,pt1,pt2,topGraph)
1067                else
1068                        W_GenerateReport(funcStr,folderStr,$parStr,cw,yesSave,V_chisq,W_sigma,V_npnts,V_FitError,V_FitQuitReason,V_startRow,V_endRow,topGraph)
1069                endif
1070        endif
1071       
1072        SetDataFolder root:
1073        return(0)
1074End
1075
1076// parse something off of a table, or ?
1077Function/S getHStr(hold)
1078        Wave hold
1079       
1080        String str=""
1081        Variable ii
1082        for(ii=0;ii<numpnts(hold);ii+=1)
1083                str += num2str(hold[ii])
1084        endfor
1085
1086//      print str
1087        if(strsearch(str, "1", 0) == -1)
1088                return ("")
1089        else
1090                return(str)
1091        endif
1092End
1093
1094//taken from SRK Auto_Fit, and modified to work better with FitWrapper
1095//must have AutoGraph as the name of the graph window (any size)
1096// func is the name of the function (for print only)
1097//par and coef are the exact names of the waves
1098//yesSave==1 will save the file(name=func+time)
1099//
1100Function W_GenerateReport(func,dataname,param,ans,yesSave,chiSq,sigWave,npts,fitErr,fitQuit,fitStart,fitEnd,topGraph)
1101        String func,dataname
1102        Wave/T param
1103        Wave ans
1104        Variable yesSave,chiSq
1105        Wave sigWave
1106        Variable npts,fitErr,fitQuit,fitStart,fitEnd
1107        String topGraph
1108       
1109        String str,pictStr="P_"
1110        String nb="Report"
1111               
1112        // bring report up
1113        DoWindow/F Report
1114        if (V_flag == 0)                // Report notebook doesn't exist ?
1115                NewNotebook/W=(10,45,550,620)/F=1/N=Report as "Report"
1116        endif
1117        // delete old stuff
1118        Notebook $nb selection={startOfFile, endOfFile}, text="\r", selection={startOfFile, startOfFile}
1119       
1120        //setup
1121        Notebook $nb defaultTab=36, statusWidth=252, pageMargins={72,72,72,72}
1122        Notebook $nb showRuler=1, rulerUnits=1, updating={1, 60}
1123        Notebook $nb newRuler=Normal, justification=0, margins={0,0,468}, spacing={0,0,0}, tabs={}, rulerDefaults={"Geneva",10,0,(0,0,0)}
1124//     
1125        // insert title
1126        Notebook $nb newRuler=Title, justification=1, rulerDefaults={"Times", 16, 1, (0, 0, 0)}
1127        sprintf str, "Fit to %s, %s, %s\r\r", func,Secs2Date(datetime, 0), time()
1128        Notebook $nb ruler=Title, text=str
1129       
1130        // insert fit results
1131        Variable num=numpnts(ans),ii=0
1132        Notebook $nb ruler=Normal
1133        Notebook $nb  margins={18,18,504}, tabs={63 + 3*8192}
1134        str = "Data file: " + dataname + "\r\r"
1135        Notebook $nb text=str
1136        Notebook $nb ruler=Normal
1137        Notebook $nb margins={18,18,504}, tabs={144,234,252}
1138        do
1139                sprintf str, "%s = \t%g\t±\t%g\r", param[ii],ans[ii],sigwave[ii]
1140                Notebook $nb text=str
1141                ii+=1
1142        while(ii<num)
1143       
1144        //
1145        // no "fitted range" for 2D data, so make sure that this exists before using it
1146        Wave/Z dataXw = $("root:"+dataname+":"+dataname+"_q")   
1147        //
1148        Notebook $nb ruler=Normal
1149        Notebook $nb  margins={18,18,504}, tabs={63+3*8192}, fStyle=1, textRGB=(65000,0,0)
1150       
1151        sprintf str,"chisq = %g\r",chisq
1152        Notebook $nb textRGB=(65000,0,0),fstyle=1,text=str
1153        sprintf str,"Npnts = %g \t\t Sqrt(X^2/N) = %g\r",npts,sqrt(chiSq/npts)
1154        Notebook $nb textRGB=(0,0,0),fstyle=0, text=str
1155        if(WaveExists(dataXw))
1156                sprintf str "Fitted range = [%d,%d] = %g < Q < %g\r",fitStart,fitEnd,dataXw(fitStart),dataXw(fitEnd)
1157                Notebook $nb textRGB=(0,0,0),fstyle=0, text=str
1158        endif
1159        sprintf str,"FitError = %s\t\tFitQuitReason = %s\r",W_ErrorMessage(FitErr),W_QuitMessage(FitQuit)
1160        Notebook $nb textRGB=(65000,0,0),fstyle=1,text=str
1161        Notebook $nb ruler=Normal
1162       
1163        // insert graphs
1164        if(WaveExists(dataXw))
1165//              Notebook $nb picture={$topGraph(0, 0, 400, 300), -5, 1}, text="\r"
1166                Notebook $nb scaling={50, 50}, picture={$topGraph(0, 0, 800, 600), -5, 1}, text="\r"
1167        //
1168        else            //must be 2D Gizmo
1169                Execute "ExportGizmo Clip"                      //this ALWAYS is a PICT or BMP. Gizmo windows are different...
1170                LoadPict/Q/O "Clipboard",tmp_Gizmo
1171                Notebook $nb picture={tmp_Gizmo(0, 0, 800, 600), 0, 1}, text="\r"
1172        endif
1173       
1174        // show the top of the report
1175        Notebook $nb  selection= {startOfFile, startOfFile},  findText={"", 1}
1176       
1177        //save the notebook and the graphic file
1178        if(yesSave)
1179                String nameStr=CleanupName(func,0)
1180                nameStr += "_"+dataname
1181                nameStr = ReplaceString("Smeared",nameStr,"Sm_")                //if Smeared function, shorten the name
1182                //make sure the name is no more than 31 characters
1183                namestr = namestr[0,30]         //if shorter than 31, this will NOT pad to 31 characters
1184                Print "file saved as ",nameStr
1185                SaveNotebook /O/P=home/S=2 $nb as nameStr
1186                //save the graph separately as a PNG file, 2x screen
1187                pictStr += nameStr
1188                pictStr = pictStr[0,28]         //need a shorter name - why?
1189//              DoWindow/F $topGraph
1190                // E=-5 is png @screen resolution
1191                // E=2 is PICT @2x screen resolution
1192///             SavePICT /E=-5/O/P=home /I/W=(0,0,3,3) as pictStr
1193                if(WaveExists(dataXw))
1194                        SavePICT /E=-5/O/P=home/WIN=$topGraph /W=(0,0,800,600) as pictStr
1195                else
1196                        Execute "ExportGizmo /P=home as \""+pictStr+"\""                //this won't be of very high quality
1197                        //SavePICT /E=-5/O/P=home/WIN=$topGraph /W=(0,0,400,300) as pictStr
1198                endif
1199        Endif
1200       
1201        // ???maybe print the notebook too?
1202End
1203
1204Function/S W_ErrorMessage(code)
1205        Variable code
1206       
1207        switch (code)
1208                case 0:
1209                        return "No Error"
1210                        break
1211                case 3: //2^0 + 2^1
1212                        return "Singular Matrix"
1213                        break
1214                case 5:         //(2^0 + 2^2)
1215                        return "Out of Memory"
1216                        break
1217                case 9:         //(2^0 + 2^3)
1218                        return "Func= NaN or Inf"
1219                        break
1220                default:
1221                        return "Unknown error code "+num2str(code)
1222        endswitch
1223end
1224
1225Function/S W_QuitMessage(code)
1226        Variable code
1227       
1228        switch (code)
1229                case 0:
1230                        return "No Error"
1231                        break
1232                case 1:
1233                        return "Max iterations - re-run fit"
1234                        break
1235                case 2:
1236                        return "User terminated fit"
1237                        break
1238                case 3:
1239                        return "No decrease in chi-squared"
1240                        break
1241                default:
1242                        return "Unknown Quit code "+num2str(code)
1243        endswitch
1244end
1245
1246Function UseInfoTextBoxCheckProc(cba) : CheckBoxControl
1247        STRUCT WMCheckboxAction &cba
1248
1249        switch( cba.eventCode )
1250                case 2: // mouse up
1251                        Variable checked = cba.checked
1252                        if(checked)
1253                                //print "checked, use textBox in the next fit"
1254                        else
1255                                //print "unchecked, ask to remove TextBox from the graph"
1256                                ControlInfo/W=WrapperPanel popup_0
1257                                RemoveTextBox(S_value)
1258                        endif
1259                        break
1260        endswitch
1261
1262        return 0
1263End
1264
1265//does not report an error if the text box is not there
1266// -- so I'll just be lazy and not check to see if it's there
1267//
1268Function RemoveTextBox(folderStr)
1269        String folderStr
1270       
1271        DoAlert 1,"Remove the TextBox from the graph?"
1272        if(V_flag == 1)
1273                String str = "CF_"+folderStr+"_i"
1274                TextBox/K/N=$str
1275        endif
1276        return(0)
1277End
1278
1279Function UseResidualsCheckProc(cba) : CheckBoxControl
1280        STRUCT WMCheckboxAction &cba
1281
1282        switch( cba.eventCode )
1283                case 2: // mouse up
1284                        Variable checked = cba.checked
1285                        if(checked)
1286                                //print "checked, use them in the next fit"
1287                        else
1288                                //print "unchecked, ask to remove residuals from the graph"
1289                                ControlInfo/W=WrapperPanel popup_0
1290                                RemoveResiduals(S_value)
1291                        endif
1292                        break
1293        endswitch
1294
1295        return 0
1296End
1297
1298// the default name from the /R flag is "Res_" + yWaveName
1299//
1300// better to find the wave that starts with "Res_" and remove that one in case the
1301// wave names get too long
1302//
1303// the difficulty now is that the residual wave ends up in root: and not with the data....
1304// -- not really a problem, but adds to clutter
1305Function RemoveResiduals(folderStr)
1306        String folderStr
1307       
1308        String list="",topWin=""
1309        Variable num,ii
1310        String str
1311
1312        DoAlert 1,"Remove the residuals from the graph?"
1313        if(V_flag == 1)
1314//              String topGraph= WinName(0,1)   //this is the topmost graph
1315                list=TraceNameList("", ";", 1 )         //"" as first parameter == look on the target graph
1316                num=ItemsInList(list)
1317               
1318                for(ii=0;ii<num;ii+=1)
1319                        str = StringFromList(ii, list ,";")
1320                        if(strsearch(str, "Res_", 0) != -1)
1321                                RemoveFromGraph $str
1322                        endif
1323                endfor
1324       
1325                SetDataFolder root:
1326        endif
1327       
1328        return(0)
1329End
1330
1331Function Toggle2DControlsCheckProc(cba) : CheckBoxControl
1332        STRUCT WMCheckboxAction &cba
1333
1334        switch( cba.eventCode )
1335                case 2: // mouse up
1336                        Variable checked = cba.checked
1337                        if(checked)
1338                                //print "change the buttons to 2D"
1339                                Button button_0,proc=Do2DFitButtonProc,title="Do 2D Fit"
1340                                Button button_1,size={120,20},proc=Plot2DFunctionButtonProc,title="Plot 2D Function"
1341                                Button button_2,size={100,20},proc=Append2DModelButtonProc,title="Append 2D"
1342                                Button button_3,size={100,20},proc=Load2DDataButtonProc,title="Load 2D Data"
1343                               
1344                                Button button_2D_0,pos={550,60},size={70,20},proc=LogToggle2DButtonProc,title="Log/Lin"
1345                                Button button_2D_1,pos={520,37},size={100,20},proc=Plot2DButtonProc,title="Plot 2D Data"
1346                               
1347                                Button button_2D_0,disable=0            //visible again, and enabled
1348                                Button button_2D_1,disable=0
1349                               
1350                                CheckBox check_6,disable=1                      //info box and residual check, remove these from view
1351                                CheckBox check_7,disable=1
1352                        else
1353                                //print "unchecked, change them back to 1D"
1354                                Button button_0,pos={520,93},size={100,20},proc=DoTheFitButton,title="Do 1D Fit"
1355                                Button button_1,pos={280,57},size={120,20},proc=PlotModelFunction,title="Plot 1D Function"
1356                                Button button_2,pos={300,93},size={100,20},proc=AppendModelToTarget,title="Append 1D"
1357                                Button button_3,pos={300,20},size={100,20},proc=W_LoadDataButtonProc,title="Load 1D Data"
1358                               
1359                                Button button_2D_0,disable=3    //hide the extra 2D buttons, and disable
1360                                Button button_2D_1,disable=3
1361                               
1362                                CheckBox check_6,disable=0                      //info box and residual check, bring them back
1363                                CheckBox check_7,disable=0
1364                        endif
1365                        break
1366        endswitch
1367
1368        return 0
1369End
1370
1371// function to either add or remove the cursors from the topmost graph, as needed
1372
1373Function UseCursorsWrapperProc(cba) : CheckBoxControl
1374        STRUCT WMCheckboxAction &cba
1375
1376
1377        switch( cba.eventCode )
1378                case 2: // mouse up
1379               
1380                        // check to make sure there really is a "topmost" graph         
1381                        String topGraph= WinName(0,1)   //this is the topmost graph
1382                        if(cmpstr(topGraph,"")==0)      //no graphs, uncheck and exit
1383                                CheckBox check_0,value=0
1384                                return(0)
1385                        endif
1386                       
1387                        //if in 2D mode, just exit
1388                        ControlInfo/W=WrapperPanel check_3
1389                        if(V_Value == 1)
1390                                return (0)
1391                        endif
1392                               
1393                        String ciStr = CsrInfo(A , topGraph)
1394                       
1395                        ControlInfo/W=wrapperpanel popup_0
1396                        String folderStr=S_Value
1397                        String traceList = TraceNameList(topGraph, ";", 1 )             
1398               
1399                        Variable checked = cba.checked
1400                       
1401                        if(checked)
1402                                //print "add the cursors to the topmost graph, if the data set is there, or move them"
1403                                if(strlen(ciStr)==0 && strsearch(traceList, folderStr, 0) != -1 )               //no cursors && data is there
1404                                        ShowInfo
1405                                        Wave yw=$("root:"+folderStr+":"+folderStr+"_i")
1406                                        Cursor/P/W=$topGraph A, $(folderStr+"_i"),0
1407                                        Cursor/P/W=$topGraph/A=0 B, $(folderStr+"_i"),numpnts(yw)-1                     //deactivate the one at the high Q end
1408                                        DoUpdate
1409                                elseif (strlen(ciStr)!=0 && strsearch(traceList, folderStr, 0) != -1 ) //cursors present, but on wrong data
1410                                        Wave yw=$("root:"+folderStr+":"+folderStr+"_i")
1411                                        Cursor/P/W=$topGraph A, $(folderStr+"_i"),0                                                             //move the cursors
1412                                        Cursor/P/W=$topGraph/A=0 B, $(folderStr+"_i"),numpnts(yw)-1
1413                                        DoUpdate
1414                                endif
1415                               
1416                                AreCursorsCorrect(folderStr)
1417                        else
1418                                //print "unchecked, remove the cursors"
1419                                // go back to the full matrix for the resolution calculation (not if SANS data...)
1420                                if(waveExists($("root:"+folderStr+":weights_save")))
1421                                        Duplicate/O $("root:"+folderStr+":weights_save"), $("root:"+folderStr+":"+folderStr+"_res"),$("root:"+folderStr+":"+folderStr+"_rest")
1422                                endif
1423
1424                                HideInfo/W=$topGraph
1425                                Cursor/K A
1426                                Cursor/K B
1427                        endif
1428                        break
1429        endswitch
1430
1431        return 0
1432End
1433
1434// returns 1 if the specified data is on the top graph && has cursors on it
1435// returns 0 and unchecks the box if anything is wrong
1436//
1437// only call this function if the cursor box is checked, to uncheck it as needed
1438// if the box is unchecked, leave it be.
1439//
1440Function AreCursorsCorrect(folderStr)
1441        String folderStr
1442       
1443        String topGraph= WinName(0,1)   //this is the topmost graph
1444        if(cmpstr(topGraph,"")==0)      //no graphs, uncheck and exit
1445                CheckBox check_0,win=wrapperpanel,value=0
1446                return(0)
1447        endif
1448               
1449        String traceAisOn = CsrWave(A , "", 0)
1450        if(     strsearch(traceAisOn, folderStr, 0) == -1)              //data and cursors don't match
1451                CheckBox check_0,win=wrapperpanel,value=0
1452                HideInfo
1453                Cursor/K A
1454                Cursor/K B
1455                return(0)
1456        endif
1457       
1458        return(1)
1459End
1460
1461
1462
1463//////////////////////////////
1464//
1465// displays the covariance matrix for the current data set in the popup
1466// AND whatever was the last fit for that data set. it may not necessarily
1467// be the displayed function...
1468Function DisplayCovarianceMatrix()
1469
1470       
1471
1472        ControlInfo/W=wrapperpanel popup_0
1473        String folderStr=S_Value
1474
1475        ControlInfo/W=WrapperPanel popup_1
1476        String funcStr=S_Value
1477                       
1478        if(Stringmatch(funcStr,"Smear*"))               //simple test for smeared function
1479                if(DataFolderExists("root:"+folderStr))
1480                        SetDataFolder $("root:"+folderStr)
1481                else
1482                        SetDataFolder root:
1483                endif
1484        else
1485                SetDataFolder root:
1486        endif
1487       
1488        Wave M_Covar=M_Covar
1489        Duplicate/O M_Covar, CorMat      // You can use any name instead of CorMat
1490        CorMat = M_Covar[p][q]/sqrt(M_Covar[p][p]*M_Covar[q][q])
1491
1492        // clear the table (a subwindow)
1493        DoWindow/F CorMatPanel                          // ?? had to add this in during all of the cursor meddling...
1494        KillWindow CorMatPanel#T0
1495        Edit/W=(20,74,634,335)/HOST=CorMatPanel
1496        RenameWindow #,T0
1497        // get them onto the table
1498        // how do I get the parameter name?
1499        String param = getFunctionParams(funcStr)
1500        AppendtoTable/W=CorMatPanel#T0 $param
1501        AppendToTable/W=CorMatPanel#T0 CorMat
1502        ModifyTable/W=CorMatPanel#T0 width(Point)=0
1503
1504        GroupBox grpBox_1 title="Data set: "+folderStr
1505        GroupBox grpBox_2 title="Function: "+funcStr
1506
1507
1508        SetDataFolder root:
1509       
1510        return(0)
1511End
1512
1513
1514Window CorMatPanel()
1515        PauseUpdate; Silent 1           // building window...
1516        NewPanel /W=(459,44,1113,399)/N=CorMatPanel/K=1 as "Correlation Matrix"
1517        ModifyPanel fixedSize=1
1518       
1519        GroupBox grpBox_1 title="box 1",pos={10,20},size={0,0},frame=1,fSize=10,fstyle=1,fColor=(39321,1,1)
1520        GroupBox grpBox_2 title="box 2",pos={10,40},size={0,0},frame=1,fSize=10,fstyle=1,fColor=(39321,1,1)
1521
1522        Button button_1,pos={520,30},size={100,20},proc=CorMatHelpButtonProc,title="Help"
1523
1524        Edit/W=(20,74,634,335)/HOST=# 
1525        ModifyTable width(Point)=0
1526        RenameWindow #,T0
1527        SetActiveSubwindow ##
1528EndMacro
1529
1530
1531Proc DisplayCovariance()
1532        DoWindow/F CorMatPanel
1533        if(V_Flag==0)
1534                CorMatPanel()
1535        endif
1536       
1537        DisplayCovarianceMatrix()
1538
1539End
1540
1541//open the Help file for the Fit Manager
1542Function CorMatHelpButtonProc(ba) : ButtonControl
1543        STRUCT WMButtonAction &ba
1544
1545        switch( ba.eventCode )
1546                case 2: // mouse up
1547                        // click code here
1548                        DisplayHelpTopic/Z/K=1 "Covariance Matrix"
1549                        if(V_flag !=0)
1550                                DoAlert 0,"Help for the correlation matrix could not be found"
1551                        endif
1552                        break
1553        endswitch
1554
1555        return 0
1556End
1557
1558
1559//////////////////////////////////
1560// this is a snippet from Andy Nelson, posted at the Igor Exchange web site.
1561//
1562// search area appears to be a percent (so enter 10 to get +/- 10% variation in the parameter)
1563//
1564// TODO:
1565//              x- rename the function for just me
1566//              x- make the edata a mandatory parameter
1567//              x- remove rhs, lhs? or keep these if cursors were used to properly trim the data set
1568//              x- label the graph
1569//              x- make a panel to control this - to either pick a single parameter, or show all of them
1570//              x- have it re-use the same graph, not draw a (new) duplicate one
1571//              x- update it to use the AAO as the input function (new func template -- see Gauss Utils)
1572//              x- the wrapper must be data folder aware, and data set aware like in the Wrapper panel
1573//              x- need a different wrapper for smeared and unsmeared functions
1574//
1575//
1576
1577
1578
1579Proc MapChiSquared(paramNum,percent)
1580        Variable paramNum=0,percent=10
1581        Prompt paramNum, "Enter parameter number: "
1582        Prompt percent, "Enter percent variation +/- : "
1583
1584        fChiMap(paramNum,percent)
1585End
1586
1587
1588// this does the math for a single value of "whichParam"
1589Function chi2gen(funcStr,folderStr,xw,yw,sw,cw,whichParam,searchArea,lhs,rhs,useResol)
1590        String funcStr,folderStr
1591        Wave xw,yw,sw,cw      //        x data, y data, error wave, and coefficient wave
1592        variable whichParam, searchArea  //which of the parameters to you want to vary, how far from the original value do you want to search (%)
1593        variable lhs, rhs    //specify a region of interest in the data using a left hand side and right hand side.
1594        variable useResol               // =1 if smeared used
1595 
1596        variable originalvalue = cw[whichparam]
1597        variable range = originalValue * searchArea/100
1598        variable ii,err
1599 
1600        duplicate/o yw, :theoretical_data, :chi2_data
1601        Wave theoretical_data, chi2_data
1602 
1603        make/o/n=200/d chi2_map
1604        setscale/I x,  originalvalue - range/2, originalvalue + range/2, chi2_map
1605 
1606        String DF="root:"+folderStr+":"
1607        String suffix=getModelSuffix(funcStr)
1608
1609        // fill a struct instance whether it is needed or not
1610        Struct ResSmearAAOStruct fs
1611        WAVE/Z resW = $(DF+folderStr+"_res")                    //these may not exist, if 3-column data is used
1612        WAVE/Z fs.resW =  resW
1613//              WAVE yw=$(DF+folderStr+"_i")
1614//              WAVE xw=$(DF+folderStr+"_q")
1615//              WAVE sw=$(DF+folderStr+"_s")
1616        Wave fs.coefW = cw
1617        Wave fs.yW = theoretical_data
1618        Wave fs.xW = xw
1619 
1620 
1621 
1622        for(ii=0 ; ii < numpnts(chi2_map) ; ii+=1)
1623                cw[whichparam] = pnt2x(chi2_map, ii)
1624 
1625                if(useResol)
1626                        FUNCREF SANSModelSTRUCT_proto func1=$funcStr
1627                        err = func1(fs)
1628                else
1629                        FUNCREF SANSModelAAO_proto func2=$funcStr
1630                        func2(cw,theoretical_data,xw)
1631                endif
1632               
1633                chi2_data = (yw-theoretical_data)^2
1634 
1635                chi2_data /= sw^2
1636
1637                Wavestats/q/R=[lhs, rhs] chi2_data
1638 
1639                chi2_map[ii] = V_avg * V_npnts
1640        endfor
1641 
1642        cw[whichparam] = originalvalue
1643 
1644        DoWindow/F Chi2
1645        if(V_flag==0)
1646                display/K=1/N=Chi2 chi2_map
1647                Label left "Chi^2"
1648        endif
1649
1650        String parStr=GetWavesDataFolder(cw,1)+ WaveList("*param*"+"_"+suffix, "", "TEXT:1," )          // this is *hopefully* one wave
1651        Wave/T parW = $parStr
1652        Label bottom parW[whichParam]
1653       
1654       
1655        killwaves/z theoretical_data, chi2_data
1656End
1657 
1658
1659// this does the setup
1660Function fChiMap(paramNum,percent)
1661        Variable paramNum,percent
1662
1663        String folderStr,funcStr,coefStr
1664        Variable useCursors,useResol=0,pt1,pt2
1665       
1666        ControlInfo/W=WrapperPanel popup_0
1667        folderStr=S_Value
1668       
1669        ControlInfo/W=WrapperPanel popup_1
1670        funcStr=S_Value
1671       
1672        ControlInfo/W=WrapperPanel popup_2
1673        coefStr=S_Value
1674       
1675        ControlInfo/W=WrapperPanel check_0
1676        useCursors=V_Value
1677       
1678       
1679// first, figure out where we are...
1680        String suffix=getModelSuffix(funcStr)
1681       
1682        SetDataFolder $("root:"+folderStr)
1683        if(!exists(coefStr))
1684                // must be unsmeared model, work in the root folder
1685                SetDataFolder root:                             
1686                if(!exists(coefStr))            //this should be fine if the coef filter is working, but check anyhow
1687                        DoAlert 0,"the coefficient and data sets do not match"
1688                        return 0
1689                endif
1690        endif
1691               
1692        WAVE cw=$(coefStr)
1693
1694
1695// test for smeared function
1696        if(stringmatch(funcStr, "Smear*"))              // if it's a smeared function, need a struct
1697                useResol=1
1698        endif
1699       
1700        // fill a struct instance whether I need one or not
1701        String DF="root:"+folderStr+":"
1702       
1703//      Struct ResSmearAAOStruct fs
1704//      WAVE/Z resW = $(DF+folderStr+"_res")                    //these may not exist, if 3-column data is used
1705//      WAVE/Z fs.resW =  resW
1706        WAVE yw=$(DF+folderStr+"_i")
1707        WAVE xw=$(DF+folderStr+"_q")
1708        WAVE sw=$(DF+folderStr+"_s")
1709//      Wave fs.coefW = cw
1710//      Wave fs.yW = yw
1711//      Wave fs.xW = xw
1712       
1713        if(useCursors)
1714                if(pcsr(A) > pcsr(B))
1715                        pt1 = pcsr(B)
1716                        pt2 = pcsr(A)
1717                else
1718                        pt1 = pcsr(A)
1719                        pt2 = pcsr(B)
1720                endif
1721        else
1722                //if cursors are not being used, find the first and last points of the data set, and pass them
1723                pt1 = 0
1724                pt2 = numpnts(yw)-1
1725        endif
1726       
1727               
1728       
1729        chi2gen(funcStr,folderStr,xw,yw,sw,cw,paramNum,percent,pt1,pt2,useResol)
1730       
1731
1732End
1733
1734////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.