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

Last change on this file since 1222 was 1222, checked in by srkline, 3 years ago

Updated help file for VSANS. Graphics were not PNG.

Removed HFIR SANS package since if requires XML XOP - no longer supported.

Improved quality of graphics export for Analysis reports.

Added more support for super_white_beam mode on VSANS

Corrected printf bug (Igor 8) when printing out % sign

Added utilities for patching wavelength and monochromator type on VSANS since the type is still not written out correctly by NICE, and super_white_beam is not yet defined in NICE

Adjusted panel dimensions for the temperature sensor display on VSANS (needed onWindows)

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