source: sasview/src/sas/sasgui/perspectives/fitting/fitproblem.py @ cd31251

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since cd31251 was fc18690, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 9 years ago

Sasmodels integration - moved smearing from models to sascalc.

  • Property mode set to 100644
File size: 20.8 KB
RevLine 
[f32d144]1"""
2Inferface containing information to store data, model, range of data, etc...
3and retreive this information. This is an inferface
4for a fitProblem i.e relationship between data and model.
5"""
[3e3ab46]6################################################################################
7#This software was developed by the University of Tennessee as part of the
8#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
[f32d144]9#project funded by the US National Science Foundation.
[3e3ab46]10#
11#See the license text in license.txt
12#
13#copyright 2009, University of Tennessee
14################################################################################
[f32d144]15import copy
[fc18690]16from sas.sascalc.data_util.qsmearing import smear_selection
[d89f09b]17
[3e3ab46]18class FitProblemComponent(object):
19    """
20    Inferface containing information to store data, model, range of data, etc...
[f32d144]21    and retreive this information. This is an inferface
[3e3ab46]22    for a fitProblem i.e relationship between data and model.
23    """
24    def enable_smearing(self, flag=False):
25        """
26        :param flag: bool.When flag is 1 get the computer smear value. When
[ac7be54]27            flag is 0 ingore smear value.
[3e3ab46]28        """
[2f4b430]29
[3e3ab46]30    def get_smearer(self):
31        """
32        return smear object
33        """
34    def save_model_name(self, name):
35        """
[f32d144]36        """
[2f4b430]37
[3e3ab46]38    def get_name(self):
39        """
40        """
[2f4b430]41
[3e3ab46]42    def set_model(self, model):
[f32d144]43        """
[3e3ab46]44        associates each model with its new created name
45        :param model: model selected
46        :param name: name created for model
47        """
[2f4b430]48
[3e3ab46]49    def get_model(self):
50        """
51        :return: saved model
52        """
[2f4b430]53
[62f851f]54    def set_residuals(self, residuals):
[f32d144]55        """
[62f851f]56        save a copy of residual
57        :param data: data selected
58        """
[2f4b430]59
[62f851f]60    def get_residuals(self):
61        """
62        :return: residuals
63        """
[2f4b430]64
[3e3ab46]65    def set_theory_data(self, data):
[f32d144]66        """
[3e3ab46]67        save a copy of the data select to fit
68        :param data: data selected
69        """
[2f4b430]70
[3e3ab46]71    def get_theory_data(self):
72        """
73        :return: list of data dList
74        """
[2f4b430]75
[3e3ab46]76    def set_fit_data(self, data):
[f32d144]77        """
[ac7be54]78        Store of list of data and create  by create new fitproblem of each data
79        id, if there was existing information about model, this information
80        get copy to the new fitproblem
[3e3ab46]81        :param data: list of data selected
[f32d144]82        """
[2f4b430]83
[3e3ab46]84    def get_fit_data(self):
85        """
86        """
[2f4b430]87
[3e3ab46]88    def set_model_param(self, name, value=None):
[f32d144]89        """
[3e3ab46]90        Store the name and value of a parameter of this fitproblem's model
91        :param name: name of the given parameter
92        :param value: value of that parameter
93        """
[2f4b430]94
[1b14795]95    def set_param2fit(self, list):
96        """
97        Store param names to fit (checked)
98        :param list: list of the param names
99        """
[2f4b430]100
[1b14795]101    def get_param2fit(self):
102        """
103        return the list param names to fit
104        """
[2f4b430]105
[3e3ab46]106    def get_model_param(self):
[f32d144]107        """
[3e3ab46]108        return list of couple of parameter name and value
109        """
[2f4b430]110
[3e3ab46]111    def schedule_tofit(self, schedule=0):
112        """
113        set schedule to true to decide if this fit  must be performed
114        """
[2f4b430]115
[3e3ab46]116    def get_scheduled(self):
117        """
118        return true or false if a problem as being schedule for fitting
119        """
[2f4b430]120
[3e3ab46]121    def set_range(self, qmin=None, qmax=None):
122        """
[f32d144]123        set fitting range
[3e3ab46]124        """
[2f4b430]125
[3e3ab46]126    def get_range(self):
127        """
128        :return: fitting range
129        """
[2f4b430]130
[f7ef313]131    def set_weight(self, flag=None):
[55bb249c]132        """
[f32d144]133        set fitting range
[55bb249c]134        """
[2f4b430]135
[55bb249c]136    def get_weight(self):
137        """
138        get fitting weight
139        """
[2f4b430]140
[3e3ab46]141    def clear_model_param(self):
142        """
143        clear constraint info
144        """
[2f4b430]145
[3e3ab46]146    def set_fit_tab_caption(self, caption):
147        """
148        store the caption of the page associated with object
149        """
[2f4b430]150
[3e3ab46]151    def get_fit_tab_caption(self):
152        """
153        Return the caption of the page associated with object
154        """
[2f4b430]155
[5e48acb]156    def set_graph_id(self, id):
157        """
[2f4b430]158        Set graph id (from data_group_id at the time the graph produced)
[5e48acb]159        """
[2f4b430]160
[f32d144]161    def get_graph_id(self):
[5e48acb]162        """
163        Get graph_id
[f32d144]164        """
165
[41661a0]166    def set_result(self, result):
167        """
168        """
169
170    def get_result(self):
171        """
[f32d144]172        get result
173        """
[41661a0]174
[2f4b430]175
[3e3ab46]176class FitProblemDictionary(FitProblemComponent, dict):
177    """
178    This module implements a dictionary of fitproblem objects
179    """
180    def __init__(self):
181        FitProblemComponent.__init__(self)
182        dict.__init__(self)
183        ## the current model
184        self.model = None
[f32d144]185        ## if 1 this fit problem will be selected to fit , if 0
[3e3ab46]186        ## it will not be selected for fit
187        self.schedule = 0
188        ##list containing parameter name and value
189        self.list_param = []
190        ## fitting range
191        self.qmin = None
192        self.qmax = None
[5e48acb]193        self.graph_id = None
[3e3ab46]194        self._smear_on = False
195        self.scheduled = 0
196        self.fit_tab_caption = ''
[f64a4b7]197        self.nbr_residuals_computed = 0
198        self.batch_inputs = {}
199        self.batch_outputs = {}
[2f4b430]200
[3e3ab46]201    def enable_smearing(self, flag=False, fid=None):
202        """
203        :param flag: bool.When flag is 1 get the computer smear value. When
[ac7be54]204            flag is 0 ingore smear value.
[3e3ab46]205        """
206        self._smear_on = flag
207        if fid is None:
208            for value in self.itervalues():
209                value.enable_smearing(flag)
210        else:
211            if fid in self.iterkeys():
212                self[fid].enable_smearing(flag)
[2f4b430]213
[3e3ab46]214    def set_smearer(self, smearer, fid=None):
215        """
216        save reference of  smear object on fitdata
217        :param smear: smear object from DataLoader
218        """
219        if fid is None:
220            for value in self.itervalues():
221                value.set_smearer(smearer)
222        else:
223            if fid in self.iterkeys():
224                self[fid].set_smearer(smearer)
[2f4b430]225
[3e3ab46]226    def get_smearer(self, fid=None):
227        """
228        return smear object
229        """
[62f851f]230        if fid in self.iterkeys():
231            return self[fid].get_smearer()
[2f4b430]232
[3e3ab46]233    def save_model_name(self, name, fid=None):
234        """
[f32d144]235        """
[3e3ab46]236        if fid is None:
237            for value in self.itervalues():
238                value.save_model_name(name)
239        else:
240            if fid in self.iterkeys():
241                self[fid].save_model_name(name)
[2f4b430]242
[3e3ab46]243    def get_name(self, fid=None):
244        """
245        """
246        result = []
247        if fid is None:
248            for value in self.itervalues():
249                result.append(value.get_name())
250        else:
251            if fid in self.iterkeys():
252                result.append(self[fid].get_name())
253        return result
[2f4b430]254
[3e3ab46]255    def set_model(self, model, fid=None):
[f32d144]256        """
[3e3ab46]257        associates each model with its new created name
258        :param model: model selected
259        :param name: name created for model
260        """
261        self.model = model
262        if fid is None:
263            for value in self.itervalues():
264                value.set_model(self.model)
265        else:
266            if fid in self.iterkeys():
267                self[fid].set_model(self.model)
[2f4b430]268
[3e3ab46]269    def get_model(self, fid):
270        """
271        :return: saved model
272        """
273        if fid in self.iterkeys():
[62f851f]274            return self[fid].get_model()
[2f4b430]275
[3e3ab46]276    def set_fit_tab_caption(self, caption):
277        """
278        store the caption of the page associated with object
279        """
280        self.fit_tab_caption = caption
[2f4b430]281
[3e3ab46]282    def get_fit_tab_caption(self):
283        """
284        Return the caption of the page associated with object
285        """
286        return self.fit_tab_caption
[2f4b430]287
[62f851f]288    def set_residuals(self, residuals, fid):
[f32d144]289        """
[62f851f]290        save a copy of residual
291        :param data: data selected
292        """
293        if fid in self.iterkeys():
294            self[fid].set_residuals(residuals)
[2f4b430]295
[62f851f]296    def get_residuals(self, fid):
297        """
298        :return: residuals
299        """
300        if fid in self.iterkeys():
301            return self[fid].get_residuals()
[2f4b430]302
[3e3ab46]303    def set_theory_data(self, fid, data=None):
[f32d144]304        """
[3e3ab46]305        save a copy of the data select to fit
306        :param data: data selected
307        """
308        if fid in self.iterkeys():
309            self[fid].set_theory_data(data)
[2f4b430]310
[3e3ab46]311    def get_theory_data(self, fid):
312        """
313        :return: list of data dList
314        """
315        if fid in self.iterkeys():
316            return self[fid].get_theory_data()
[2f4b430]317
[3e3ab46]318    def add_data(self, data):
319        """
320        Add data to the current dictionary of fitproblem. if data id does not
321        exist create a new fit problem.
322        :note: only data changes in the fit problem
323        """
324        if data.id not in self.iterkeys():
325            self[data.id] = FitProblem()
326        self[data.id].set_fit_data(data)
[2f4b430]327
[3e3ab46]328    def set_fit_data(self, data):
[f32d144]329        """
[3e3ab46]330        save a copy of the data select to fit
331        :param data: data selected
[2f4b430]332
[3e3ab46]333        """
334        self.clear()
335        if data is None:
336            data = []
337        for d in data:
338            if (d is not None):
339                if (d.id not in self.iterkeys()):
340                    self[d.id] = FitProblem()
341                self[d.id].set_fit_data(d)
342                self[d.id].set_model(self.model)
343                self[d.id].set_range(self.qmin, self.qmax)
[2f4b430]344
[3e3ab46]345    def get_fit_data(self, fid):
346        """
347        return data for the given fitproblem id
[ac7be54]348        :param fid: key representing a fitproblem, usually extract from data id
[3e3ab46]349        """
350        if fid in self.iterkeys():
351            return self[fid].get_fit_data()
[2f4b430]352
[3e3ab46]353    def set_model_param(self, name, value=None, fid=None):
[f32d144]354        """
[3e3ab46]355        Store the name and value of a parameter of this fitproblem's model
356        :param name: name of the given parameter
357        :param value: value of that parameter
358        """
359        if fid is None:
360            for value in self.itervalues():
361                value.set_model_param(name, value)
362        else:
363            if fid in self.iterkeys():
364                self[fid].set_model_param(name, value)
[2f4b430]365
[3e3ab46]366    def get_model_param(self, fid):
[f32d144]367        """
[3e3ab46]368        return list of couple of parameter name and value
369        """
370        if fid in self.iterkeys():
371            return self[fid].get_model_param()
[2f4b430]372
[1b14795]373    def set_param2fit(self, list):
374        """
375        Store param names to fit (checked)
376        :param list: list of the param names
377        """
378        self.list_param2fit = list
[2f4b430]379
[1b14795]380    def get_param2fit(self):
381        """
382        return the list param names to fit
[f32d144]383        """
[1b14795]384        return self.list_param2fit
[2f4b430]385
[3e3ab46]386    def schedule_tofit(self, schedule=0):
387        """
388        set schedule to true to decide if this fit  must be performed
389        """
390        self.scheduled = schedule
391        for value in self.itervalues():
392            value.schedule_tofit(schedule)
[2f4b430]393
[3e3ab46]394    def get_scheduled(self):
395        """
396        return true or false if a problem as being schedule for fitting
397        """
398        return self.scheduled
[2f4b430]399
[3e3ab46]400    def set_range(self, qmin=None, qmax=None, fid=None):
401        """
[f32d144]402        set fitting range
[3e3ab46]403        """
404        self.qmin = qmin
405        self.qmax = qmax
406        if fid is None:
407            for value in self.itervalues():
408                value.set_range(self.qmin, self.qmax)
409        else:
410            if fid in self.iterkeys():
411                self[fid].value.set_range(self.qmin, self.qmax)
[2f4b430]412
[3e3ab46]413    def get_range(self, fid):
414        """
415        :return: fitting range
416        """
417        if fid in self.iterkeys():
418            return self[fid].get_range()
[2f4b430]419
[f32d144]420    def set_weight(self, is2d, flag=None, fid=None):
[55bb249c]421        """
422        fit weight
423        """
424        if fid is None:
425            for value in self.itervalues():
[f7ef313]426                value.set_weight(flag=flag, is2d=is2d)
[55bb249c]427        else:
428            if fid in self.iterkeys():
[f7ef313]429                self[fid].set_weight(flag=flag, is2d=is2d)
[2f4b430]430
[55bb249c]431    def get_weight(self, fid=None):
432        """
433        return fit weight
434        """
435        if fid in self.iterkeys():
436            return self[fid].get_weight()
[2f4b430]437
[3e3ab46]438    def clear_model_param(self, fid=None):
439        """
440        clear constraint info
441        """
442        if fid is None:
443            for value in self.itervalues():
444                value.clear_model_param()
445        else:
446            if fid in self.iterkeys():
447                self[fid].clear_model_param()
[2f4b430]448
[3e3ab46]449    def get_fit_problem(self):
450        """
451        return fitproblem contained in this dictionary
452        """
453        return self.itervalues()
[2f4b430]454
[5bf0331]455    def set_result(self, result, fid):
[41661a0]456        """
457        """
458        if fid in self.iterkeys():
459            self[fid].set_result(result)
[2f4b430]460
[41661a0]461    def set_batch_result(self, batch_inputs, batch_outputs):
[3e3ab46]462        """
463        set a list of result
464        """
[f64a4b7]465        self.batch_inputs = batch_inputs
466        self.batch_outputs = batch_outputs
[2f4b430]467
[41661a0]468    def get_result(self, fid):
469        """
[f32d144]470        get result
471        """
[41661a0]472        if fid in self.iterkeys():
473            return self[fid].get_result()
[2f4b430]474
[41661a0]475    def get_batch_result(self):
[3e3ab46]476        """
[f32d144]477        get result
[3e3ab46]478        """
[f64a4b7]479        return self.batch_inputs, self.batch_outputs
[2f4b430]480
[5e48acb]481    def set_graph_id(self, id):
482        """
[2f4b430]483        Set graph id (from data_group_id at the time the graph produced)
[5e48acb]484        """
485        self.graph_id = id
[2f4b430]486
[f32d144]487    def get_graph_id(self):
[5e48acb]488        """
489        Get graph_id
[f32d144]490        """
[5e48acb]491        return self.graph_id
[2f4b430]492
493
[3e3ab46]494class FitProblem(FitProblemComponent):
[f32d144]495    """
[5062bbf]496    FitProblem class allows to link a model with the new name created in _on_model,
497    a name theory created with that model  and the data fitted with the model.
498    FitProblem is mostly used  as value of the dictionary by fitting module.
[d89f09b]499    """
500    def __init__(self):
[3e3ab46]501        FitProblemComponent.__init__(self)
[d89f09b]502        """
[5062bbf]503        contains information about data and model to fit
[d89f09b]504        """
[925a30e]505        ## data used for fitting
[6bbeacd4]506        self.fit_data = None
507        self.theory_data = None
[62f851f]508        self.residuals = None
[05325ec4]509        # original data: should not be modified
510        self.original_data = None
[2140e68]511        ## the current model
512        self.model = None
[f32d144]513        ## if 1 this fit problem will be selected to fit , if 0
[925a30e]514        ## it will not be selected for fit
[6bbeacd4]515        self.schedule = 0
[925a30e]516        ##list containing parameter name and value
[6bbeacd4]517        self.list_param = []
[925a30e]518        ## smear object to smear or not data1D
[7afcae8]519        self.smearer_computed = False
[3e3ab46]520        self.smearer_enable = False
521        self.smearer_computer_value = None
[2140e68]522        ## fitting range
523        self.qmin = None
524        self.qmax = None
[55bb249c]525        # fit weight
526        self.weight = None
[a3c8e8f]527        self.result = None
[2f4b430]528
[3e3ab46]529    def enable_smearing(self, flag=False):
[9853ad0]530        """
[3e3ab46]531        :param flag: bool.When flag is 1 get the computer smear value. When
[ac7be54]532            flag is 0 ingore smear value.
[9853ad0]533        """
[3e3ab46]534        self.smearer_enable = flag
[2f4b430]535
[08b9c6c8]536    def set_smearer(self, smearer):
[925a30e]537        """
[5062bbf]538        save reference of  smear object on fitdata
[2f4b430]539
[5062bbf]540        :param smear: smear object from DataLoader
[2f4b430]541
[925a30e]542        """
[3e3ab46]543        self.smearer_computer_value = smearer
[2f4b430]544
[08b9c6c8]545    def get_smearer(self):
[925a30e]546        """
[5062bbf]547        return smear object
[925a30e]548        """
[3e3ab46]549        if not self.smearer_enable:
550            return None
[7afcae8]551        if not self.smearer_computed:
[3e3ab46]552            #smeari_selection should be call only once per fitproblem
[7afcae8]553            self.smearer_computer_value = smear_selection(self.fit_data,
[3e3ab46]554                                                           self.model)
[7afcae8]555            self.smearer_computed = True
[3e3ab46]556        return self.smearer_computer_value
[2f4b430]557
[5062bbf]558    def save_model_name(self, name):
559        """
[f32d144]560        """
561        self.name_per_page = name
[2f4b430]562
[bb18ef1]563    def get_name(self):
[5062bbf]564        """
565        """
[bb18ef1]566        return self.name_per_page
[2f4b430]567
[8aa5788]568    def set_model(self, model):
[f32d144]569        """
[5062bbf]570        associates each model with its new created name
571        :param model: model selected
572        :param name: name created for model
[d89f09b]573        """
[7afcae8]574        self.model = model
575        self.smearer_computer_value = smear_selection(self.fit_data,
576                                                           self.model)
577        self.smearer_computed = True
[2f4b430]578
[2140e68]579    def get_model(self):
[5062bbf]580        """
581        :return: saved model
582        """
[2140e68]583        return self.model
[2f4b430]584
[62f851f]585    def set_residuals(self, residuals):
[f32d144]586        """
[62f851f]587        save a copy of residual
588        :param data: data selected
589        """
590        self.residuals = residuals
[2f4b430]591
[62f851f]592    def get_residuals(self):
593        """
594        :return: residuals
595        """
596        return self.residuals
[2f4b430]597
[6bbeacd4]598    def set_theory_data(self, data):
[f32d144]599        """
[5062bbf]600        save a copy of the data select to fit
[2f4b430]601
[5062bbf]602        :param data: data selected
[2f4b430]603
[d89f09b]604        """
[e88ebfd]605        self.theory_data = copy.deepcopy(data)
[2f4b430]606
[6bbeacd4]607    def get_theory_data(self):
[5062bbf]608        """
[3e3ab46]609        :return: theory generated with the current model and data of this class
[5062bbf]610        """
[6bbeacd4]611        return self.theory_data
[5062bbf]612
[3e3ab46]613    def set_fit_data(self, data):
[f32d144]614        """
[3e3ab46]615        Store data associated with this class
616        :param data: list of data selected
[2a8fac1]617        """
[3fb5e68]618        self.original_data = None
619        self.fit_data = None
[05325ec4]620        # original data: should not be modified
[7db52f1]621        self.original_data = data
[05325ec4]622        # fit data: used for fit and can be modified for convenience
[55bb249c]623        self.fit_data = copy.deepcopy(data)
[7afcae8]624        self.smearer_computer_value = smear_selection(self.fit_data,
625                                                           self.model)
626        self.smearer_computed = True
[a3c8e8f]627        self.result = None
[2f4b430]628
[2a8fac1]629    def get_fit_data(self):
[5062bbf]630        """
[3e3ab46]631        :return: data associate with this class
[5062bbf]632        """
[2a8fac1]633        return self.fit_data
[2f4b430]634
[7db52f1]635    def get_origin_data(self):
636        """
637        """
638        return self.original_data
[2f4b430]639
[f7ef313]640    def set_weight(self, is2d, flag=None):
[55bb249c]641        """
[f7ef313]642        Received flag and compute error on data.
643        :param flag: flag to transform error of data.
644        :param is2d: flag to distinguish 1D to 2D Data
[55bb249c]645        """
[d85c194]646        from sas.sasgui.perspectives.fitting.utils import get_weight
[05325ec4]647        # send original data for weighting
648        self.weight = get_weight(data=self.original_data, is2d=is2d, flag=flag)
[55bb249c]649        if is2d:
650            self.fit_data.err_data = self.weight
651        else:
652            self.fit_data.dy = self.weight
653
654    def get_weight(self):
655        """
656        returns weight array
657        """
658        return self.weight
[2f4b430]659
[1b14795]660    def set_param2fit(self, list):
661        """
662        Store param names to fit (checked)
663        :param list: list of the param names
664        """
665        self.list_param2fit = list
[2f4b430]666
[1b14795]667    def get_param2fit(self):
668        """
669        return the list param names to fit
[f32d144]670        """
[1b14795]671        return self.list_param2fit
[2f4b430]672
[f32d144]673    def set_model_param(self, name, value=None):
674        """
[5062bbf]675        Store the name and value of a parameter of this fitproblem's model
676        :param name: name of the given parameter
677        :param value: value of that parameter
[d89f09b]678        """
[f32d144]679        self.list_param.append([name, value])
[2f4b430]680
[00561739]681    def get_model_param(self):
[f32d144]682        """
[5062bbf]683        return list of couple of parameter name and value
[00561739]684        """
[8e81af0]685        return self.list_param
[2f4b430]686
[948add7]687    def schedule_tofit(self, schedule=0):
[3b19ac9]688        """
[5062bbf]689        set schedule to true to decide if this fit  must be performed
[3b19ac9]690        """
[3e3ab46]691        self.schedule = schedule
[2f4b430]692
[3b19ac9]693    def get_scheduled(self):
[5062bbf]694        """
695        return true or false if a problem as being schedule for fitting
696        """
[3b19ac9]697        return self.schedule
[2f4b430]698
[2140e68]699    def set_range(self, qmin=None, qmax=None):
700        """
[3e3ab46]701        set fitting range
702        :param qmin: minimum value to consider for the fit range
703        :param qmax: maximum value to consider for the fit range
[2140e68]704        """
705        self.qmin = qmin
706        self.qmax = qmax
[2f4b430]707
[2140e68]708    def get_range(self):
709        """
[5062bbf]710        :return: fitting range
[2f4b430]711
[2140e68]712        """
713        return self.qmin, self.qmax
[2f4b430]714
[9e27de9]715    def clear_model_param(self):
716        """
717        clear constraint info
718        """
[3e3ab46]719        self.list_param = []
[2f4b430]720
[6bbeacd4]721    def set_fit_tab_caption(self, caption):
722        """
723        """
724        self.fit_tab_caption = str(caption)
[2f4b430]725
[6bbeacd4]726    def get_fit_tab_caption(self):
727        """
728        """
729        return self.fit_tab_caption
[2f4b430]730
[5e48acb]731    def set_graph_id(self, id):
732        """
[f32d144]733        Set graph id (from data_group_id at the time the graph produced)
[5e48acb]734        """
735        self.graph_id = id
[2f4b430]736
[f32d144]737    def get_graph_id(self):
[5e48acb]738        """
739        Get graph_id
[f32d144]740        """
[5e48acb]741        return self.graph_id
[2f4b430]742
[41661a0]743    def set_result(self, result):
744        """
745        """
746        self.result = result
[2f4b430]747
[41661a0]748    def get_result(self):
749        """
[f32d144]750        get result
751        """
752        return self.result
Note: See TracBrowser for help on using the repository browser.