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

Last change on this file since 941 was 941, checked in by srkline, 9 years ago

Moved rescaling panel from Wrapper.ipf to PlotUtils?.ipf, a more natural location.

Added "Manual Optimization" utility to the SANS Models/1D operations menu. this is a simple panel that allows users to "optimize" the fit in 1 or 2 directions. Very instructive to see whether you're near a minimum, and what the chi2 surface looks like around the minimum.

Did a similar Manual Optimization for the Real-space MultiClyinder? calculations from Ken Rubinson. simpler interface here.

All of the "CGB" fixes are present here, including the calculation of the number of guides.

File size: 61.4 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=4.10
3#pragma IgorVersion=6.1
4
5
6// this is the flag for the relative error = W_sigma/coef that will
7// trip the bold/red color of W_sigma in the table.
8//
9Constant kRelErrorTolerance=0.5
10
11//Macro OpenWrapperPanel()
12//      Init_WrapperPanel()
13//End
14
15Function Init_WrapperPanel()
16
17        if(itemsinlist(WinList("SA_includes_v400.ipf", ";","INCLUDE:6"),";") != 0)
18                //must be opening a v4.00 or earlier template
19                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"
20        endif
21       
22        //make sure that folders exist - this is the first initialization to be called
23        NewDataFolder/O root:Packages
24        NewDataFolder/O root:Packages:NIST
25
26        //Create useful globals
27        Variable/G root:Packages:NIST:SANS_ANA_VERSION=4.10
28        String/G root:Packages:NIST:SANS_ANA_EXTENSION="_v40"
29        //Set this variable to 1 to force use of trapezoidal integration routine for USANS smearing
30        Variable/G root:Packages:NIST:USANSUseTrap = 0
31        Variable/G root:Packages:NIST:USANS_dQv = 0.117
32        Variable/G root:Packages:NIST:gUseGenCurveFit = 0                       //set to 1 to use genetic optimization
33                       
34        //Ugly. Put this here to make sure things don't break
35        String/G root:Packages:NIST:gXMLLoader_Title
36       
37       
38        //initializes preferences. this includes XML y/n, and SANS Reduction items.
39        // if they already exist, they won't be overwritten
40        Execute "Initialize_Preferences()"             
41       
42        DoWindow/F WrapperPanel
43        if(V_flag==0)
44                if(exists("root:Packages:NIST:coefKWStr")==0)
45                        String/G root:Packages:NIST:coefKWStr=""
46                endif
47                if(exists("root:Packages:NIST:suffixKWStr")==0)
48                        String/G root:Packages:NIST:suffixKWStr=""
49                endif
50                if(exists("root:Packages:NIST:paramKWStr")==0)
51                        String/G root:Packages:NIST:paramKWStr=""
52                endif
53                Execute "WrapperPanel()"
54        endif
55End
56
57////////
58//
59// if model is Smeared, search the DF for coefficients
60// if new DF chosen, need to reset
61// if new model function, need to reset table
62//
63// create hold_mod (0/1), constr_low_mod, constr_hi_mod
64// in either DF (smeared) or in root: (normal)
65// and put these in the table as needed
66//
67Window WrapperPanel()
68        PauseUpdate; Silent 1           // building window...
69        NewPanel /W=(459,44,1113,499)/N=wrapperPanel/K=1 as "Curve Fit Setup"
70        ModifyPanel fixedSize=1
71       
72        GroupBox grpBox_0,pos={18,11},size={390,113}
73        GroupBox grpBox_1,pos={426,10},size={207,113}
74        GroupBox grpBox_2 title="No Fit",pos={10,130},size={0,0},frame=1,fSize=10,fstyle=1,fColor=(39321,1,1)
75        GroupBox grpBox_3 title="",pos={10,150},size={0,0},frame=1,fSize=10,fstyle=1,fColor=(39321,1,1)
76
77        Button button_1,pos={280,57},size={120,20},proc=PlotModelFunction,title="Plot 1D Function"
78        Button button_2,pos={300,93},size={100,20},proc=AppendModelToTarget,title="Append 1D"
79        Button button_3,pos={300,20},size={100,20},proc=W_LoadDataButtonProc,title="Load 1D Data"
80        PopupMenu popup_0,pos={30,21},size={218,20},title="Data Set",proc=DataSet_PopMenuProc
81        PopupMenu popup_0,mode=1,value= #"W_DataSetPopupList()"
82        PopupMenu popup_1,pos={30,57},size={136,20},title="Function"
83        PopupMenu popup_1,mode=1,value= #"W_FunctionPopupList()",proc=Function_PopMenuProc
84        PopupMenu popup_2,pos={30,93},size={123,20},title="Coefficients"
85        PopupMenu popup_2,mode=1,value= #"W_CoefPopupList()",proc=Coef_PopMenuProc
86        CheckBox check_0,pos={430,19},size={79,14},title="Use Cursors?",value= 0
87        CheckBox check_0,proc=UseCursorsWrapperProc
88        CheckBox check_1,pos={430,42},size={74,14},title="Use Epsilon?",value= 0
89        CheckBox check_2,pos={430,65},size={95,14},title="Use Constraints?",value= 0
90        CheckBox check_3,pos={530,18},size={72,14},title="2D Functions?",value= 0
91        CheckBox check_3 proc=Toggle2DControlsCheckProc
92        CheckBox check_4,pos={430,85},size={72,14},title="Report?",value= 0
93        CheckBox check_5,pos={444,103},size={72,14},title="Save it?",value= 0
94        CheckBox check_6,pos={530,38},size={72,14},title="Use Residuals?",value= 0
95        CheckBox check_6,proc=UseResidualsCheckProc
96        CheckBox check_7,pos={530,57},size={72,14},title="Info Box?",value= 0
97        CheckBox check_7,proc=UseInfoTextBoxCheckProc
98        CheckBox check_8, pos={530,75}, size={72,14}, title="Rescale Axis?", value=0
99        CheckBox check_8,proc=UseRescaleAxisCheckProc
100        //change draw order to put button over text of checkbox
101        Button button_0,pos={520,93},size={100,20},proc=DoTheFitButton,title="Do 1D Fit"
102        Button button_4,pos={520,126},size={100,20},proc=FeedbackButtonProc,title="Feedback"
103        Button button_5,pos={520,150},size={100,20},proc=FitHelpButtonProc,title="Help"
104
105        Edit/W=(20,174,634,435)/HOST=# 
106        ModifyTable width(Point)=0
107        RenameWindow #,T0
108        SetActiveSubwindow ##
109EndMacro
110
111//open the Help file for the Fit Manager
112Function FitHelpButtonProc(ba) : ButtonControl
113        STRUCT WMButtonAction &ba
114
115        switch( ba.eventCode )
116                case 2: // mouse up
117                        // click code here
118                        DisplayHelpTopic/Z/K=1 "Fit Manager"
119                        if(V_flag !=0)
120                                DoAlert 0,"The Fit Manager Help file could not be found"
121                        endif
122                        break
123        endswitch
124
125        return 0
126End
127
128
129//open the trac page for feedback
130Function FeedbackButtonProc(ba) : ButtonControl
131        STRUCT WMButtonAction &ba
132
133        switch( ba.eventCode )
134                case 2: // mouse up
135                        // click code here
136                        OpenTracTicketPage()
137                        break
138        endswitch
139
140        return 0
141End
142
143
144//obvious use, now finds the most recent data loaded, finds the folder, and pops the menu with that selection...
145//
146Function W_LoadDataButtonProc(ba) : ButtonControl
147        STRUCT WMButtonAction &ba
148
149        switch( ba.eventCode )
150                case 2: // mouse up
151                        // click code here
152                        String  topGraph= WinName(0,1)
153                        if(strlen(topGraph) != 0)
154                                DoWindow/F $topGraph                    //so that the panel is not on top
155                        endif
156                        Execute "A_LoadOneDData()"
157                       
158                        ControlUpdate/W=WrapperPanel popup_0
159                        //instead of a simple controlUpdate, better to pop the menu to make sure that the other menus follow
160                        // convoluted method to find the right item and pop the menu.
161
162                        // data is plotted, so get the "new" top graph
163                        topGraph= WinName(0,1)  //this is the topmost graph, and should exist, but...
164                        if(cmpstr(topGraph,"")==0)
165                                return(0)
166                        endif
167                        String list,folderStr
168                        Variable num
169                        list = TraceNameList(topGraph,";",1)            //want the last item in the list
170                        num= ItemsInList(list)
171                        FolderStr = StringFromList(num-1,list,";")
172                        folderStr = folderStr[0,strlen(folderStr)-3]            //remove the "_i" that the loader enforced
173                        list = W_DataSetPopupList()
174                        num=WhichListItem(folderStr,list,";",0,0)
175                        if(num != -1)
176                                PopupMenu popup_0,mode=num+1,win=WrapperPanel
177                                ControlUpdate/W=WrapperPanel popup_0
178                               
179                                // fake mouse up to pop the menu
180                                Struct WMPopupAction ps
181                                ps.eventCode = 2                //fake mouse up
182                                DataSet_PopMenuProc(ps)
183                        endif
184                        break
185        endswitch
186       
187        return 0
188End
189
190
191// is there a simpler way to do this? I don't think so.
192Function/S W_DataSetPopupList()
193
194        String str=GetAList(4)
195
196        if(strlen(str)==0)
197                str = "No data loaded"
198        endif
199        str = SortList(str)
200       
201        return(str)
202End
203
204
205// show the available models
206// not the f*(cw,xw) point calculations
207// not the *X(cw,xw) XOPS
208//
209// KIND:10 should show only user-defined curve fitting functions
210// - not XOPs
211// - not other user-defined functions
212Function/S W_FunctionPopupList()
213        String list,tmp
214        //get every user defined curve fit function, remove everything the user doesn't need to see...
215        list = User_FunctionPopupList()         
216
217        if(strlen(list)==0)
218                list = "No functions plotted"
219        endif
220       
221        list = SortList(list)
222        return(list)
223End
224
225
226// show all the appropriate coefficient waves
227//
228// also need to search the folder listed in "data set" popup
229// for smeared coefs
230//
231// - or - restrict the coefficient list based on the model function
232// - new way, filter the possible values based on the data folder and function
233Function/S W_CoefPopupList()
234
235        String notPlotted="Please plot the function"
236        ControlInfo/W=wrapperpanel popup_1
237        String funcStr=S_Value
238        String coefStr=getFunctionCoef(funcStr)
239       
240        if(cmpstr(coefStr,"")==0)               //no correspondence in the KW string
241                return(notPlotted)
242        endif
243       
244       
245        //found a coefficient wave - only two places to look
246        // is it in the root folder?
247        if(exists("root:"+coefStr) != 0)
248                return(coefStr)
249        endif
250       
251        // is it in the data folder?
252        ControlInfo/W=wrapperpanel popup_0
253        String folderStr=S_Value
254        if(exists("root:"+folderStr+":"+coefStr) != 0)
255                return(coefStr)
256        endif
257
258        return(notPlotted)
259End
260
261// show all the appropriate coefficient waves
262//
263// also need to search the folder listed in "data set" popup
264// for smeared coefs
265//
266// - or - restrict the coefficient list based on the model function
267//
268// --old way
269//Function/S W_CoefPopupList()
270//      String list
271//      setDataFolder root:
272//      list = WaveList("coef*",";","")
273//     
274//      ControlInfo/W=wrapperpanel popup_0
275//      if(V_Value != 0)                //0== no items in menu
276//              if(DataFolderExists("root:"+S_Value))
277//                      SetDataFolder $("root:"+S_Value)
278//                      list += WaveList("*coef*",";","")
279//              endif
280//      endif
281//     
282//      // tmp coefficients that aren't being cleaned up from somewhere...
283//      list = RemoveFromList("temp_coef_1;temp_coef_2;", list  ,";")
284//
285//      if(strlen(list)==0)
286//              list = "No functions plotted"
287//      endif
288//      list = SortList(list)
289//     
290////    Print itemsinlist(list,";")
291//     
292//      setDataFolder root:
293//      return(list)
294//End
295
296// if the coefficients are changed, then update the table
297//
298//update the table
299// may be easier to just kill the subwindow (table) and create a new one
300// need to set/reset all of the waves in the table
301//
302// !! only respond to mouse up
303//
304Function Coef_PopMenuProc(pa) : PopupMenuControl
305        STRUCT WMPopupAction &pa
306
307        switch( pa.eventCode )
308                case 2: // mouse up
309                        Variable popNum = pa.popNum
310                        String popStr = pa.popStr
311                        ControlInfo/W=WrapperPanel popup_1
312                        String funcStr=S_Value
313                        String suffix = getModelSuffix(funcStr)
314                        ControlInfo/W=WrapperPanel popup_0
315                        String folderStr=S_Value
316                       
317                        if(cmpstr(popStr,"Please plot the function")==0)
318//                              Print "function not plotted"
319                                return(0)
320                        endif
321
322// this if/else/endif should not ever return an error alert     
323// it should simply set the data folder properly       
324                        if(DataFolderExists("root:"+folderStr))
325                                SetDataFolder $("root:"+folderStr)
326                                if(!exists(popStr))
327                                        // must be unsmeared model, work in the root folder
328                                        SetDataFolder root:                             
329                                        if(!exists(popStr))             //this should be fine if the coef filter is working, but check anyhow
330                                                DoAlert 0,"the coefficient and data sets do not match (1)"
331                                                return 0
332                                        endif
333                                endif
334                        else
335                                // must be unsmeared model, work in the root folder
336                                SetDataFolder root:     
337                                if(!exists(popStr))             //this should be fine if the coef filter is working, but check anyhow
338                                        DoAlert 0,"the coefficient and data sets do not match (2)"
339                                        return 0
340                                endif
341                        endif
342                       
343                        // farm the work out to another function?
344                        Variable num=numpnts($popStr)
345                        // make the necessary waves if they don't exist already
346                        if(exists("Hold_"+suffix) == 0)
347                                Make/O/D/N=(num) $("epsilon_"+suffix),$("Hold_"+suffix)
348                                Make/O/T/N=(num) $("LoLim_"+suffix),$("HiLim_"+suffix)
349                                Wave eps = $("epsilon_"+suffix)
350                                Wave coef=$popStr
351                                if(eps[0] == 0)         //if eps already if filled, don't change it
352                                        eps = abs(coef*1e-4) + 1e-10                    //default eps is proportional to the coefficients
353                                endif
354                        endif
355                        // default epsilon values, sometimes needed for the fit
356                       
357                        WAVE/T LoLim = $("LoLim_"+suffix)
358                        WAVE/T HiLim = $("HiLim_"+suffix)
359                       
360                        // clear the table (a subwindow)
361                        DoWindow/F WrapperPanel                         // ?? had to add this in during all of the cursor meddling...
362                        KillWindow wrapperPanel#T0
363                        Edit/W=(20,174,634,435)/HOST=wrapperPanel
364                        RenameWindow #,T0
365                        // get them onto the table
366                        // how do I get the parameter name?
367                        String param = getFunctionParams(funcStr)
368                        AppendtoTable/W=wrapperPanel#T0 $param,$(popStr)
369                        AppendToTable/W=wrapperPanel#T0 $("Hold_"+suffix),$("LoLim_"+suffix),$("HiLim_"+suffix),$("epsilon_"+suffix)
370                        ModifyTable/W=wrapperPanel#T0 width(Point)=0
371                       
372                        SetDataFolder root:
373                        break
374        endswitch
375
376        return 0
377End
378
379// if the Function is changed, then update the coef popup (if possible) and then the table (if possible)
380//
381// !! only respond to mouse up
382//
383Function Function_PopMenuProc(pa) : PopupMenuControl
384        STRUCT WMPopupAction &pa
385
386        switch( pa.eventCode )
387                case 2: // mouse up
388                        Variable popNum = pa.popNum
389                        String funcStr = pa.popStr
390                        String coefStr = W_CoefPopupList()
391                       
392//                      Print "coefStr = ",coefStr
393                       
394                        ControlInfo/W=WrapperPanel popup_0
395                        String folderStr=S_Value
396                       
397                        String listStr = W_CoefPopupList()
398                        Variable num=WhichListItem(coefStr, listStr, ";")
399                        String str=StringFromList(num, listStr  ,";")
400//                      print "str = ",str
401                        //set the item in the coef popup, and pop it
402                        PopupMenu popup_2 win=WrapperPanel,mode=(num+1)
403                       
404                        Struct WMPopupAction ps
405                        ps.eventCode = 2                //fake mouse up
406                        ps.popStr = str
407                        Coef_PopMenuProc(ps)
408                       
409                        SetDataFolder root:
410                        break
411        endswitch
412
413        return 0
414End
415
416// if the Data Set is changed, then update the function (if possible)
417// and the coef popup (if possible) and then the table (if possible)
418//
419// !! only respond to mouse up here, and simply send a fake mouse up
420// to the function pop, which will do what it can do
421//
422Function DataSet_PopMenuProc(pa) : PopupMenuControl
423        STRUCT WMPopupAction &pa
424       
425        switch( pa.eventCode )
426                case 2: // mouse up
427                        // make sure that the cursors are on/off appropriately
428                        // let the cursors checkbox decide what to do, sending the current state
429                        ControlInfo/W=WrapperPanel check_0
430                        STRUCT WMCheckboxAction cba
431                        cba.eventCode = 2
432                        cba.checked = V_Value
433                        UseCursorsWrapperProc(cba)
434                                       
435                        // then cascade the function/coefficient popups
436                        Struct WMPopupAction ps
437                        ps.eventCode = 2                //fake mouse up
438                        Function_PopMenuProc(ps)
439                       
440                        SetDataFolder root:
441                        break
442        endswitch
443
444        return 0
445End
446
447
448// - this is based on stringent "PlotNNN" naming requirements
449//
450//  ???
451// - how to kill the generated table and graph, that are not needed now
452//
453Function PlotModelFunction(ba) : ButtonControl
454        STRUCT WMButtonAction &ba
455
456        String folderStr,funcStr,coefStr,cmdStr=""
457        Variable useCursors,useEps,useConstr
458       
459        Variable killWhat=0             //kill nothing as default
460       
461        switch( ba.eventCode )
462                case 2: // mouse up
463                        ControlInfo/W=WrapperPanel popup_0
464                        folderStr=S_Value
465                       
466                        ControlInfo/W=WrapperPanel popup_1
467                        funcStr=S_Value
468                       
469                        // maybe nothing has been loaded yet...
470                        if(cmpstr(funcStr,"No functions plotted") == 0)
471                                break
472                        endif
473                       
474                        // check for smeared or smeared function
475                        if(stringmatch(funcStr, "Smear*" )==1)
476                                //it's a smeared model
477                                // check for the special case of RPA that has an extra parameter
478                                if(strsearch(funcStr, "RPAForm", 0 ,0) == -1)
479                                        sprintf cmdStr, "Plot%s(\"%s\")",funcStr,folderStr              //not RPA
480                                else
481                                        sprintf cmdStr, "Plot%s(\"%s\",)",funcStr,folderStr             //yes RPA, leave a comma for input
482                                endif
483                                killWhat = 1
484                        else
485                                // it's not,    don't kill the graph, just the table           
486                                sprintf cmdStr, "Plot%s()",funcStr
487                                killWhat = 2
488                        endif
489                       
490                        //Print cmdStr
491                        Execute cmdStr
492                       
493                        //pop the function menu to set the proper coefficients
494                        DoWindow/F WrapperPanel
495                        STRUCT WMPopupAction pa
496                        pa.popStr = funcStr
497                        pa.eventcode = 2
498                        Function_PopMenuProc(pa)
499       
500                        KillTopGraphAndTable(killWhat)          // crude
501       
502                        break
503        endswitch
504       
505        return 0
506End
507
508// passing 0 kills nothing
509// passing 1 kills the top graph and table
510// passing 2 kills the top table only
511//
512Function KillTopGraphAndTable(killwhat)
513        Variable killWhat
514       
515        String topGraph= WinName(0,1)   //this is the topmost graph     
516        String topTable= WinName(0,2)   //this is the topmost table
517
518        if(killWhat == 0)
519                return(0)
520        endif
521       
522        if(killWhat == 1)
523                KillWindow $topGraph
524                KillWindow $topTable
525        endif
526       
527        if(killWhat == 2)
528                KillWindow $topTable
529        endif
530       
531        return(0)
532End
533
534// How to bypass the step of plot and append?
535//
536// do it in two separate events
537//
538Function AppendModelToTarget(ba) : ButtonControl
539        STRUCT WMButtonAction &ba
540
541        String coefStr,suffix,yWStr,xWStr,folderStr,funcStr
542       
543        switch( ba.eventCode )
544                case 2: // mouse up                     
545                        ControlInfo/W=WrapperPanel popup_2
546                        coefStr=S_Value
547                       
548                        ControlInfo/W=WrapperPanel popup_1
549                        funcStr=S_Value
550                        suffix = getModelSuffix(funcStr)
551                       
552                        // check for smeared or smeared function
553                        if(stringmatch(coefStr, "smear*" )==1)
554                                //it's a smeared model
555                                ControlInfo/W=WrapperPanel popup_0
556                                folderStr=S_Value
557                                xWStr = "root:"+folderStr+":smeared_qvals"
558                                ywStr = "root:"+folderStr+":smeared_"+suffix
559                        else
560                                // it's not, so it's in the root folder
561                                xWStr = "xwave_"+suffix
562                                yWStr = "ywave_"+suffix
563                        endif
564                       
565                        Wave/Z yw = $yWStr
566                        Wave/Z xw = $xWStr
567                        if(WaveExists(yw) && WaveExists(xw))
568                                AppendtoGraph yw vs xw
569                        else
570                                DoAlert 0,"The selected model has not been plotted for the selected data set."
571                        endif
572                        break
573        endswitch
574       
575        return 0
576End
577
578
579// this should parse the panel and call the FitWrapper() function
580Function DoTheFitButton(ba) : ButtonControl
581        STRUCT WMButtonAction &ba
582
583        String folderStr,funcStr,coefStr
584        Variable useCursors,useEps,useConstr,useResiduals,useTextBox, useRescaleAxis
585       
586        switch( ba.eventCode )
587                case 2: // mouse up
588                        ControlInfo/W=WrapperPanel popup_0
589                        folderStr=S_Value
590                       
591                        ControlInfo/W=WrapperPanel popup_1
592                        funcStr=S_Value
593                       
594                        ControlInfo/W=WrapperPanel popup_2
595                        coefStr=S_Value
596                       
597                        ControlInfo/W=WrapperPanel check_0
598                        useCursors=V_Value
599                        ControlInfo/W=WrapperPanel check_1
600                        useEps=V_Value
601                        ControlInfo/W=WrapperPanel check_2
602                        useConstr=V_Value
603                       
604                        ControlInfo/W=WrapperPanel check_6
605                        useResiduals=V_Value
606                       
607                        ControlInfo/W=WrapperPanel check_7
608                        useTextBox = V_Value
609                       
610                        ControlInfo/W=WrapperPanel check_8
611                        useRescaleAxis = V_Value
612                       
613                        if(!CheckFunctionAndCoef(funcStr,coefStr))
614                                DoAlert 0,"The coefficients and function type do not match. Please correct the selections in the popup menus."
615                                break
616                        endif
617                       
618                        FitWrapper(folderStr,funcStr,coefStr,useCursors,useEps,useConstr,useResiduals,useTextBox,useRescaleAxis)
619                       
620                        //      DoUpdate (does not work!)
621                        //?? why do I need to force an update ??
622                        if(!exists("root:"+folderStr+":"+coefStr))
623                                Wave w=$coefStr
624                        else
625                                Wave w=$("root:"+folderStr+":"+coefStr) //smeared coefs in data folder
626                        endif
627                        w[0] += 1e-6
628                        w[0] -= 1e-6
629       
630                        break
631        endswitch
632       
633        return 0
634End
635
636Function CheckFunctionAndCoef(funcStr,coefStr)
637        String funcStr,coefStr
638       
639        SVAR listStr=root:Packages:NIST:coefKWStr
640        String properCoefStr = StringByKey(funcStr, listStr  ,"=",";",0)
641        if(cmpstr("",properCoefStr)==0)
642                return(0)               //false, no match found, so properCoefStr is returned null
643        endif
644        if(cmpstr(coefStr,properCoefStr)==0)
645                return(1)               //true, the coef is the correct match
646        endif
647        return(0)                       //false, wrong coef
648End
649
650/////////////////////////////////
651
652// wrapper to do the desired fit
653//
654// folderStr is the data folder for the desired data set
655//
656//
657Function FitWrapper(folderStr,funcStr,coefStr,useCursors,useEps,useConstr,useResiduals,useTextBox,useRescaleAxis)
658        String folderStr,funcStr,coefStr
659        Variable useCursors,useEps,useConstr,useResiduals,useTextBox,useRescaleAxis
660
661        String suffix=getModelSuffix(funcStr)
662       
663        SetDataFolder $("root:"+folderStr)
664        if(!exists(coefStr))
665                // must be unsmeared model, work in the root folder
666                SetDataFolder root:                             
667                if(!exists(coefStr))            //this should be fine if the coef filter is working, but check anyhow
668                        DoAlert 0,"the coefficient and data sets do not match"
669                        return 0
670                endif
671        endif
672               
673        WAVE cw=$(coefStr)     
674        Wave hold=$("Hold_"+suffix)
675        Wave/T lolim=$("LoLim_"+suffix)
676        Wave/T hilim=$("HiLim_"+suffix)
677       
678        if(useEps)
679                Wave eps=$("epsilon_"+suffix)
680        endif
681// fill a struct instance whether I need one or not
682        String DF="root:"+folderStr+":"
683       
684        Struct ResSmearAAOStruct fs
685        WAVE/Z resW = $(DF+folderStr+"_res")                    //these may not exist, if 3-column data is used
686        WAVE/Z fs.resW =  resW
687        WAVE yw=$(DF+folderStr+"_i")
688        WAVE xw=$(DF+folderStr+"_q")
689        WAVE sw=$(DF+folderStr+"_s")
690        Wave fs.coefW = cw
691        Wave fs.yW = yw
692        Wave fs.xW = xw
693       
694        Duplicate/O yw $(DF+"FitYw")
695        WAVE fitYw = $(DF+"FitYw")
696        fitYw = NaN
697       
698        Variable useResol=0,isUSANS=0,val
699        if(stringmatch(funcStr, "Smear*"))              // if it's a smeared function, need a struct
700                useResol=1
701        endif
702        if(dimsize(resW,1) > 4)
703                isUSANS=1
704        endif
705       
706        // do not construct constraints for any of the coefficients that are being held
707        // -- this will generate an "unknown error" from the curve fitting
708        // -- if constraints are not used, the constr wave is killed. This apparently
709        // confuses the /NWOK flag, since there is not even a null reference present. So generate one.
710        if(useConstr)
711                Make/O/T/N=0 constr
712                String constraintExpression
713                Variable i, nPnts=DimSize(lolim, 0),nextRow=0
714                for (i=0; i < nPnts; i += 1)
715                        if (strlen(lolim[i]) > 0 && hold[i] == 0)
716                                InsertPoints nextRow, 1, constr
717                                sprintf constraintExpression, "K%d > %s", i, lolim[i]
718                                constr[nextRow] = constraintExpression
719                                nextRow += 1
720                        endif
721                        if (strlen(hilim[i]) > 0 && hold[i] == 0)
722                                InsertPoints nextRow, 1, constr
723                                sprintf constraintExpression, "K%d < %s", i, hilim[i]
724                                constr[nextRow] = constraintExpression
725                                nextRow += 1
726                        endif
727                endfor
728        else
729                Wave/T/Z constr = constr
730                KillWaves/Z constr
731                Wave/T/Z constr = constr                //this is intentionally a null reference
732        endif
733
734        // 20JUN if useCursors is true, and there are no cursors on the specified data set, uncheck and set to false
735        // this is a last line of defense, and should never actually do anything...
736        if(useCursors)
737                useCursors = AreCursorsCorrect(folderStr)
738        endif
739        //if useCursors, and the data is USANS, need to recalculate the matrix if the range is new
740        Variable pt1,pt2,newN,mPt1,mPt2
741        String noteStr
742        if(useCursors && isUSANS )
743                //where are the cursors, and what is the status of the current matrix?
744                if(pcsr(A) > pcsr(B))
745                        pt1 = pcsr(B)
746                        pt2 = pcsr(A)
747                else
748                        pt1 = pcsr(A)
749                        pt2 = pcsr(B)
750                endif
751               
752                noteStr = note(resW)
753                mPt1 = NumberByKey("P1",noteStr,"=",";")
754                mPt2 = NumberByKey("P2",noteStr,"=",";")
755                if((mPt1 != pt1) || (mPt2 != pt2) )
756                        // need to recalculate
757                        USANS_RE_CalcWeights(folderStr,pt1,pt2)
758                        Print "Done recalculating the matrix"
759                endif
760               
761                Wave trimResW=$(DF+folderStr+"_res"+"t")        //put the trimmed resW in the struct for the fit!
762                Wave fs.resW=trimResW
763        endif
764        if(useCursors)
765                //find the points so that genetic optimization can use them
766                if(pcsr(A) > pcsr(B))
767                        pt1 = pcsr(B)
768                        pt2 = pcsr(A)
769                else
770                        pt1 = pcsr(A)
771                        pt2 = pcsr(B)
772                endif
773        else
774                //if cursors are not being used, find the first and last points of the data set, and pass them
775                pt1 = 0
776                pt2 = numpnts(yw)-1
777        endif
778               
779// create these variables so that FuncFit will set them on exit
780        Variable/G V_FitError=0                         //0=no err, 1=error,(2^1+2^0)=3=singular matrix
781        Variable/G V_FitQuitReason=0            //0=ok,1=maxiter,2=user stop,3=no chisq decrease
782
783        NVAR useGenCurveFit = root:Packages:NIST:gUseGenCurveFit
784// don't use the auto-destination with no flag, it doesn't appear to work correctly
785// dispatch the fit
786
787// currently, none of the fit functions are defined as threadsafe, so I don't think that the /NTHR flag really
788// does anything. The functions themselves can be threaded since they are AAO, and that is probably enough,
789// since it doesn't make much sense to thread threads. In addition, there is a little-publicized warning
790// in the WM help file that /C=texWave cannot be used to specify constraints for threadsafe functions!
791// The textwave would have to be parsed into a constraint matrix first, then passed as /C={cMat,cVec}.
792// -- just something to watch out for.
793
794// now two more flags... ,useResiduals,useTextBox
795        Variable tb = 1+2+4+8+16+256+512                //See CurveFit docs for bit settings for /TBOX flag
796
797        do
798                Variable t0 = stopMStimer(-2)           // corresponding print is at the end of the do-while loop (outside)
799
800
801                if(useGenCurveFit)
802               
803#if !(exists("GenCurveFit"))
804                        // XOP not available
805                        useGenCurveFit = 0
806                        Abort "Genetic Optimiztion XOP not available. Reverting to normal optimization."       
807#endif
808                        //send everything to a function, to reduce the clutter
809                        // useEps and useConstr are not needed
810                        // pass the structure to get the current waves, including the trimmed USANS matrix
811                        //
812                        // I don't know that GetCurveFit can do residuals, so I'm not passing that flag, or the text box flag
813                        //
814                        Variable chi,pt
815
816                        chi = DoGenCurveFit(useResol,useCursors,sw,fitYw,fs,funcStr,getHStr(hold),val,lolim,hilim,pt1,pt2)
817                        pt = val
818
819                        break
820                       
821                endif
822               
823                // now useCursors, useEps, and useConstr are all handled w/ /NWOK
824                // so there are only three conditions to test == 1 + 3 + 3 + 1 = 8 conditions
825               
826                if(useResol && useResiduals && useTextBox)              //do it all
827                        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
828                        break
829                endif
830               
831                if(useResol && useResiduals)            //res + resid
832                        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
833                        break
834                endif
835
836               
837                if(useResol && useTextBox)              //res + text
838                        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
839                        break
840                endif
841               
842                if(useResol)            //res only
843//                      Print "timing test for Cylinder_PolyRadius---"
844//                      Variable t0 = stopMStimer(-2)
845
846                        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
847                       
848//                      t0 = (stopMSTimer(-2) - t0)*1e-6
849//                      Printf  "CylPolyRad fit time using res and eps and /NTHR=0 time = %g seconds\r\r",t0
850//                      cw[0] = .01
851//                      cw[1] = 20
852//                      cw[2] = 400
853//                      cw[3] = 0.2
854//                      cw[4] = 3e-6
855//                      cw[5] = 0.0
856//                     
857//                      t0 = stopMSTimer(-2)
858//                      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
859//                      t0 = (stopMSTimer(-2) - t0)*1e-6
860//                      Printf  "CylPolyRad fit time using res and eps and NO THREADING time = %g seconds\r\r",t0
861                        break
862                endif
863                       
864               
865               
866/////   same as above, but all without useResol (no /STRC flag)
867                if(useResiduals && useTextBox)          //resid+ text
868                        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
869                        break
870                endif
871               
872                if(useResiduals)                //resid
873                        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
874                        break
875                endif
876
877               
878                if(useTextBox)          //text
879                        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
880                        break
881                endif
882               
883                //just a plain vanilla fit
884
885                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
886               
887        while(0)
888       
889        t0 = (stopMSTimer(-2) - t0)*1e-6
890        Printf  "fit time = %g seconds\r\r",t0
891       
892       
893        // append the fit
894        // need to manage duplicate copies
895        // Don't plot the full curve if cursors were used (set fitYw to NaN on entry...)
896        String traces=TraceNameList("", ";", 1 )                //"" as first parameter == look on the target graph
897        if(strsearch(traces,"FitYw",0) == -1 )
898                if(useGenCurveFit && useCursors)
899                        WAVE trimX = trimX
900                        AppendtoGraph fitYw vs trimX
901                else
902                        AppendToGraph FitYw vs xw
903                endif
904        elseif (strsearch(traces,"FitYw_RA",0) == -1)
905                RemoveFromGraph FitYw
906                if(useGenCurveFit && useCursors)
907                        WAVE trimX = trimX
908                        AppendtoGraph fitYw vs trimX
909                else
910                        AppendToGraph FitYw vs xw
911                endif
912        else
913                RemoveFromGraph FitYw_RA
914                if(useGenCurveFit && useCursors)
915                        WAVE trimX = trimX
916                        AppendtoGraph fitYw vs trimX
917                else
918                        AppendToGraph FitYw vs xw
919                endif
920        endif
921        ModifyGraph lsize(FitYw)=2,rgb(FitYw)=(0,0,0)
922       
923        DoUpdate                //force update of table and graph with fitted values (why doesn't this work? - the table still does not update)
924       
925        // report the results (to the panel?)
926        if(useGenCurveFit)
927                V_chisq = chi
928                V_npnts = pt
929        endif
930        print "V_chisq = ",V_chisq
931        print cw
932        WAVE/Z w_sigma
933        print w_sigma
934        String resultStr=""
935        Variable maxRelError=0
936       
937        if(waveexists(W_sigma))
938                //append it to the table, if it's not already there
939                CheckDisplayed/W=WrapperPanel#T0 W_sigma
940                if(V_flag==0)
941                        //not there, append it
942                        AppendtoTable/W=wrapperPanel#T0 W_sigma
943                else
944                        //remove it, and put it back on to make sure it's the right one (do I need to do this?)
945                        // -- not really, since any switch of the function menu takes W_Sigma off
946                endif
947                // then do I want to color it if the errors are horrible?
948                Duplicate/O cw, relError
949                relError = W_sigma/cw
950                maxRelError = WaveMax(relError)
951                if(maxRelError > kRelErrorTolerance)
952                        ModifyTable/W=wrapperPanel#T0 style(W_sigma)=1,rgb(W_sigma)=(65535,0,0)
953                else
954                        ModifyTable/W=wrapperPanel#T0 style=0,rgb=(0,0,0)
955        endif
956       
957        endif
958       
959        //now re-write the results
960        sprintf resultStr,"Chi^2 = %g  Sqrt(X^2/N) = %g",V_chisq,sqrt(V_chisq/V_Npnts)
961        resultStr = PadString(resultStr,63,0x20)
962        DoWIndow/F WrapperPanel
963        GroupBox grpBox_2 title=resultStr
964        ControlUpdate/W=WrapperPanel grpBox_2
965        sprintf resultStr,"FitErr = %s : FitQuit = %s",W_ErrorMessage(V_FitError),W_QuitMessage(V_FitQuitReason)
966        resultStr = PadString(resultStr,63,0x20)
967        GroupBox grpBox_3 title=resultStr
968        ControlUpdate/W=WrapperPanel grpBox_3
969       
970        Variable yesSave=0,yesReport=0
971        ControlInfo/W=WrapperPanel check_4
972        yesReport = V_Value
973        ControlInfo/W=WrapperPanel check_5
974        yesSave = V_Value
975       
976       
977        if(yesReport)
978                String parStr=GetWavesDataFolder(cw,1)+ WaveList("*param*"+"_"+suffix, "", "TEXT:1," )          // this is *hopefully* one wave
979                String topGraph= WinName(0,1)   //this is the topmost graph
980       
981                DoUpdate                //force an update of the graph before making a copy of it for the report
982
983                //if GenCurveFit used, V_startRow and V_endRow may not exist - so read the cursors? but the cursors may not be used, so
984                // there won't be anything on the graph... but pt1 and pt2 are set and passed!. The V_ variables are more foolproof
985                // so keep these for the "normal" report
986                //
987                if(useGenCurveFit)     
988                        W_GenerateReport(funcStr,folderStr,$parStr,cw,yesSave,V_chisq,W_sigma,V_npnts,V_FitError,V_FitQuitReason,pt1,pt2,topGraph)
989                else
990                        W_GenerateReport(funcStr,folderStr,$parStr,cw,yesSave,V_chisq,W_sigma,V_npnts,V_FitError,V_FitQuitReason,V_startRow,V_endRow,topGraph)
991                endif
992        endif
993       
994        //Rescale the Plot depending on the user choice
995        if(useRescaleAxis)
996                string ctrlName = "GoRescale"
997                RescalePlot(ctrlName)
998        elseif (DataFolderExists("root:Packages:NIST:RescaleAxis"))
999                SetDataFolder root:
1000                String PlotGraph= WinName(0,1)  //this is the topmost graph
1001                DoWindow/F $PlotGraph
1002               
1003                GetWindow/Z $PlotGraph, wavelist
1004                if (V_flag != 0)
1005                        DoPrompt/Help="" "I couldn't find the graph"
1006                        Abort
1007                endif
1008               
1009                wave/t W_Wavelist
1010               
1011                variable j
1012                string temp
1013                SetDataFolder root:Packages:NIST:RescaleAxis
1014                if (exists("W_WaveList")==1)
1015                        KillWaves/Z root:Packages:NIST:RescaleAxis:W_WaveList
1016                endif
1017                MoveWave root:W_WaveList, root:Packages:NIST:RescaleAxis:W_WaveList
1018               
1019                for(i=0; i < numpnts(W_Wavelist)/3; i+=1)
1020                        temp = W_WaveList[i][0]
1021                        if(stringmatch(temp, "*_RA"))
1022               
1023                                string WaveDataFolder, WaveToRescale
1024                                WaveDataFolder = ReplaceString(W_WaveList[i][0], W_WaveList[i][1], "")
1025                                if(strlen(WaveDataFolder)==0)
1026                                        WaveDataFolder = ":"
1027                                endif
1028                                WaveDataFolder = "root"+WaveDataFolder 
1029                                SetDataFolder $WaveDataFolder
1030                                temp = RemoveEnding(temp, "_RA")
1031                               
1032                                string xwave, ywave, oldywave, swave
1033                                if(exists(temp)==1)
1034                                        Wave/T WaveString = $temp
1035                                        WaveToRescale = temp
1036                                        if (stringmatch(WaveToRescale, "*_i"))
1037                                                DoWindow/F PlotGraph
1038                                                oldywave = WaveToRescale+"_RA"
1039                                                ywave = WaveToRescale
1040                                                replacewave/Y/W=$PlotGraph trace=$oldywave, $ywave
1041                                                xwave = RemoveEnding(WaveToRescale, "_i")+"_q"
1042                                                replacewave/X/W=$PlotGraph trace=$ywave, $xwave
1043                                                ModifyGraph log=0
1044                                                swave = RemoveEnding(WaveToRescale, "_i")+"_s"
1045                                                if(exists(swave)==1)
1046                                                        ErrorBars/W=$PlotGraph $ywave, Y wave=($swave,$swave)   
1047                                                endif
1048                                        elseif(stringmatch(WaveToRescale, "smeared*") && stringmatch(WaveToRescale, "!*_qvals"))
1049                                                oldywave = WaveToRescale+"_RA"
1050                                                ywave = WaveToRescale
1051                                                replacewave/Y/W=$PlotGraph trace=$oldywave, $ywave
1052                                                xwave = "smeared_qvals"
1053                                                replacewave/X/W=$PlotGraph trace=$ywave, $xwave
1054                                                ModifyGraph log=0
1055                                        elseif(stringmatch(WaveToRescale,"ywave*"))
1056                                                oldywave = WaveToRescale+"_RA"
1057                                                ywave = WaveToRescale
1058                                                xwave = ReplaceString("ywave",ywave,"xwave")
1059                                                replacewave/Y/W=$PlotGraph trace=$oldywave, $ywave
1060                                                replacewave/X/W=$PlotGraph trace=$ywave, $xwave                                 
1061                                        endif
1062                                SetDataFolder root:Packages:NIST:RescaleAxis
1063                                endif
1064                        endif
1065                endfor
1066                KillWaves/Z W_WaveList
1067                modifygraph log=1
1068                Label left "I(q)"
1069                Label bottom "q (A\S-1\M)"
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        // saving with a unique name can be an issue if there are a lot of files with similar names
1179        // and the fit function has a long name
1180        if(yesSave)
1181                String nameStr
1182                // function first               
1183//              nameStr=CleanupName(func,0)
1184//              nameStr += "_"+dataname
1185//              nameStr = ReplaceString("Smeared",nameStr,"Sm_")                //if Smeared function, shorten the name
1186                // -- or
1187                // data first
1188                nameStr = dataname+"_"
1189                nameStr += CleanupName(func,0)
1190                nameStr = ReplaceString("Smeared",nameStr,"Sm_")                //if Smeared function, shorten the name
1191
1192                //make sure the name is no more than 31 characters
1193                namestr = namestr[0,26]         //if shorter than 31, this will NOT pad to 31 characters
1194                nameStr += ".ifn"                       //extension is needed, otherwise the files are not recognized on Windows
1195               
1196                Print "file saved as ",nameStr
1197                SaveNotebook /O/P=home/S=2 $nb as nameStr
1198                //save the graph separately as a PNG file, 2x screen
1199                pictStr += nameStr
1200                pictStr = pictStr[0,24]+".png"          //need a shorter name - only 29 characters allowed - why?
1201//              DoWindow/F $topGraph
1202                // E=-5 is png @screen resolution
1203                // E=2 is PICT @2x screen resolution
1204///             SavePICT /E=-5/O/P=home /I/W=(0,0,3,3) as pictStr
1205                if(WaveExists(dataXw))
1206                        SavePICT /E=-5/O/P=home/WIN=$topGraph /W=(0,0,800,600) as pictStr
1207                else
1208                        Execute "ExportGizmo /P=home as \""+pictStr+"\""                //this won't be of very high quality
1209                        //SavePICT /E=-5/O/P=home/WIN=$topGraph /W=(0,0,400,300) as pictStr
1210                endif
1211        Endif
1212       
1213        // ???maybe print the notebook too?
1214End
1215
1216Function/S W_ErrorMessage(code)
1217        Variable code
1218       
1219        switch (code)
1220                case 0:
1221                        return "No Error"
1222                        break
1223                case 3: //2^0 + 2^1
1224                        return "Singular Matrix"
1225                        break
1226                case 5:         //(2^0 + 2^2)
1227                        return "Out of Memory"
1228                        break
1229                case 9:         //(2^0 + 2^3)
1230                        return "Func= NaN or Inf"
1231                        break
1232                default:
1233                        return "Unknown error code "+num2str(code)
1234        endswitch
1235end
1236
1237Function/S W_QuitMessage(code)
1238        Variable code
1239       
1240        switch (code)
1241                case 0:
1242                        return "No Error"
1243                        break
1244                case 1:
1245                        return "Max iterations - re-run fit"
1246                        break
1247                case 2:
1248                        return "User terminated fit"
1249                        break
1250                case 3:
1251                        return "No decrease in chi-squared"
1252                        break
1253                default:
1254                        return "Unknown Quit code "+num2str(code)
1255        endswitch
1256end
1257
1258Function UseInfoTextBoxCheckProc(cba) : CheckBoxControl
1259        STRUCT WMCheckboxAction &cba
1260
1261        switch( cba.eventCode )
1262                case 2: // mouse up
1263                        Variable checked = cba.checked
1264                        if(checked)
1265                                //print "checked, use textBox in the next fit"
1266                        else
1267                                //print "unchecked, ask to remove TextBox from the graph"
1268                                ControlInfo/W=WrapperPanel popup_0
1269                                RemoveTextBox(S_value)
1270                        endif
1271                        break
1272        endswitch
1273
1274        return 0
1275End
1276
1277//does not report an error if the text box is not there
1278// -- so I'll just be lazy and not check to see if it's there
1279//
1280Function RemoveTextBox(folderStr)
1281        String folderStr
1282       
1283        DoAlert 1,"Remove the TextBox from the graph?"
1284        if(V_flag == 1)
1285                String str = "CF_"+folderStr+"_i"
1286                TextBox/K/N=$str
1287        endif
1288        return(0)
1289End
1290
1291Function UseResidualsCheckProc(cba) : CheckBoxControl
1292        STRUCT WMCheckboxAction &cba
1293
1294        switch( cba.eventCode )
1295                case 2: // mouse up
1296                        Variable checked = cba.checked
1297                        if(checked)
1298                                //print "checked, use them in the next fit"
1299                        else
1300                                //print "unchecked, ask to remove residuals from the graph"
1301                                ControlInfo/W=WrapperPanel popup_0
1302                                RemoveResiduals(S_value)
1303                        endif
1304                        break
1305        endswitch
1306
1307        return 0
1308End
1309
1310// the default name from the /R flag is "Res_" + yWaveName
1311//
1312// better to find the wave that starts with "Res_" and remove that one in case the
1313// wave names get too long
1314//
1315// the difficulty now is that the residual wave ends up in root: and not with the data....
1316// -- not really a problem, but adds to clutter
1317Function RemoveResiduals(folderStr)
1318        String folderStr
1319       
1320        String list="",topWin=""
1321        Variable num,ii
1322        String str
1323
1324        DoAlert 1,"Remove the residuals from the graph?"
1325        if(V_flag == 1)
1326//              String topGraph= WinName(0,1)   //this is the topmost graph
1327                list=TraceNameList("", ";", 1 )         //"" as first parameter == look on the target graph
1328                num=ItemsInList(list)
1329               
1330                for(ii=0;ii<num;ii+=1)
1331                        str = StringFromList(ii, list ,";")
1332                        if(strsearch(str, "Res_", 0) != -1)
1333                                RemoveFromGraph $str
1334                        endif
1335                endfor
1336       
1337                SetDataFolder root:
1338        endif
1339       
1340        return(0)
1341End
1342
1343Function Toggle2DControlsCheckProc(cba) : CheckBoxControl
1344        STRUCT WMCheckboxAction &cba
1345
1346        switch( cba.eventCode )
1347                case 2: // mouse up
1348                        Variable checked = cba.checked
1349                        if(checked)
1350                                //print "change the buttons to 2D"
1351                                Button button_0,proc=Do2DFitButtonProc,title="Do 2D Fit"
1352                                Button button_1,size={120,20},proc=Plot2DFunctionButtonProc,title="Plot 2D Function"
1353                                Button button_2,size={100,20},proc=Append2DModelButtonProc,title="Append 2D"
1354                                Button button_3,size={100,20},proc=Load2DDataButtonProc,title="Load 2D Data"
1355                               
1356                                Button button_2D_0,pos={550,60},size={70,20},proc=LogToggle2DButtonProc,title="Log/Lin"
1357                                Button button_2D_1,pos={520,37},size={100,20},proc=Plot2DButtonProc,title="Plot 2D Data"
1358                               
1359                                Button button_2D_0,disable=0            //visible again, and enabled
1360                                Button button_2D_1,disable=0
1361                               
1362                                CheckBox check_6,disable=1                      //info box and residual check, remove these from view
1363                                CheckBox check_7,disable=1
1364                                CheckBox check_8,disable=1
1365                        else
1366                                //print "unchecked, change them back to 1D"
1367                                Button button_0,pos={520,93},size={100,20},proc=DoTheFitButton,title="Do 1D Fit"
1368                                Button button_1,pos={280,57},size={120,20},proc=PlotModelFunction,title="Plot 1D Function"
1369                                Button button_2,pos={300,93},size={100,20},proc=AppendModelToTarget,title="Append 1D"
1370                                Button button_3,pos={300,20},size={100,20},proc=W_LoadDataButtonProc,title="Load 1D Data"
1371                               
1372                                Button button_2D_0,disable=3    //hide the extra 2D buttons, and disable
1373                                Button button_2D_1,disable=3
1374                               
1375                                CheckBox check_6,disable=0                      //info box and residual check, bring them back
1376                                CheckBox check_7,disable=0
1377                                CheckBox check_8,disable=0
1378                        endif
1379                        break
1380        endswitch
1381
1382        return 0
1383End
1384
1385// function to either add or remove the cursors from the topmost graph, as needed
1386
1387Function UseCursorsWrapperProc(cba) : CheckBoxControl
1388        STRUCT WMCheckboxAction &cba
1389
1390
1391        switch( cba.eventCode )
1392                case 2: // mouse up
1393               
1394                        // check to make sure there really is a "topmost" graph         
1395                        String topGraph= WinName(0,1)   //this is the topmost graph
1396                        if(cmpstr(topGraph,"")==0)      //no graphs, uncheck and exit
1397                                CheckBox check_0,value=0
1398                                return(0)
1399                        endif
1400                       
1401                        //if in 2D mode, just exit
1402                        ControlInfo/W=WrapperPanel check_3
1403                        if(V_Value == 1)
1404                                return (0)
1405                        endif
1406                               
1407                        String ciStr = CsrInfo(A , topGraph)
1408                       
1409                        ControlInfo/W=wrapperpanel popup_0
1410                        String folderStr=S_Value
1411                        String traceList = TraceNameList(topGraph, ";", 1 )             
1412               
1413                        Variable checked = cba.checked
1414                       
1415                        if(checked)
1416                                //print "add the cursors to the topmost graph, if the data set is there, or move them"
1417                                if(strlen(ciStr)==0 && strsearch(traceList, folderStr, 0) != -1 )               //no cursors && data is there
1418                                        ShowInfo
1419                                        Wave yw=$("root:"+folderStr+":"+folderStr+"_i")
1420                                        Cursor/P/W=$topGraph A, $(folderStr+"_i"),0
1421                                        Cursor/P/W=$topGraph/A=0 B, $(folderStr+"_i"),numpnts(yw)-1                     //deactivate the one at the high Q end
1422                                        DoUpdate
1423                                elseif (strlen(ciStr)!=0 && strsearch(traceList, folderStr, 0) != -1 ) //cursors present, but on wrong data
1424                                        Wave yw=$("root:"+folderStr+":"+folderStr+"_i")
1425                                        Cursor/P/W=$topGraph A, $(folderStr+"_i"),0                                                             //move the cursors
1426                                        Cursor/P/W=$topGraph/A=0 B, $(folderStr+"_i"),numpnts(yw)-1
1427                                        DoUpdate
1428                                endif
1429                               
1430                                AreCursorsCorrect(folderStr)
1431                        else
1432                                //print "unchecked, remove the cursors"
1433                                // go back to the full matrix for the resolution calculation (not if SANS data...)
1434                                if(waveExists($("root:"+folderStr+":weights_save")))
1435                                        Duplicate/O $("root:"+folderStr+":weights_save"), $("root:"+folderStr+":"+folderStr+"_res"),$("root:"+folderStr+":"+folderStr+"_rest")
1436                                endif
1437
1438                                HideInfo/W=$topGraph
1439                                Cursor/K A
1440                                Cursor/K B
1441                        endif
1442                        break
1443        endswitch
1444
1445        return 0
1446End
1447
1448// returns 1 if the specified data is on the top graph && has cursors on it
1449// returns 0 and unchecks the box if anything is wrong
1450//
1451// only call this function if the cursor box is checked, to uncheck it as needed
1452// if the box is unchecked, leave it be.
1453//
1454Function AreCursorsCorrect(folderStr)
1455        String folderStr
1456       
1457        String topGraph= WinName(0,1)   //this is the topmost graph
1458        if(cmpstr(topGraph,"")==0)      //no graphs, uncheck and exit
1459                CheckBox check_0,win=wrapperpanel,value=0
1460                return(0)
1461        endif
1462               
1463        String traceAisOn = CsrWave(A , "", 0)
1464        if(     strsearch(traceAisOn, folderStr, 0) == -1)              //data and cursors don't match
1465                CheckBox check_0,win=wrapperpanel,value=0
1466                HideInfo
1467                Cursor/K A
1468                Cursor/K B
1469                return(0)
1470        endif
1471       
1472        return(1)
1473End
1474
1475
1476
1477//////////////////////////////
1478//
1479// displays the covariance matrix for the current data set in the popup
1480// AND whatever was the last fit for that data set. it may not necessarily
1481// be the displayed function...
1482Function DisplayCovarianceMatrix()
1483
1484       
1485
1486        ControlInfo/W=wrapperpanel popup_0
1487        String folderStr=S_Value
1488
1489        ControlInfo/W=WrapperPanel popup_1
1490        String funcStr=S_Value
1491                       
1492        if(Stringmatch(funcStr,"Smear*"))               //simple test for smeared function
1493                if(DataFolderExists("root:"+folderStr))
1494                        SetDataFolder $("root:"+folderStr)
1495                else
1496                        SetDataFolder root:
1497                endif
1498        else
1499                SetDataFolder root:
1500        endif
1501       
1502        Wave M_Covar=M_Covar
1503        Duplicate/O M_Covar, CorMat      // You can use any name instead of CorMat
1504        CorMat = M_Covar[p][q]/sqrt(M_Covar[p][p]*M_Covar[q][q])
1505
1506        // clear the table (a subwindow)
1507        DoWindow/F CorMatPanel                          // ?? had to add this in during all of the cursor meddling...
1508        KillWindow CorMatPanel#T0
1509        Edit/W=(20,74,634,335)/HOST=CorMatPanel
1510        RenameWindow #,T0
1511        // get them onto the table
1512        // how do I get the parameter name?
1513        String param = getFunctionParams(funcStr)
1514        AppendtoTable/W=CorMatPanel#T0 $param
1515        AppendToTable/W=CorMatPanel#T0 CorMat
1516        ModifyTable/W=CorMatPanel#T0 width(Point)=0
1517
1518        GroupBox grpBox_1 title="Data set: "+folderStr
1519        GroupBox grpBox_2 title="Function: "+funcStr
1520
1521
1522        SetDataFolder root:
1523       
1524        return(0)
1525End
1526
1527
1528Window CorMatPanel()
1529        PauseUpdate; Silent 1           // building window...
1530        NewPanel /W=(459,44,1113,399)/N=CorMatPanel/K=1 as "Correlation Matrix"
1531        ModifyPanel fixedSize=1
1532       
1533        GroupBox grpBox_1 title="box 1",pos={10,20},size={0,0},frame=1,fSize=10,fstyle=1,fColor=(39321,1,1)
1534        GroupBox grpBox_2 title="box 2",pos={10,40},size={0,0},frame=1,fSize=10,fstyle=1,fColor=(39321,1,1)
1535
1536        Button button_1,pos={520,30},size={100,20},proc=CorMatHelpButtonProc,title="Help"
1537
1538        Edit/W=(20,74,634,335)/HOST=# 
1539        ModifyTable width(Point)=0
1540        RenameWindow #,T0
1541        SetActiveSubwindow ##
1542EndMacro
1543
1544
1545Proc DisplayCovariance()
1546        DoWindow/F CorMatPanel
1547        if(V_Flag==0)
1548                CorMatPanel()
1549        endif
1550       
1551        DisplayCovarianceMatrix()
1552
1553End
1554
1555//open the Help file for the Fit Manager
1556Function CorMatHelpButtonProc(ba) : ButtonControl
1557        STRUCT WMButtonAction &ba
1558
1559        switch( ba.eventCode )
1560                case 2: // mouse up
1561                        // click code here
1562                        DisplayHelpTopic/Z/K=1 "Covariance Matrix"
1563                        if(V_flag !=0)
1564                                DoAlert 0,"Help for the correlation matrix could not be found"
1565                        endif
1566                        break
1567        endswitch
1568
1569        return 0
1570End
1571
1572
1573//////////////////////////////////
1574// this is a snippet from Andy Nelson, posted at the Igor Exchange web site.
1575//
1576// search area appears to be a percent (so enter 10 to get +/- 10% variation in the parameter)
1577//
1578// TODO:
1579//              x- rename the function for just me
1580//              x- make the edata a mandatory parameter
1581//              x- remove rhs, lhs? or keep these if cursors were used to properly trim the data set
1582//              x- label the graph
1583//              x- make a panel to control this - to either pick a single parameter, or show all of them
1584//              x- have it re-use the same graph, not draw a (new) duplicate one
1585//              x- update it to use the AAO as the input function (new func template -- see Gauss Utils)
1586//              x- the wrapper must be data folder aware, and data set aware like in the Wrapper panel
1587//              x- need a different wrapper for smeared and unsmeared functions
1588//
1589//
1590
1591
1592
1593Proc MapChiSquared(paramNum,percent)
1594        Variable paramNum=0,percent=10
1595        Prompt paramNum, "Enter parameter number: "
1596        Prompt percent, "Enter percent variation +/- : "
1597
1598        fChiMap(paramNum,percent)
1599End
1600
1601
1602// this does the setup
1603Function fChiMap(paramNum,percent)
1604        Variable paramNum,percent
1605
1606        String folderStr,funcStr,coefStr
1607        Variable useCursors,useResol=0,pt1,pt2,minIndex
1608       
1609        ControlInfo/W=WrapperPanel popup_0
1610        folderStr=S_Value
1611       
1612        ControlInfo/W=WrapperPanel popup_1
1613        funcStr=S_Value
1614       
1615        ControlInfo/W=WrapperPanel popup_2
1616        coefStr=S_Value
1617       
1618        ControlInfo/W=WrapperPanel check_0
1619        useCursors=V_Value
1620       
1621       
1622// first, figure out where we are...
1623        String suffix=getModelSuffix(funcStr)
1624       
1625        SetDataFolder $("root:"+folderStr)
1626        if(!exists(coefStr))
1627                // must be unsmeared model, work in the root folder
1628                SetDataFolder root:                             
1629                if(!exists(coefStr))            //this should be fine if the coef filter is working, but check anyhow
1630                        DoAlert 0,"the coefficient and data sets do not match"
1631                        return 0
1632                endif
1633        endif
1634               
1635        WAVE cw=$(coefStr)
1636
1637
1638// test for smeared function
1639        if(stringmatch(funcStr, "Smear*"))              // if it's a smeared function, need a struct
1640                useResol=1
1641        endif
1642       
1643        // fill a struct instance whether I need one or not
1644        String DF="root:"+folderStr+":"
1645       
1646//      Struct ResSmearAAOStruct fs
1647//      WAVE/Z resW = $(DF+folderStr+"_res")                    //these may not exist, if 3-column data is used
1648//      WAVE/Z fs.resW =  resW
1649        WAVE yw=$(DF+folderStr+"_i")
1650        WAVE xw=$(DF+folderStr+"_q")
1651        WAVE sw=$(DF+folderStr+"_s")
1652//      Wave fs.coefW = cw
1653//      Wave fs.yW = yw
1654//      Wave fs.xW = xw
1655       
1656        if(useCursors)
1657                if(pcsr(A) > pcsr(B))
1658                        pt1 = pcsr(B)
1659                        pt2 = pcsr(A)
1660                else
1661                        pt1 = pcsr(A)
1662                        pt2 = pcsr(B)
1663                endif
1664        else
1665                //if cursors are not being used, find the first and last points of the data set, and pass them
1666                pt1 = 0
1667                pt2 = numpnts(yw)-1
1668        endif
1669       
1670        minIndex = chi2gen(funcStr,folderStr,xw,yw,sw,cw,paramNum,percent,pt1,pt2,useResol)
1671       
1672        WAVE chi2_map=chi2_map
1673        cw[paramNum] = pnt2x(chi2_map, minIndex)
1674       
1675        return(0)
1676End
1677
1678// this does the math for a single value of "whichParam"
1679Function chi2gen(funcStr,folderStr,xw,yw,sw,cw,whichParam,searchArea,lhs,rhs,useResol)
1680        String funcStr,folderStr
1681        Wave xw,yw,sw,cw      //        x data, y data, error wave, and coefficient wave
1682        variable whichParam, searchArea  //which of the parameters to you want to vary, how far from the original value do you want to search (%)
1683        variable lhs, rhs    //specify a region of interest in the data using a left hand side and right hand side.
1684        variable useResol               // =1 if smeared used
1685 
1686        variable originalvalue = cw[whichparam]
1687        variable range = originalValue * searchArea/100
1688        variable ii,err,minIndex
1689 
1690        duplicate/o yw, :theoretical_data, :chi2_data
1691        Wave theoretical_data, chi2_data
1692 
1693        make/o/n=50/d chi2_map
1694        setscale/I x,  originalvalue - range, originalvalue + range, chi2_map
1695 
1696        String DF="root:"+folderStr+":"
1697        String suffix=getModelSuffix(funcStr)
1698
1699        // fill a struct instance whether it is needed or not
1700        Struct ResSmearAAOStruct fs
1701        WAVE/Z resW = $(DF+folderStr+"_res")                    //these may not exist, if 3-column data is used
1702        WAVE/Z fs.resW =  resW
1703//              WAVE yw=$(DF+folderStr+"_i")
1704//              WAVE xw=$(DF+folderStr+"_q")
1705//              WAVE sw=$(DF+folderStr+"_s")
1706        Wave fs.coefW = cw
1707        Wave fs.yW = theoretical_data
1708        Wave fs.xW = xw
1709 
1710 
1711 
1712        for(ii=0 ; ii < numpnts(chi2_map) ; ii+=1)
1713                cw[whichparam] = pnt2x(chi2_map, ii)
1714 
1715                if(useResol)
1716                        FUNCREF SANSModelSTRUCT_proto func1=$funcStr
1717                        err = func1(fs)
1718                else
1719                        FUNCREF SANSModelAAO_proto func2=$funcStr
1720                        func2(cw,theoretical_data,xw)
1721                endif
1722               
1723                chi2_data = (yw-theoretical_data)^2
1724 
1725                chi2_data /= sw^2
1726
1727                Wavestats/q/R=[lhs, rhs] chi2_data
1728 
1729                chi2_map[ii] = V_avg * V_npnts
1730        endfor
1731 
1732        cw[whichparam] = originalvalue
1733 
1734        DoWindow/F Chi2
1735        if(V_flag==0)
1736                display/K=1/N=Chi2 chi2_map
1737                Label left "Chi^2"
1738        endif
1739
1740        String parStr=GetWavesDataFolder(cw,1)+ WaveList("*param*"+"_"+suffix, "", "TEXT:1," )          // this is *hopefully* one wave
1741        Wave/T parW = $parStr
1742        Label bottom parW[whichParam]
1743       
1744        WaveStats/Q chi2_map
1745        minIndex = V_minRowLoc
1746        Print "minimum at: ", minIndex,chi2_map[minIndex]
1747       
1748       
1749        killwaves/z theoretical_data, chi2_data
1750        return(minIndex)
1751End
1752 
1753
1754//////////////////////////////////
1755// this is based on a snippet from Andy Nelson, posted at the Igor Exchange web site.
1756// -- modified to do "manual fitting" - mapping out chi-squared along one or two directions
1757//////////////////////////////////
1758
1759Proc OpenManualFitPanel()
1760
1761        DoWindow/F ManualFitPanel
1762        if(V_flag==0)
1763                init_manualFit()
1764                ManualFitPanel()
1765        Endif
1766
1767End
1768
1769Function init_manualFit()
1770
1771        Variable/G root:gNumManualParam=0
1772        Variable/G root:gNumManualParam2=1
1773        Variable/G root:gCurrentChiSq=0
1774        Variable/G root:gNumManualSteps=50
1775       
1776        Make/O/D/N=1 root:chi2_map,root:testVals
1777        Make/O/D/N=(1,1) root:chi2D
1778       
1779        return(0)
1780end
1781
1782Window ManualFitPanel() : Panel
1783        PauseUpdate; Silent 1           // building window...
1784        NewPanel /W=(1170,44,1842,412) /K=1
1785        ModifyPanel cbRGB=(51664,44236,58982)
1786        DoWindow/C ManualFitPanel
1787       
1788//      ShowTools/A
1789        SetVariable setvar0,pos={25,10},size={150,15},title="Parameter number"
1790        SetVariable setvar0,limits={0,inf,1},value=root:gNumManualParam,disable=0
1791        SetVariable setvar3,pos={25,30},size={150,15},title="Parameter number"
1792        SetVariable setvar3,limits={0,inf,1},value=root:gNumManualParam2,disable=2
1793       
1794        CheckBox check0,pos={200,10},size={37,15},value=0,title="2D?",proc=Vary2DCheck
1795               
1796        Button button0,pos={25,55},size={100,20},title="Vary 100 %",proc=VaryPCTButton
1797        Button button1,pos={25,80},size={100,20},title="Vary 25 %",proc=VaryPCTButton
1798        Button button2,pos={25,105},size={100,20},title="Vary 5 %",proc=VaryPCTButton
1799        Button button3,pos={25,130},size={100,20},title="Vary 1 %",proc=VaryPCTButton
1800        SetVariable setvar1,pos={31,196},size={200,15},title="Current Chi-Squared"
1801        SetVariable setvar1,limits={0,0,0},value=root:gCurrentChiSq     
1802        SetVariable setvar2,pos={31,222},size={200,15},title="Number of steps"
1803        SetVariable setvar2,limits={5,500,1},value=root:gNumManualSteps
1804       
1805        //
1806        Display/W=(259,23,643,346)/HOST=# root:chi2_map vs root:testVals
1807        RenameWindow #,G0
1808        ModifyGraph mode=4,msize=1,rgb=(65535,0,0)
1809        ModifyGraph tick=2,mirror=1
1810//      Label left "Chi-squared"
1811//      Label bottom "degrees" 
1812        SetActiveSubwindow ##
1813               
1814EndMacro
1815
1816
1817Function Vary2DCheck(ctrlName,checked)
1818        String ctrlName
1819        Variable checked
1820       
1821        ControlInfo check0
1822        Variable isChecked = V_Value
1823       
1824        Wave chi2D=chi2D
1825        Wave chi2_map=chi2_map
1826        wave testVals=testVals
1827       
1828        if(isChecked)
1829                SetVariable setvar0,disable=0
1830                SetVariable setvar3,disable=0
1831               
1832                //
1833                RemoveFromGraph/W=ManualFitPanel#G0 chi2_map
1834               
1835//              Display/W=(259,23,643,346)/HOST=#
1836                AppendImage/W=ManualFitPanel#G0 chi2D
1837                SetActiveSubwindow ManualFitPanel#G0
1838                ModifyImage chi2D ctab= {*,*,ColdWarm,0}
1839                Label left "par"
1840                Label bottom "par2"
1841                SetActiveSubwindow ##
1842               
1843        else
1844                SetVariable setvar0,disable=0
1845                SetVariable setvar3,disable=2
1846               
1847                //
1848                RemoveImage/W=ManualFitPanel#G0 chi2D
1849
1850                AppendToGraph/W=ManualFitPanel#G0 root:chi2_map vs root:testVals
1851                SetActiveSubwindow ManualFitPanel#G0
1852//              Display/W=(259,23,643,346)/HOST=# root:chi2_map vs root:testVals
1853                ModifyGraph mode=4,msize=1,rgb=(65535,0,0)
1854                ModifyGraph tick=2,mirror=1
1855                Label left "Chi-squared"
1856        //      Label bottom "degrees" 
1857                SetActiveSubwindow ##
1858               
1859               
1860        endif
1861       
1862        return(0)
1863End
1864
1865
1866Function getParamFromWrapper()
1867
1868        Variable parNum
1869       
1870        GetSelection table, WrapperPanel#T0, 1
1871        parNum = V_startRow
1872        return(parNum)
1873End
1874
1875
1876Function VaryPCTButton(ctrlName) : ButtonControl
1877        String ctrlName
1878
1879        Variable percent
1880        strswitch(ctrlName)     // string switch
1881                case "button0":         
1882                        percent = 105
1883                        break
1884                case "button1":         
1885                        percent = 25
1886                        break
1887                case "button2":         
1888                        percent = 5
1889                        break           
1890                case "button3":         
1891                        percent = 1
1892                        break
1893                default:                                                       
1894                        percent = 10                                   
1895        endswitch
1896
1897        ControlInfo check0
1898        Variable isChecked = V_Value
1899
1900        // get the necessary info about parameters, etc.
1901        String folderStr,funcStr,coefStr
1902        Variable useCursors,useResol=0,pt1,pt2,minIndex
1903       
1904        ControlInfo/W=WrapperPanel popup_0
1905        folderStr=S_Value
1906       
1907        ControlInfo/W=WrapperPanel popup_1
1908        funcStr=S_Value
1909       
1910        ControlInfo/W=WrapperPanel popup_2
1911        coefStr=S_Value
1912       
1913//      ControlInfo/W=WrapperPanel check_0
1914//      useCursors=V_Value
1915//     
1916       
1917// first, figure out where we are...
1918        String suffix=getModelSuffix(funcStr)
1919       
1920        SetDataFolder $("root:"+folderStr)
1921        if(!exists(coefStr))
1922                // must be unsmeared model, work in the root folder
1923                SetDataFolder root:                             
1924                if(!exists(coefStr))            //this should be fine if the coef filter is working, but check anyhow
1925                        DoAlert 0,"the coefficient and data sets do not match"
1926                        return 0
1927                endif
1928        endif
1929               
1930        WAVE cw=$(coefStr)
1931        SetDataFolder root:
1932
1933       
1934        Variable loLim,hiLim,minChiSq
1935
1936        NVAR numStep = root:gNumManualSteps
1937        make/o/n=(numStep)/D root:testVals
1938        Wave testVals = root:testVals
1939        WAVE chi2_map = root:chi2_map
1940        Make/O/D/N=(numStep,numStep) root:chi2D
1941        WAVE chi2D = root:chi2D
1942       
1943       
1944        // then do either a 1D or 2D map of the chi squared
1945        if(isChecked)
1946       
1947                NVAR par = root:gNumManualParam
1948                NVAR par2 = root:gNumManualParam2
1949               
1950                Variable ii,jj,saveVal2
1951                saveVal2 = cw[par2]             //initial value of par2
1952               
1953                //steps in par2 direction
1954                make/o/n=(numStep)/D root:testVals2
1955                Wave testVals2 = root:testVals2
1956                loLim = cw[par2] - percent*cw[par2]/100
1957                hiLim = cw[par2] + percent*cw[par2]/100
1958                testVals2 = loLim + x*(hiLim-loLim)/numStep
1959
1960                SetScale/I x LoLim,HiLim,"", chi2D
1961
1962                //steps in par1 direction
1963                if(cw[par] != 0)       
1964                        loLim = cw[par] - percent*cw[par]/100
1965                        hiLim = cw[par] + percent*cw[par]/100
1966                else
1967                        loLim = -1
1968                        hiLim = 1
1969                endif
1970                testVals = loLim + x*(hiLim-loLim)/numStep
1971                SetScale/I y LoLim,HiLim,"", chi2D
1972
1973               
1974                for(ii=0;ii<numStep;ii+=1)
1975                        cw[par2] = testVals2[ii]                //set the value for par2, vary par
1976               
1977                        fChiMap_new(par,percent,cw,testVals)            //the wave chi2_map is generated
1978
1979                        chi2D[ii][] = chi2_map[q]
1980       
1981                endfor
1982
1983                // set the new minimum value
1984                WaveStats/Q chi2D
1985        // now with scaled dimensions of Chi2D, the reported values are the values, not the point index
1986                cw[par] = V_MinColLoc
1987                cw[par2] = V_MinRowLoc 
1988       
1989                // the minimum chi_squared  along this path is at: -- is it better?
1990                minChiSq = V_Min
1991       
1992                NVAR curChi2=root:gCurrentChiSq
1993                curChi2 = minChiSq     
1994       
1995                //V_min*1.01 = the 1% neighborhood around the solution
1996                ModifyImage/W=ManualFitPanel#G0 chi2D ctab= {(V_min*1.01),*,ColdWarm,0}
1997                ModifyImage/W=ManualFitPanel#G0 chi2D minRGB=(0,65535,0),maxRGB=(0,65535,0)
1998       
1999        else
2000                NVAR par = root:gNumManualParam
2001                par = getParamFromWrapper()
2002               
2003                if(cw[par] != 0)       
2004                        loLim = cw[par] - percent*cw[par]/100
2005                        hiLim = cw[par] + percent*cw[par]/100
2006                else
2007                        loLim = -1
2008                        hiLim = 1
2009                endif
2010                testVals = loLim + x*(hiLim-loLim)/numStep
2011
2012               
2013                fChiMap_new(par,percent,cw,testVals)            //the wave chi2_map is generated
2014                       
2015                // set the new minimum value
2016                WaveStats/Q chi2_map
2017                minIndex = V_minRowLoc
2018                cw[par] = testVals[minIndex]
2019               
2020                // the minimum chi_squared  along this path is at: -- is it better?
2021                minChiSq = chi2_map[minIndex]
2022       
2023                NVAR curChi2=root:gCurrentChiSq
2024                curChi2 = minChiSq
2025        endif
2026       
2027       
2028        return(0)
2029End
2030
2031
2032Proc mMapChiSquared_Pct(paramNum,percent)
2033        Variable paramNum=0,percent=50
2034        Prompt paramNum, "Enter parameter number: "
2035        Prompt percent, "Enter percent variation:"
2036
2037        fChiMap_new(paramNum,percent)
2038End
2039
2040//Macro mMapChiSquared(paramNum,loLim,hiLim)
2041//      Variable paramNum=0,loLim=0,hiLim=1
2042//      Prompt paramNum, "Enter parameter number: "
2043//      Prompt loLim, "Enter lower value:"
2044//      Prompt hiLim, "Enter higher value:"
2045//
2046//      fChiMap_new(paramNum,loLim,hiLim)
2047//End
2048
2049
2050// this does the setup
2051Function fChiMap_new(paramNum,percent,cw,testVals)
2052        Variable paramNum,percent
2053        Wave cw,testVals
2054       
2055//Function fChiMap_new(paramNum,percent)
2056//      Variable paramNum,percent
2057
2058
2059        String folderStr,funcStr,coefStr
2060        Variable useCursors,useResol=0,pt1,pt2,minIndex
2061       
2062        ControlInfo/W=WrapperPanel popup_0
2063        folderStr=S_Value
2064       
2065        ControlInfo/W=WrapperPanel popup_1
2066        funcStr=S_Value
2067       
2068        ControlInfo/W=WrapperPanel popup_2
2069        coefStr=S_Value
2070       
2071        ControlInfo/W=WrapperPanel check_0
2072        useCursors=V_Value
2073       
2074// coefficent wave cw is passed in
2075
2076// test for smeared function
2077        if(stringmatch(funcStr, "Smear*"))              // if it's a smeared function, need a struct
2078                useResol=1
2079        endif
2080       
2081        // wave references for the data (to pass)
2082        String DF="root:"+folderStr+":"
2083       
2084        WAVE yw=$(DF+folderStr+"_i")
2085        WAVE xw=$(DF+folderStr+"_q")
2086        WAVE sw=$(DF+folderStr+"_s")
2087
2088        if(useCursors)
2089                if(pcsr(A) > pcsr(B))
2090                        pt1 = pcsr(B)
2091                        pt2 = pcsr(A)
2092                else
2093                        pt1 = pcsr(A)
2094                        pt2 = pcsr(B)
2095                endif
2096        else
2097                //if cursors are not being used, find the first and last points of the data set, and pass them
2098                pt1 = 0
2099                pt2 = numpnts(yw)-1
2100        endif
2101
2102        Variable loLim,hiLim,minChiSq
2103
2104        SetDataFolder root:
2105       
2106        NVAR numStep = root:gNumManualSteps
2107        make/o/n=(numStep)/D root:chi2_map
2108        Wave chi2_map = root:chi2_map
2109//      Wave testVals = root:testVals
2110       
2111        //the testVals are genereated and passed by the calling routine
2112                       
2113        minIndex = chi2gen_new(funcStr,folderStr,xw,yw,sw,cw,paramNum,pt1,pt2,useResol,chi2_map,testVals)
2114       
2115        return(0)
2116End
2117
2118
2119// this does the math for a single value of "whichParam"
2120Function chi2gen_new(funcStr,folderStr,xw,yw,sw,cw,whichParam,lhs,rhs,useResol,chi2_map,testVals)
2121        String funcStr,folderStr
2122        Wave xw,yw,sw,cw      //        x data, y data, error wave, and coefficient wave
2123        variable whichParam  //which of the parameters to you want to vary, how far from the original value do you want to search (%)
2124        variable lhs, rhs    //specify a region of interest in the data using a left hand side and right hand side.
2125        variable useResol               // =1 if smeared used
2126        Wave chi2_map,testVals
2127 
2128        variable originalvalue = cw[whichparam]
2129//      variable range = originalValue * searchArea/100
2130        variable ii,err,minIndex
2131 
2132        duplicate/o yw, :theoretical_data, :chi2_data
2133        Wave theoretical_data, chi2_data
2134 
2135        String DF="root:"+folderStr+":"
2136        String suffix=getModelSuffix(funcStr)
2137
2138        // fill a struct instance whether it is needed or not
2139        Struct ResSmearAAOStruct fs
2140        WAVE/Z resW = $(DF+folderStr+"_res")                    //these may not exist, if 3-column data is used
2141        WAVE/Z fs.resW =  resW
2142//              WAVE yw=$(DF+folderStr+"_i")                    //these are passed in
2143//              WAVE xw=$(DF+folderStr+"_q")
2144//              WAVE sw=$(DF+folderStr+"_s")
2145        Wave fs.coefW = cw
2146        Wave fs.yW = theoretical_data
2147        Wave fs.xW = xw
2148 
2149 
2150 
2151        for(ii=0 ; ii < numpnts(chi2_map) ; ii+=1)
2152                cw[whichparam] = testVals[ii]
2153 
2154                if(useResol)
2155                        FUNCREF SANSModelSTRUCT_proto func1=$funcStr
2156                        err = func1(fs)
2157                else
2158                        FUNCREF SANSModelAAO_proto func2=$funcStr
2159                        func2(cw,theoretical_data,xw)
2160                endif
2161               
2162                chi2_data = (yw-theoretical_data)^2
2163 
2164                chi2_data /= sw^2
2165
2166                Wavestats/q/R=[lhs, rhs] chi2_data
2167 
2168                chi2_map[ii] = V_avg * V_npnts
2169        endfor
2170 
2171        cw[whichparam] = originalvalue
2172
2173       
2174        WaveStats/Q chi2_map
2175        minIndex = V_minRowLoc
2176//      Print "minimum at: ", minIndex,chi2_map[minIndex]
2177       
2178        killwaves/z theoretical_data, chi2_data
2179        return(minIndex)
2180End
2181
2182//////////////////////////
Note: See TracBrowser for help on using the repository browser.