source: sasview/src/sas/perspectives/fitting/pagestate.py @ 5e880fe1

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 5e880fe1 was acf8e4a5, checked in by Paul Kienzle <pkienzle@…>, 10 years ago

reference BumpsFit? directly and remove fit engine selection layer

  • Property mode set to 100644
File size: 70.0 KB
RevLine 
[f32d144]1"""
2    Class that holds a fit page state
3"""
[b1e609c]4#TODO: Refactor code so we don't need to use getattr/setattr
[5062bbf]5################################################################################
6#This software was developed by the University of Tennessee as part of the
7#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
[f32d144]8#project funded by the US National Science Foundation.
[5062bbf]9#
10#See the license text in license.txt
11#
12#copyright 2009, University of Tennessee
13################################################################################
[11a7e11]14import time
15import os
16import sys
[6f023e8]17import copy
[11a7e11]18import logging
[df7ed14]19import numpy
[eddb6ec]20import string
[c77d859]21
[35b556d]22import xml.dom.minidom
[ac5b69d]23from xml.dom.minidom import parseString
[11a7e11]24from lxml import etree
25
[79492222]26import sas.dataloader
27from sas.dataloader.readers.cansas_reader import Reader as CansasReader
28from sas.dataloader.readers.cansas_reader import get_content, write_node
29from sas.dataloader.data_info import Data2D
30from sas.dataloader.data_info import Collimation
31from sas.dataloader.data_info import Detector
32from sas.dataloader.data_info import Process
33from sas.dataloader.data_info import Aperture
[11a7e11]34#Information to read/write state as xml
[61cada5]35FITTING_NODE_NAME = 'fitting_plug_in'
36CANSAS_NS = "cansas1d/1.0"
37
[b1e609c]38LIST_OF_DATA_ATTRIBUTES = [["is_data", "is_data", "bool"],
39                           ["group_id", "data_group_id", "string"],
40                           ["data_name", "data_name", "string"],
41                           ["data_id", "data_id", "string"],
42                           ["name", "name", "string"],
43                           ["data_name", "data_name", "string"]]
[acf8e4a5]44LIST_OF_STATE_ATTRIBUTES = [["qmin", "qmin", "float"],
[b1e609c]45                            ["qmax", "qmax", "float"],
46                            ["npts", "npts", "float"],
47                            ["categorycombobox", "categorycombobox", "string"],
48                            ["formfactorcombobox", "formfactorcombobox", "string"],
49                            ["structurecombobox", "structurecombobox", "string"],
50                            ["multi_factor", "multi_factor", "float"],
51                            ["magnetic_on", "magnetic_on", "bool"],
52                            ["enable_smearer", "enable_smearer", "bool"],
53                            ["disable_smearer", "disable_smearer", "bool"],
54                            ["pinhole_smearer", "pinhole_smearer", "bool"],
55                            ["slit_smearer", "slit_smearer", "bool"],
56                            ["enable_disp", "enable_disp", "bool"],
57                            ["disable_disp", "disable_disp", "bool"],
58                            ["dI_noweight", "dI_noweight", "bool"],
59                            ["dI_didata", "dI_didata", "bool"],
60                            ["dI_sqrdata", "dI_sqrdata", "bool"],
61                            ["dI_idata", "dI_idata", "bool"],
62                            ["enable2D", "enable2D", "bool"],
63                            ["cb1", "cb1", "bool"],
64                            ["tcChi", "tcChi", "float"],
65                            ["smearer", "smearer", "float"],
66                            ["smear_type", "smear_type", "string"],
67                            ["dq_l", "dq_l", "string"],
68                            ["dq_r", "dq_r", "string"],
69                            ["dx_max", "dx_max", "float"],
70                            ["dx_min", "dx_min", "float"],
71                            ["dxl", "dxl", "float"],
72                            ["dxw", "dxw", "float"]]
73
74LIST_OF_MODEL_ATTRIBUTES = [["values", "values"],
[11a7e11]75                            ["weights", "weights"]]
76
[b1e609c]77DISPERSION_LIST = [["disp_obj_dict", "_disp_obj_dict", "string"]]
[2296316]78
[b1e609c]79LIST_OF_STATE_PARAMETERS = [["parameters", "parameters"],
[f32d144]80                            ["str_parameters", "str_parameters"],
[61cada5]81                            ["orientation_parameters", "orientation_params"],
82                            ["dispersity_parameters", "orientation_params_disp"],
[f32d144]83                            ["fixed_param", "fixed_param"],
84                            ["fittable_param", "fittable_param"]]
[b1e609c]85LIST_OF_DATA_2D_ATTR = [["xmin", "xmin", "float"],
[f32d144]86                        ["xmax", "xmax", "float"],
87                        ["ymin", "ymin", "float"],
88                        ["ymax", "ymax", "float"],
89                        ["_xaxis", "_xaxis", "string"],
[df7ed14]90                        ["_xunit", "_xunit", "string"],
[f32d144]91                        ["_yaxis", "_yaxis", "string"],
92                        ["_yunit", "_yunit", "string"],
93                        ["_zaxis", "_zaxis", "string"],
94                        ["_zunit", "_zunit", "string"]]
[b1e609c]95LIST_OF_DATA_2D_VALUES = [["qx_data", "qx_data", "float"],
96                          ["qy_data", "qy_data", "float"],
97                          ["dqx_data", "dqx_data", "float"],
98                          ["dqy_data", "dqy_data", "float"],
99                          ["data", "data", "float"],
100                          ["q_data", "q_data", "float"],
101                          ["err_data", "err_data", "float"],
102                          ["mask", "mask", "bool"]]
[61cada5]103
[f32d144]104
105def parse_entry_helper(node, item):
[0b12abb5]106    """
107    Create a numpy list from value extrated from the node
[2f4b430]108
[0b12abb5]109    :param node: node from each the value is stored
110    :param item: list name of three strings.the two first are name of data
[f32d144]111        attribute and the third one is the type of the value of that
[0b12abb5]112        attribute. type can be string, float, bool, etc.
[2f4b430]113
[0b12abb5]114    : return: numpy array
115    """
116    if node is not None:
117        if item[2] == "string":
118            return str(node.get(item[0]).strip())
119        elif item[2] == "bool":
120            try:
[e3d1423]121                return node.get(item[0]).strip() == "True"
[2f4b430]122
[0b12abb5]123            except:
124                return None
125        else:
126            try:
127                return float(node.get(item[0]))
128            except:
129                return None
[2f4b430]130
131
[cfc0913]132class PageState(object):
[c77d859]133    """
[5062bbf]134    Contains information to reconstruct a page of the fitpanel.
[c77d859]135    """
[61cada5]136    def __init__(self, parent=None, model=None, data=None):
[f32d144]137        """
[5062bbf]138        Initialize the current state
[2f4b430]139
[5062bbf]140        :param model: a selected model within a page
[f32d144]141        :param data:
[2f4b430]142
[c77d859]143        """
[61cada5]144        self.file = None
[11a7e11]145        #Time of state creation
146        self.timestamp = time.time()
[c77d859]147        ## Data member to store the dispersion object created
148        self._disp_obj_dict = {}
[61cada5]149        #------------------------
[f32d144]150        #Data used for fitting
[c77d859]151        self.data = data
[2296316]152        # model data
153        self.theory_data = None
154        #Is 2D
155        self.is_2D = False
156        self.images = None
[2f4b430]157
[61cada5]158        #save additional information on data that dataloader.reader does not read
159        self.is_data = None
160        self.data_name = ""
[c0ff8cc]161
[61cada5]162        if self.data is not None:
163            self.data_name = self.data.name
164        self.data_id = None
165        if self.data is not None and hasattr(self.data, "id"):
166            self.data_id = self.data.id
167        self.data_group_id = None
168        if self.data is not None and hasattr(self.data, "group_id"):
169            self.data_group_id = self.data.group_id
[2f4b430]170
[61cada5]171        ## reset True change the state of exsiting button
172        self.reset = False
[2f4b430]173
[c77d859]174        # flag to allow data2D plot
[cfc0913]175        self.enable2D = False
[c77d859]176        # model on which the fit would be performed
177        self.model = model
[93f0a862]178        self.m_name = None
[dce84c0]179        #list of process done to model
180        self.process = []
[f32d144]181        #fit page manager
[c77d859]182        self.manager = None
183        #Store the parent of this panel parent
184        # For this application fitpanel is the parent
[f32d144]185        self.parent = parent
[c77d859]186        # Event_owner is the owner of model event
187        self.event_owner = None
[c9a4377]188        ##page name
[cfc0913]189        self.page_name = ""
[eddb6ec]190        # Contains link between model, all its parameters, and panel organization
[61cada5]191        self.parameters = []
[fb59ed9]192        # String parameter list that can not be fitted
193        self.str_parameters = []
[f32d144]194        # Contains list of parameters that cannot be fitted and reference to
195        #panel objects
[61cada5]196        self.fixed_param = []
[f32d144]197        # Contains list of parameters with dispersity and reference to
198        #panel objects
[61cada5]199        self.fittable_param = []
[60132ef]200        ## orientation parameters
[61cada5]201        self.orientation_params = []
[eddb6ec]202        ## orientation parameters for gaussian dispersity
[61cada5]203        self.orientation_params_disp = []
[3370922]204        ## smearer info
[61cada5]205        self.smearer = None
[7609f1a]206        self.smear_type = None
207        self.dq_l = None
208        self.dq_r = None
[db8fd5b]209        self.dx_max = None
210        self.dx_min = None
211        self.dxl = None
212        self.dxw = None
[eddb6ec]213        #list of dispersion parameters
[f32d144]214        self.disp_list = []
[61cada5]215        if self.model is not None:
[71f0373]216            self.disp_list = self.model.getDispParamList()
[2296316]217
[61cada5]218        self.disp_cb_dict = {}
[2296316]219        self.values = {}
220        self.weights = {}
[2f4b430]221
[f32d144]222        #contains link between a model and selected parameters to fit
[61cada5]223        self.param_toFit = []
[a074145]224        ##dictionary of model type and model class
[cfc0913]225        self.model_list_box = None
[a074145]226        ## save the state of the context menu
[61cada5]227        self.saved_states = {}
[240b9966]228        ## save selection of combobox
[3b9e023]229        self.formfactorcombobox = None
[ea5fa58]230        self.categorycombobox = None
[f32d144]231        self.structurecombobox = None
[c0ff8cc]232
[240b9966]233        ## radio box to select type of model
[ea5fa58]234        #self.shape_rbutton = False
235        #self.shape_indep_rbutton = False
236        #self.struct_rbutton = False
237        #self.plugin_rbutton = False
[b787e68c]238        ## the indice of the current selection
239        self.disp_box = 0
[c77d859]240        ## Qrange
[cfc0913]241        ## Q range
[61cada5]242        self.qmin = 0.001
243        self.qmax = 0.1
[0b12abb5]244        #reset data range
245        self.qmax_x = None
246        self.qmin_x = None
[2f4b430]247
[cfc0913]248        self.npts = None
[61cada5]249        self.name = ""
[4523b68]250        self.multi_factor = None
[318b5bbb]251        self.magnetic_on = False
[cfc0913]252        ## enable smearering state
253        self.enable_smearer = False
[fc6ea43]254        self.disable_smearer = True
[7609f1a]255        self.pinhole_smearer = False
[f32d144]256        self.slit_smearer = False
[55bb249c]257        # weighting options
258        self.dI_noweight = False
259        self.dI_didata = True
260        self.dI_sqrdata = False
[f32d144]261        self.dI_idata = False
[cfc0913]262        ## disperity selection
[61cada5]263        self.enable_disp = False
264        self.disable_disp = True
[2f4b430]265
[cfc0913]266        ## state of selected all check button
267        self.cb1 = False
[0aeabc6]268        ## store value of chisqr
[61cada5]269        self.tcChi = None
[2f4b430]270
[6f023e8]271    def clone(self):
[61cada5]272        """
[5062bbf]273        Create a new copy of the current object
[61cada5]274        """
275        model = None
276        if self.model is not None:
[6f023e8]277            model = self.model.clone()
[bb70474]278            model.name = self.model.name
[61cada5]279        obj = PageState(self.parent, model=model)
280        obj.file = copy.deepcopy(self.file)
[6f023e8]281        obj.data = copy.deepcopy(self.data)
[61cada5]282        if self.data is not None:
283            self.data_name = self.data.name
284        obj.data_name = self.data_name
285        obj.is_data = self.is_data
[dcf29d7]286        obj.model_list_box = copy.deepcopy(self.model_list_box)
[2f4b430]287
[ea5fa58]288        obj.categorycombobox = self.categorycombobox
[61cada5]289        obj.formfactorcombobox = self.formfactorcombobox
[f32d144]290        obj.structurecombobox = self.structurecombobox
[2f4b430]291
[ea5fa58]292        #obj.shape_rbutton = self.shape_rbutton
293        #obj.shape_indep_rbutton = self.shape_indep_rbutton
294        #obj.struct_rbutton = self.struct_rbutton
295        #obj.plugin_rbutton = self.plugin_rbutton
[2f4b430]296
[dcf29d7]297        obj.manager = self.manager
298        obj.event_owner = self.event_owner
[71f0373]299        obj.disp_list = copy.deepcopy(self.disp_list)
[2f4b430]300
[c477b31]301        obj.enable2D = copy.deepcopy(self.enable2D)
[cfc0913]302        obj.parameters = copy.deepcopy(self.parameters)
[fb59ed9]303        obj.str_parameters = copy.deepcopy(self.str_parameters)
[cfc0913]304        obj.fixed_param = copy.deepcopy(self.fixed_param)
305        obj.fittable_param = copy.deepcopy(self.fittable_param)
[f32d144]306        obj.orientation_params = copy.deepcopy(self.orientation_params)
307        obj.orientation_params_disp = copy.deepcopy(self.orientation_params_disp)
[b787e68c]308        obj.enable_disp = copy.deepcopy(self.enable_disp)
[fc6ea43]309        obj.disable_disp = copy.deepcopy(self.disable_disp)
[0aeabc6]310        obj.tcChi = self.tcChi
[2f4b430]311
[f32d144]312        if len(self._disp_obj_dict) > 0:
313            for k, v in self._disp_obj_dict.iteritems():
314                obj._disp_obj_dict[k] = v
315        if len(self.disp_cb_dict) > 0:
316            for k, v in self.disp_cb_dict.iteritems():
317                obj.disp_cb_dict[k] = v
318        if len(self.values) > 0:
319            for k, v in self.values.iteritems():
[2296316]320                obj.values[k] = v
[f32d144]321        if len(self.weights) > 0:
322            for k, v in self.weights.iteritems():
[2296316]323                obj.weights[k] = v
[b787e68c]324        obj.enable_smearer = copy.deepcopy(self.enable_smearer)
[fc6ea43]325        obj.disable_smearer = copy.deepcopy(self.disable_smearer)
[7609f1a]326        obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
327        obj.slit_smearer = copy.deepcopy(self.slit_smearer)
328        obj.smear_type = copy.deepcopy(self.smear_type)
[55bb249c]329        obj.dI_noweight = copy.deepcopy(self.dI_noweight)
330        obj.dI_didata = copy.deepcopy(self.dI_didata)
331        obj.dI_sqrdata = copy.deepcopy(self.dI_sqrdata)
332        obj.dI_idata = copy.deepcopy(self.dI_idata)
[7609f1a]333        obj.dq_l = copy.deepcopy(self.dq_l)
334        obj.dq_r = copy.deepcopy(self.dq_r)
[db8fd5b]335        obj.dx_max = copy.deepcopy(self.dx_max)
336        obj.dx_min = copy.deepcopy(self.dx_min)
337        obj.dxl = copy.deepcopy(self.dxl)
[2f4b430]338        obj.dxw = copy.deepcopy(self.dxw)
[b787e68c]339        obj.disp_box = copy.deepcopy(self.disp_box)
340        obj.qmin = copy.deepcopy(self.qmin)
341        obj.qmax = copy.deepcopy(self.qmax)
[c0ff8cc]342        obj.multi_factor = self.multi_factor
[318b5bbb]343        obj.magnetic_on = self.magnetic_on
[f32d144]344        obj.npts = copy.deepcopy(self.npts)
[b787e68c]345        obj.cb1 = copy.deepcopy(self.cb1)
[3370922]346        obj.smearer = copy.deepcopy(self.smearer)
[2f4b430]347
[a074145]348        for name, state in self.saved_states.iteritems():
349            copy_name = copy.deepcopy(name)
350            copy_state = state.clone()
[f32d144]351            obj.saved_states[copy_name] = copy_state
[6f023e8]352        return obj
[2f4b430]353
[61cada5]354    def _repr_helper(self, list, rep):
355        """
[5062bbf]356        Helper method to print a state
[61cada5]357        """
358        for item in list:
[f32d144]359            rep += "parameter name: %s \n" % str(item[1])
360            rep += "value: %s\n" % str(item[2])
361            rep += "selected: %s\n" % str(item[0])
362            rep += "error displayed : %s \n" % str(item[4][0])
363            rep += "error value:%s \n" % str(item[4][1])
364            rep += "minimum displayed : %s \n" % str(item[5][0])
365            rep += "minimum value : %s \n" % str(item[5][1])
366            rep += "maximum displayed : %s \n" % str(item[6][0])
367            rep += "maximum value : %s \n" % str(item[6][1])
368            rep += "parameter unit: %s\n\n" % str(item[7])
[240b9966]369        return rep
[2f4b430]370
[61cada5]371    def __repr__(self):
[f32d144]372        """
[5062bbf]373        output string for printing
[11a7e11]374        """
[f32d144]375        rep = "\nState name: %s\n" % self.file
[11a7e11]376        t = time.localtime(self.timestamp)
[deff488]377        time_str = time.strftime("%b %d %Y %H;%M;%S ", t)
[c0ff8cc]378
[f32d144]379        rep += "State created: %s\n" % time_str
380        rep += "State form factor combobox selection: %s\n" % self.formfactorcombobox
381        rep += "State structure factor combobox selection: %s\n" % self.structurecombobox
382        rep += "is data : %s\n" % self.is_data
383        rep += "data's name : %s\n" % self.data_name
384        rep += "data's id : %s\n" % self.data_id
[74dc0a4]385        if self.model != None:
[93f0a862]386            m_name = self.model.__class__.__name__
387            if m_name == 'Model':
388                m_name = self.m_name
[f32d144]389            rep += "model name : %s\n" % m_name
[74dc0a4]390        else:
391            rep += "model name : None\n"
[f32d144]392        rep += "multi_factor : %s\n" % str(self.multi_factor)
[2f4b430]393        rep += "magnetic_on : %s\n" % str(self.magnetic_on)
[ea5fa58]394        rep += "model type (Category) selected: %s\n" % self.categorycombobox
[f32d144]395        rep += "data : %s\n" % str(self.data)
396        rep += "Plotting Range: min: %s, max: %s, steps: %s\n" % (str(self.qmin),
[b1e609c]397                                                                  str(self.qmax), str(self.npts))
[f32d144]398        rep += "Dispersion selection : %s\n" % str(self.disp_box)
399        rep += "Smearing enable : %s\n" % str(self.enable_smearer)
400        rep += "Smearing disable : %s\n" % str(self.disable_smearer)
401        rep += "Pinhole smearer enable : %s\n" % str(self.pinhole_smearer)
402        rep += "Slit smearer enable : %s\n" % str(self.slit_smearer)
403        rep += "Dispersity enable : %s\n" % str(self.enable_disp)
404        rep += "Dispersity disable : %s\n" % str(self.disable_disp)
405        rep += "Slit smearer enable: %s\n" % str(self.slit_smearer)
[2f4b430]406
[f32d144]407        rep += "dI_noweight : %s\n" % str(self.dI_noweight)
408        rep += "dI_didata : %s\n" % str(self.dI_didata)
409        rep += "dI_sqrdata : %s\n" % str(self.dI_sqrdata)
410        rep += "dI_idata : %s\n" % str(self.dI_idata)
[2f4b430]411
[f32d144]412        rep += "2D enable : %s\n" % str(self.enable2D)
413        rep += "All parameters checkbox selected: %s\n" % (self.cb1)
414        rep += "Value of Chisqr : %s\n" % str(self.tcChi)
415        rep += "Smear object : %s\n" % str(self.smearer)
416        rep += "Smear type : %s\n" % (self.smear_type)
417        rep += "dq_l  : %s\n" % self.dq_l
418        rep += "dq_r  : %s\n" % self.dq_r
[db8fd5b]419        rep += "dx_max  : %s\n" % str(self.dx_max)
[2f4b430]420        rep += "dx_min : %s\n" % str(self.dx_min)
[db8fd5b]421        rep += "dxl  : %s\n" % str(self.dxl)
[2f4b430]422        rep += "dxw : %s\n" % str(self.dxw)
[f32d144]423        rep += "model  : %s\n\n" % str(self.model)
[2296316]424        temp_parameters = []
425        temp_fittable_param = []
426        if self.data.__class__.__name__ == "Data2D":
427            self.is_2D = True
428        else:
429            self.is_2D = False
430        if self.data is not None:
431            if not self.is_2D:
432                for item in self.parameters:
433                    if not item in self.orientation_params:
434                        temp_parameters.append(item)
435                for item in self.fittable_param:
436                    if not item in self.orientation_params_disp:
437                        temp_fittable_param.append(item)
438            else:
439                temp_parameters = self.parameters
440                temp_fittable_param = self.fittable_param
[2f4b430]441
[f32d144]442            rep += "number parameters(self.parameters): %s\n" % len(temp_parameters)
443            rep = self._repr_helper(list=temp_parameters, rep=rep)
444            rep += "number str_parameters(self.str_parameters): %s\n" % len(self.str_parameters)
445            rep = self._repr_helper(list=self.str_parameters, rep=rep)
446            rep += "number fittable_param(self.fittable_param): %s\n" % len(temp_fittable_param)
447            rep = self._repr_helper(list=temp_fittable_param, rep=rep)
[61cada5]448        return rep
[2296316]449
450    def set_report_string(self):
451        """
[f32d144]452        Get the values (strings) from __str__ for report
[2296316]453        """
[d06ae30]454        # Dictionary of the report strings
[2296316]455        repo_time = ""
456        model_name = ""
457        title = ""
458        title_name = ""
459        file_name = ""
460        param_string = ""
461        paramval_string = ""
462        chi2_string = ""
463        q_range = ""
464        strings = self.__repr__()
465        lines = strings.split('\n')
466
467        # get all string values from __str__()
468        for line in lines:
469            value = ""
470            content = line.split(":")
471            name = content[0]
472            try:
473                value = content[1]
474            except:
[b1e609c]475                logging.error(sys.exc_value)
[b7c6a4a]476            if name.count("State created"):
477                repo_time = "" + value
[2296316]478            if name.count("parameter name"):
479                val_name = value.split(".")
480                if len(val_name) > 1:
481                    if val_name[1].count("width"):
482                        param_string += value + ','
483                    else:
484                        continue
485                else:
486                    param_string += value + ','
487            if name == "value":
488                param_string += value + ','
[b1e609c]489            if name == "selected":
490                if value == u' False':
491                    fixed_parameter = True
492                else:
493                    fixed_parameter = False
[2296316]494            if name == "error value":
[b1e609c]495                if fixed_parameter:
496                    param_string += '(fixed),'
497                else:
[d06ae30]498                    param_string += value + ','
[2296316]499            if name == "parameter unit":
[f32d144]500                param_string += value + ':'
[2296316]501            if name == "Value of Chisqr ":
502                chi2 = ("Chi2/Npts = " + value)
503                chi2_string = CENTRE % chi2
504            if name == "Title":
505                if len(value.strip()) == 0:
506                    continue
507                title = value + " [" + repo_time + "]"
508                title_name = HEADER % title
509            if name == "data ":
510                try:
[b1e609c]511                    file_value = ("File name:" + content[2])
512                    file_name = CENTRE % file_value
[2296316]513                    if len(title) == 0:
514                        title = content[2] + " [" + repo_time + "]"
515                        title_name = HEADER % title
516                except:
[b1e609c]517                    logging.error(sys.exc_value)
[74dc0a4]518            if name == "model name ":
519                try:
520                    modelname = "Model name:" + content[1]
521                except:
522                    modelname = "Model name:" + " NAN"
[f32d144]523                model_name = CENTRE % modelname
[2f4b430]524
[2296316]525            if name == "Plotting Range":
526                try:
527                    q_range = content[1] + " = " + content[2] \
528                            + " = " + content[3].split(",")[0]
529                    q_name = ("Q Range:    " + q_range)
530                    q_range = CENTRE % q_name
531                except:
[b1e609c]532                    logging.error(sys.exc_value)
[2296316]533        paramval = ""
[f32d144]534        for lines in param_string.split(":"):
[2296316]535            line = lines.split(",")
[f32d144]536            if len(lines) > 0:
537                param = line[0]
[2296316]538                param += " = " + line[1]
539                if len(line[2].split()) > 0 and not line[2].count("None"):
540                    param += " +- " + line[2]
541                if len(line[3].split()) > 0 and not line[3].count("None"):
542                    param += " " + line[3]
543                if not paramval.count(param):
[f32d144]544                    paramval += param + "\n"
[2296316]545                    paramval_string += CENTRE % param + "\n"
[2f4b430]546
[f5bdb4a]547        text_string = "\n\n\n" + title + "\n\n" + file + \
[f32d144]548                      "\n" + q_name + \
549                      "\n" + chi2 + \
550                      "\n\n" + paramval
[2f4b430]551
[f5bdb4a]552        title_name = self._check_html_format(title_name)
553        file_name = self._check_html_format(file_name)
554        title = self._check_html_format(title)
[2f4b430]555
[2296316]556        html_string = title_name + "\n" + file_name + \
[f32d144]557                                   "\n" + model_name + \
[2296316]558                                   "\n" + q_range + \
559                                   "\n" + chi2_string + \
560                                   "\n" + ELINE + \
561                                   "\n" + paramval_string + \
562                                   "\n" + ELINE + \
563                                   "\n" + FEET_1 % title + \
[f32d144]564                                   "\n" + FEET_2
[2f4b430]565
[2296316]566        return html_string, text_string, title
[2f4b430]567
[f5bdb4a]568    def _check_html_format(self, name):
569        """
570        Check string '%' for html format
571        """
572        if name.count('%'):
573            name = name.replace('%', '&#37')
[2f4b430]574
[f5bdb4a]575        return name
[2f4b430]576
[2296316]577    def report(self, figs=None, canvases=None):
578        """
579        Invoke report dialog panel
[2f4b430]580
[2296316]581        : param figs: list of pylab figures [list]
582        """
[79492222]583        from sas.perspectives.fitting.report_dialog import ReportDialog
[2296316]584        # get the strings for report
585        html_str, text_str, title = self.set_report_string()
586        # Allow 2 figures to append
587        if len(figs) == 1:
[f32d144]588            add_str = FEET_3
[2296316]589        elif len(figs) == 2:
[f32d144]590            add_str = ELINE
591            add_str += FEET_2 % ("%s")
592            add_str += ELINE
593            add_str += FEET_3
[2296316]594        elif len(figs) > 2:
[f32d144]595            add_str = ELINE
596            add_str += FEET_2 % ("%s")
597            add_str += ELINE
598            add_str += FEET_2 % ("%s")
599            add_str += ELINE
600            add_str += FEET_3
[2296316]601        else:
602            add_str = ""
[c0ff8cc]603
[2296316]604        # final report html strings
605        report_str = html_str % ("%s") + add_str
606
607        # make plot image
608        images = self.set_plot_state(figs, canvases)
[f32d144]609        report_list = [report_str, text_str, images]
[2296316]610        dialog = ReportDialog(report_list, None, -1, "")
[d838715]611        dialog.Show()
[2f4b430]612
[eddb6ec]613    def _toXML_helper(self, thelist, element, newdoc):
[61cada5]614        """
[5062bbf]615        Helper method to create xml file for saving state
[61cada5]616        """
[eddb6ec]617        for item in thelist:
[61cada5]618            sub_element = newdoc.createElement('parameter')
619            sub_element.setAttribute('name', str(item[1]))
620            sub_element.setAttribute('value', str(item[2]))
621            sub_element.setAttribute('selected_to_fit', str(item[0]))
622            sub_element.setAttribute('error_displayed', str(item[4][0]))
623            sub_element.setAttribute('error_value', str(item[4][1]))
624            sub_element.setAttribute('minimum_displayed', str(item[5][0]))
625            sub_element.setAttribute('minimum_value', str(item[5][1]))
626            sub_element.setAttribute('maximum_displayed', str(item[6][0]))
627            sub_element.setAttribute('maximum_value', str(item[6][1]))
628            sub_element.setAttribute('unit', str(item[7]))
629            element.appendChild(sub_element)
[2f4b430]630
[61cada5]631    def toXML(self, file="fitting_state.fitv", doc=None, entry_node=None):
632        """
[5062bbf]633        Writes the state of the InversionControl panel to file, as XML.
[2f4b430]634
[5062bbf]635        Compatible with standalone writing, or appending to an
636        already existing XML document. In that case, the XML document
637        is required. An optional entry node in the XML document may also be given.
[2f4b430]638
[5062bbf]639        :param file: file to write to
640        :param doc: XML document object [optional]
641        :param entry_node: XML node within the XML document at which we will append the data [optional]
[2f4b430]642
[61cada5]643        """
644        from xml.dom.minidom import getDOMImplementation
[71f0373]645
[61cada5]646        # Check whether we have to write a standalone XML file
647        if doc is None:
648            impl = getDOMImplementation()
[f32d144]649            doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")
[61cada5]650            newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
651            top_element = newdoc.documentElement
652        else:
653            # We are appending to an existing document
654            newdoc = doc
[ac5b69d]655            try:
656                top_element = newdoc.createElement(FITTING_NODE_NAME)
657            except:
658                string = etree.tostring(doc, pretty_print=True)
659                newdoc = parseString(string)
660                top_element = newdoc.createElement(FITTING_NODE_NAME)
[61cada5]661            if entry_node is None:
662                newdoc.documentElement.appendChild(top_element)
663            else:
[ac5b69d]664                try:
665                    entry_node.appendChild(top_element)
666                except:
667                    node_name = entry_node.tag
668                    node_list = newdoc.getElementsByTagName(node_name)
669                    entry_node = node_list.item(0)
670                    entry_node.appendChild(top_element)
[2f4b430]671
[61cada5]672        attr = newdoc.createAttribute("version")
673        attr.nodeValue = '1.0'
674        top_element.setAttributeNode(attr)
[2f4b430]675
[61cada5]676        # File name
677        element = newdoc.createElement("filename")
678        if self.file is not None:
679            element.appendChild(newdoc.createTextNode(str(self.file)))
680        else:
681            element.appendChild(newdoc.createTextNode(str(file)))
682        top_element.appendChild(element)
[2f4b430]683
[11a7e11]684        element = newdoc.createElement("timestamp")
685        element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
686        attr = newdoc.createAttribute("epoch")
687        attr.nodeValue = str(self.timestamp)
688        element.setAttributeNode(attr)
689        top_element.appendChild(element)
[61cada5]690        # Inputs
691        inputs = newdoc.createElement("Attributes")
692        top_element.appendChild(inputs)
[2f4b430]693
[61cada5]694        if self.data is not None and hasattr(self.data, "group_id"):
695            self.data_group_id = self.data.group_id
696        if self.data is not None and hasattr(self.data, "is_data"):
697            self.is_data = self.data.is_data
698        if self.data is not None:
699            self.data_name = self.data.name
700        if self.data is not None and hasattr(self.data, "id"):
701            self.data_id = self.data.id
[2f4b430]702
[b1e609c]703        for item in LIST_OF_DATA_ATTRIBUTES:
[0b12abb5]704            element = newdoc.createElement(item[0])
[b1e609c]705            element.setAttribute(item[0], str(getattr(self, item[1])))
[f32d144]706            inputs.appendChild(element)
[2f4b430]707
[b1e609c]708        for item in LIST_OF_STATE_ATTRIBUTES:
[26f3dd5]709            element = newdoc.createElement(item[0])
[b1e609c]710            element.setAttribute(item[0], str(getattr(self, item[1])))
[26f3dd5]711            inputs.appendChild(element)
[2f4b430]712
[f32d144]713        # For self.values ={ disp_param_name: [vals,...],...}
714        # and for self.weights ={ disp_param_name: [weights,...],...}
[b1e609c]715        value_list = {}
716        for item in LIST_OF_MODEL_ATTRIBUTES:
[11a7e11]717            element = newdoc.createElement(item[0])
[b1e609c]718            value_list = getattr(self, item[1])
719            for key, value in value_list.iteritems():
[2296316]720                sub_element = newdoc.createElement(key)
721                sub_element.setAttribute('name', str(key))
722                for val in value:
[b1e609c]723                    sub_element.appendChild(newdoc.createTextNode(str(val)))
[2f4b430]724
[f32d144]725                element.appendChild(sub_element)
[11a7e11]726            inputs.appendChild(element)
[2f4b430]727
[2296316]728        # Create doc for the dictionary of self._disp_obj_dic
[b1e609c]729        for item in DISPERSION_LIST:
[f32d144]730            element = newdoc.createElement(item[0])
[b1e609c]731            value_list = getattr(self, item[1])
732            for key, val in value_list.iteritems():
[f32d144]733                value = repr(val)
734                sub_element = newdoc.createElement(key)
735                sub_element.setAttribute('name', str(key))
736                sub_element.setAttribute('value', str(value))
737                element.appendChild(sub_element)
738            inputs.appendChild(element)
[2f4b430]739
[b1e609c]740        for item in LIST_OF_STATE_PARAMETERS:
[61cada5]741            element = newdoc.createElement(item[0])
[b1e609c]742            self._toXML_helper(thelist=getattr(self, item[1]), element=element, newdoc=newdoc)
[61cada5]743            inputs.appendChild(element)
[2f4b430]744
[61cada5]745        # Save the file
746        if doc is None:
747            fd = open(file, 'w')
748            fd.write(newdoc.toprettyxml())
749            fd.close()
750            return None
751        else:
[ac5b69d]752            return newdoc
[2f4b430]753
[61cada5]754    def _fromXML_helper(self, node, list):
755        """
[5062bbf]756        Helper function to write state to xml
[61cada5]757        """
758        for item in node:
[0b12abb5]759            try:
760                name = item.get('name')
761            except:
762                name = None
763            try:
764                value = item.get('value')
765            except:
766                value = None
767            try:
[3ad91de]768                selected_to_fit = (item.get('selected_to_fit') == "True")
[0b12abb5]769            except:
770                selected_to_fit = None
771            try:
[3ad91de]772                error_displayed = (item.get('error_displayed') == "True")
[0b12abb5]773            except:
774                error_displayed = None
[f32d144]775            try:
[0b12abb5]776                error_value = item.get('error_value')
777            except:
778                error_value = None
779            try:
[f32d144]780                minimum_displayed = (item.get('minimum_displayed') == "True")
[0b12abb5]781            except:
782                minimum_displayed = None
783            try:
784                minimum_value = item.get('minimum_value')
785            except:
786                minimum_value = None
787            try:
[3ad91de]788                maximum_displayed = (item.get('maximum_displayed') == "True")
[0b12abb5]789            except:
790                maximum_displayed = None
791            try:
792                maximum_value = item.get('maximum_value')
793            except:
794                maximum_value = None
795            try:
796                unit = item.get('unit')
797            except:
798                unit = None
[2296316]799            list.append([selected_to_fit, name, value, "+/-",
800                         [error_displayed, error_value],
[f32d144]801                         [minimum_displayed, minimum_value],
802                         [maximum_displayed, maximum_value], unit])
[2f4b430]803
[61cada5]804    def fromXML(self, file=None, node=None):
805        """
[5062bbf]806        Load fitting state from a file
[2f4b430]807
[5062bbf]808        :param file: .fitv file
809        :param node: node of a XML document to read from
[2f4b430]810
[61cada5]811        """
812        if file is not None:
[11a7e11]813            msg = "PageState no longer supports non-CanSAS"
814            msg += " format for fitting files"
815            raise RuntimeError, msg
[2f4b430]816
[11a7e11]817        if node.get('version')and node.get('version') == '1.0':
[2f4b430]818
[61cada5]819            # Get file name
820            entry = get_content('ns:filename', node)
821            if entry is not None:
822                self.file = entry.text.strip()
[2f4b430]823
[11a7e11]824            # Get time stamp
825            entry = get_content('ns:timestamp', node)
826            if entry is not None and entry.get('epoch'):
827                try:
828                    self.timestamp = float(entry.get('epoch'))
829                except:
830                    msg = "PageState.fromXML: Could not"
831                    msg += " read timestamp\n %s" % sys.exc_value
832                    logging.error(msg)
[2f4b430]833
[61cada5]834            # Parse fitting attributes
835            entry = get_content('ns:Attributes', node)
[b1e609c]836            for item in LIST_OF_DATA_ATTRIBUTES:
[f32d144]837                node = get_content('ns:%s' % item[0], entry)
[b1e609c]838                setattr(self, item[0], parse_entry_helper(node, item))
[2296316]839
[61cada5]840            if entry is not None:
[b1e609c]841                for item in LIST_OF_STATE_ATTRIBUTES:
[2296316]842                    node = get_content('ns:%s' % item[0], entry)
[b1e609c]843                    setattr(self, item[0], parse_entry_helper(node, item))
[2f4b430]844
[b1e609c]845                for item in LIST_OF_STATE_PARAMETERS:
[2296316]846                    node = get_content("ns:%s" % item[0], entry)
[b1e609c]847                    self._fromXML_helper(node=node, list=getattr(self, item[1]))
[2f4b430]848
[f32d144]849                # Recover _disp_obj_dict from xml file
850                self._disp_obj_dict = {}
[b1e609c]851                for item in DISPERSION_LIST:
[2296316]852                    # Get node
853                    node = get_content("ns:%s" % item[0], entry)
854                    for attr in node:
[b1e609c]855                        name = str(attr.get('name'))
[f32d144]856                        val = attr.get('value')
[2296316]857                        value = val.split(" instance")[0]
858                        disp_name = value.split("<")[1]
[11a7e11]859                        try:
[2296316]860                            # Try to recover disp_model object from strings
[79492222]861                            com = "from sas.models.dispersion_models "
[2c44cf8]862                            com += "import %s as disp"
[2296316]863                            com_name = disp_name.split(".")[3]
864                            exec com % com_name
[2c44cf8]865                            disp_model = disp()
[b1e609c]866                            attribute = getattr(self, item[1])
867                            attribute[name] = com_name
[11a7e11]868                        except:
[b1e609c]869                            logging.error(sys.exc_value)
[2f4b430]870
[f32d144]871                # get self.values and self.weights dic. if exists
[b1e609c]872                for item in LIST_OF_MODEL_ATTRIBUTES:
[2296316]873                    node = get_content("ns:%s" % item[0], entry)
874                    dic = {}
[b1e609c]875                    value_list = []
[2296316]876                    for par in node:
877                        name = par.get('name')
878                        values = par.text.split('\n')
879                        # Get lines only with numbers
880                        for line in values:
881                            try:
[f32d144]882                                val = float(line)
[b1e609c]883                                value_list.append(val)
[2296316]884                            except:
885                                # pass if line is empty (it happens)
[b1e609c]886                                logging.error(sys.exc_value)
887                    dic[name] = numpy.array(value_list)
888                    setattr(self, item[1], dic)
[2f4b430]889
[2296316]890    def set_plot_state(self, figs, canvases):
891        """
892        Build image state that wx.html understand
893        by plotting, putting it into wx.FileSystem image object
894
895        """
896        images = []
897        # some imports
898        import wx
899
900        # Reset memory
901        self.imgRAM = None
902        wx.MemoryFSHandler()
[2f4b430]903
[2296316]904        # For no figures in the list, prepare empty plot
905        if figs == None or len(figs) == 0:
906            figs = [None]
[2f4b430]907
[f32d144]908        # Loop over the list of figures
[2296316]909        # use wx.MemoryFSHandler
[f32d144]910        self.imgRAM = wx.MemoryFSHandler()
[2296316]911        for fig in figs:
912            if figs != None:
913                ind = figs.index(fig)
914                canvas = canvases[ind]
[2f4b430]915
[b1e609c]916            #store the image in wx.FileSystem Object
[2296316]917            wx.FileSystem.AddHandler(wx.MemoryFSHandler())
[2f4b430]918
[2296316]919            # index of the fig
920            ind = figs.index(fig)
[2f4b430]921
[2296316]922            #AddFile, image can be retrieved with 'memory:filename'
[f32d144]923            self.imgRAM.AddFile('img_fit%s.png' % ind,
[2296316]924                                canvas.bitmap, wx.BITMAP_TYPE_PNG)
[2f4b430]925
[2296316]926            #append figs
927            images.append(fig)
[2f4b430]928
[c0ff8cc]929        return images
[61cada5]930
[f32d144]931
[61cada5]932class Reader(CansasReader):
933    """
[5062bbf]934    Class to load a .fitv fitting file
[61cada5]935    """
936    ## File type
937    type_name = "Fitting"
[2f4b430]938
[61cada5]939    ## Wildcards
[b35d3d1]940    type = ["Fitting files (*.fitv)|*.fitv"
[b9a5f0e]941            "SASView file (*.svs)|*.svs"]
[61cada5]942    ## List of allowed extensions
[f32d144]943    ext = ['.fitv', '.FITV', '.svs', 'SVS']
[2f4b430]944
[61cada5]945    def __init__(self, call_back=None, cansas=True):
[df7ed14]946        CansasReader.__init__(self)
[61cada5]947        """
[5062bbf]948        Initialize the call-back method to be called
949        after we load a file
[2f4b430]950
[5062bbf]951        :param call_back: call-back method
952        :param cansas:  True = files will be written/read in CanSAS format
953                        False = write CanSAS format
[2f4b430]954
[61cada5]955        """
956        ## Call back method to be executed after a file is read
957        self.call_back = call_back
958        ## CanSAS format flag
959        self.cansas = cansas
[75fbd17]960        self.state = None
[2f4b430]961
[75fbd17]962    def get_state(self):
963        return self.state
[2f4b430]964
[61cada5]965    def read(self, path):
[f32d144]966        """
[5062bbf]967        Load a new P(r) inversion state from file
[2f4b430]968
[5062bbf]969        :param path: file path
[2f4b430]970
[61cada5]971        """
[e9b12eaf]972        if self.cansas == True:
[61cada5]973            return self._read_cansas(path)
[2f4b430]974
[e9b12eaf]975    def _data2d_to_xml_doc(self, datainfo):
[61cada5]976        """
[5062bbf]977        Create an XML document to contain the content of a Data2D
[2f4b430]978
[5062bbf]979        :param datainfo: Data2D object
[2f4b430]980
[61cada5]981        """
982        if not issubclass(datainfo.__class__, Data2D):
983            raise RuntimeError, "The cansas writer expects a Data2D instance"
[2f4b430]984
[61cada5]985        doc = xml.dom.minidom.Document()
986        main_node = doc.createElement("SASroot")
987        main_node.setAttribute("version", self.version)
[df7ed14]988        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
989        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
[b1e609c]990        main_node.setAttribute("xsi:schemaLocation",
991                               "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
[2f4b430]992
[61cada5]993        doc.appendChild(main_node)
[2f4b430]994
[61cada5]995        entry_node = doc.createElement("SASentry")
996        main_node.appendChild(entry_node)
[2f4b430]997
[61cada5]998        write_node(doc, entry_node, "Title", datainfo.title)
[df7ed14]999        if datainfo is not None:
1000            write_node(doc, entry_node, "data_class", datainfo.__class__.__name__)
[61cada5]1001        for item in datainfo.run:
1002            runname = {}
[2f4b430]1003            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item])) > 1:
[b1e609c]1004                runname = {'name': datainfo.run_name[item]}
[61cada5]1005            write_node(doc, entry_node, "Run", item, runname)
1006        # Data info
[df7ed14]1007        new_node = doc.createElement("SASdata")
1008        entry_node.appendChild(new_node)
[b1e609c]1009        for item in LIST_OF_DATA_2D_ATTR:
[e9b12eaf]1010            element = doc.createElement(item[0])
[b1e609c]1011            element.setAttribute(item[0], str(getattr(datainfo, item[1])))
[df7ed14]1012            new_node.appendChild(element)
[2f4b430]1013
[b1e609c]1014        for item in LIST_OF_DATA_2D_VALUES:
[df7ed14]1015            root_node = doc.createElement(item[0])
1016            new_node.appendChild(root_node)
[38226d26]1017            temp_list = None
[b1e609c]1018            temp_list = getattr(datainfo, item[1])
[df7ed14]1019
[2f4b430]1020            if temp_list is None or len(temp_list) == 0:
[df7ed14]1021                element = doc.createElement(item[0])
[b1e609c]1022                element.appendChild(doc.createTextNode(str(temp_list)))
[df7ed14]1023                root_node.appendChild(element)
[35b556d]1024            else:
1025                for value in temp_list:
[df7ed14]1026                    element = doc.createElement(item[0])
[b1e609c]1027                    element.setAttribute(item[0], str(value))
[df7ed14]1028                    root_node.appendChild(element)
[2f4b430]1029
[61cada5]1030        # Sample info
1031        sample = doc.createElement("SASsample")
1032        if datainfo.sample.name is not None:
1033            sample.setAttribute("name", str(datainfo.sample.name))
1034        entry_node.appendChild(sample)
1035        write_node(doc, sample, "ID", str(datainfo.sample.ID))
[f32d144]1036        write_node(doc, sample, "thickness", datainfo.sample.thickness,
1037                   {"unit": datainfo.sample.thickness_unit})
[61cada5]1038        write_node(doc, sample, "transmission", datainfo.sample.transmission)
[f32d144]1039        write_node(doc, sample, "temperature", datainfo.sample.temperature,
1040                   {"unit": datainfo.sample.temperature_unit})
[2f4b430]1041
[61cada5]1042        for item in datainfo.sample.details:
1043            write_node(doc, sample, "details", item)
[2f4b430]1044
[61cada5]1045        pos = doc.createElement("position")
[f32d144]1046        written = write_node(doc, pos, "x", datainfo.sample.position.x,
1047                             {"unit": datainfo.sample.position_unit})
1048        written = written | write_node(doc, pos, "y",
1049                                       datainfo.sample.position.y,
1050                                       {"unit": datainfo.sample.position_unit})
1051        written = written | write_node(doc, pos, "z",
1052                                       datainfo.sample.position.z,
1053                                       {"unit": datainfo.sample.position_unit})
[61cada5]1054        if written == True:
1055            sample.appendChild(pos)
[2f4b430]1056
[61cada5]1057        ori = doc.createElement("orientation")
[f32d144]1058        written = write_node(doc, ori, "roll", datainfo.sample.orientation.x,
1059                             {"unit": datainfo.sample.orientation_unit})
1060        written = written | write_node(doc, ori, "pitch",
1061                                       datainfo.sample.orientation.y,
1062                                       {"unit": datainfo.sample.orientation_unit})
1063        written = written | write_node(doc, ori, "yaw",
1064                                       datainfo.sample.orientation.z,
1065                                       {"unit": datainfo.sample.orientation_unit})
[61cada5]1066        if written == True:
1067            sample.appendChild(ori)
[2f4b430]1068
[61cada5]1069        # Instrument info
1070        instr = doc.createElement("SASinstrument")
1071        entry_node.appendChild(instr)
[2f4b430]1072
[61cada5]1073        write_node(doc, instr, "name", datainfo.instrument)
[2f4b430]1074
[61cada5]1075        #   Source
1076        source = doc.createElement("SASsource")
1077        if datainfo.source.name is not None:
1078            source.setAttribute("name", str(datainfo.source.name))
1079        instr.appendChild(source)
[2f4b430]1080
[61cada5]1081        write_node(doc, source, "radiation", datainfo.source.radiation)
1082        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
1083        size = doc.createElement("beam_size")
1084        if datainfo.source.beam_size_name is not None:
1085            size.setAttribute("name", str(datainfo.source.beam_size_name))
[f32d144]1086        written = write_node(doc, size, "x", datainfo.source.beam_size.x,
1087                             {"unit": datainfo.source.beam_size_unit})
1088        written = written | write_node(doc, size, "y",
1089                                       datainfo.source.beam_size.y,
1090                                       {"unit": datainfo.source.beam_size_unit})
1091        written = written | write_node(doc, size, "z",
1092                                       datainfo.source.beam_size.z,
1093                                       {"unit": datainfo.source.beam_size_unit})
[61cada5]1094        if written == True:
1095            source.appendChild(size)
[2f4b430]1096
[f32d144]1097        write_node(doc, source, "wavelength", datainfo.source.wavelength,
1098                   {"unit": datainfo.source.wavelength_unit})
1099        write_node(doc, source, "wavelength_min",
1100                   datainfo.source.wavelength_min,
1101                   {"unit": datainfo.source.wavelength_min_unit})
1102        write_node(doc, source, "wavelength_max",
1103                   datainfo.source.wavelength_max,
1104                   {"unit": datainfo.source.wavelength_max_unit})
1105        write_node(doc, source, "wavelength_spread",
1106                   datainfo.source.wavelength_spread,
1107                   {"unit": datainfo.source.wavelength_spread_unit})
[2f4b430]1108
[61cada5]1109        #   Collimation
1110        for item in datainfo.collimation:
1111            coll = doc.createElement("SAScollimation")
1112            if item.name is not None:
1113                coll.setAttribute("name", str(item.name))
1114            instr.appendChild(coll)
[2f4b430]1115
[f32d144]1116            write_node(doc, coll, "length", item.length,
1117                       {"unit": item.length_unit})
[2f4b430]1118
[61cada5]1119            for apert in item.aperture:
1120                ap = doc.createElement("aperture")
1121                if apert.name is not None:
1122                    ap.setAttribute("name", str(apert.name))
1123                if apert.type is not None:
1124                    ap.setAttribute("type", str(apert.type))
1125                coll.appendChild(ap)
[2f4b430]1126
[f32d144]1127                write_node(doc, ap, "distance", apert.distance,
1128                           {"unit": apert.distance_unit})
[2f4b430]1129
[61cada5]1130                size = doc.createElement("size")
1131                if apert.size_name is not None:
1132                    size.setAttribute("name", str(apert.size_name))
[f32d144]1133                written = write_node(doc, size, "x", apert.size.x,
1134                                     {"unit": apert.size_unit})
1135                written = written | write_node(doc, size, "y", apert.size.y,
1136                                               {"unit": apert.size_unit})
1137                written = written | write_node(doc, size, "z", apert.size.z,
1138                                               {"unit": apert.size_unit})
[61cada5]1139                if written == True:
1140                    ap.appendChild(size)
1141
1142        #   Detectors
1143        for item in datainfo.detector:
1144            det = doc.createElement("SASdetector")
1145            written = write_node(doc, det, "name", item.name)
[f32d144]1146            written = written | write_node(doc, det, "SDD", item.distance,
1147                                           {"unit": item.distance_unit})
1148            written = written | write_node(doc, det, "slit_length",
1149                                           item.slit_length,
1150                                           {"unit": item.slit_length_unit})
[61cada5]1151            if written == True:
1152                instr.appendChild(det)
[2f4b430]1153
[61cada5]1154            off = doc.createElement("offset")
[f32d144]1155            written = write_node(doc, off, "x", item.offset.x,
1156                                 {"unit": item.offset_unit})
1157            written = written | write_node(doc, off, "y", item.offset.y,
1158                                           {"unit": item.offset_unit})
1159            written = written | write_node(doc, off, "z", item.offset.z,
1160                                           {"unit": item.offset_unit})
[61cada5]1161            if written == True:
1162                det.appendChild(off)
[2f4b430]1163
[61cada5]1164            center = doc.createElement("beam_center")
[f32d144]1165            written = write_node(doc, center, "x", item.beam_center.x,
1166                                 {"unit": item.beam_center_unit})
1167            written = written | write_node(doc, center, "y",
1168                                           item.beam_center.y,
1169                                           {"unit": item.beam_center_unit})
1170            written = written | write_node(doc, center, "z",
1171                                           item.beam_center.z,
1172                                           {"unit": item.beam_center_unit})
[61cada5]1173            if written == True:
1174                det.appendChild(center)
[2f4b430]1175
[61cada5]1176            pix = doc.createElement("pixel_size")
[f32d144]1177            written = write_node(doc, pix, "x", item.pixel_size.x,
1178                                 {"unit": item.pixel_size_unit})
1179            written = written | write_node(doc, pix, "y", item.pixel_size.y,
1180                                           {"unit": item.pixel_size_unit})
1181            written = written | write_node(doc, pix, "z", item.pixel_size.z,
1182                                           {"unit": item.pixel_size_unit})
[61cada5]1183            if written == True:
1184                det.appendChild(pix)
[2f4b430]1185
[61cada5]1186            ori = doc.createElement("orientation")
[f32d144]1187            written = write_node(doc, ori, "roll", item.orientation.x,
1188                                 {"unit": item.orientation_unit})
1189            written = written | write_node(doc, ori, "pitch",
1190                                           item.orientation.y,
1191                                           {"unit": item.orientation_unit})
1192            written = written | write_node(doc, ori, "yaw", item.orientation.z,
1193                                           {"unit": item.orientation_unit})
[61cada5]1194            if written == True:
1195                det.appendChild(ori)
[2f4b430]1196
[61cada5]1197        # Processes info
1198        for item in datainfo.process:
1199            node = doc.createElement("SASprocess")
1200            entry_node.appendChild(node)
1201
1202            write_node(doc, node, "name", item.name)
1203            write_node(doc, node, "date", item.date)
1204            write_node(doc, node, "description", item.description)
1205            for term in item.term:
1206                value = term['value']
1207                del term['value']
1208                write_node(doc, node, "term", value, term)
1209            for note in item.notes:
1210                write_node(doc, node, "SASprocessnote", note)
1211        # Return the document, and the SASentry node associated with
1212        # the data we just wrote
1213        return doc, entry_node
[2f4b430]1214
[61cada5]1215    def _parse_state(self, entry):
1216        """
[5062bbf]1217        Read a fit result from an XML node
[2f4b430]1218
[f32d144]1219        :param entry: XML node to read from
[2f4b430]1220
[5062bbf]1221        :return: PageState object
[61cada5]1222        """
1223        # Create an empty state
[2f4b430]1224        state = None
[61cada5]1225        # Locate the P(r) node
1226        try:
[f32d144]1227            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
1228                                namespaces={'ns': CANSAS_NS})
1229            if nodes != []:
[b35d3d1]1230                # Create an empty state
[f32d144]1231                state = PageState()
[b35d3d1]1232                state.fromXML(node=nodes[0])
[2f4b430]1233
[61cada5]1234        except:
1235            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value)
[2f4b430]1236
[61cada5]1237        return state
[2f4b430]1238
[ac5b69d]1239    def _parse_save_state_entry(self, dom):
[e9b12eaf]1240        """
[5062bbf]1241        Parse a SASentry
[2f4b430]1242
[5062bbf]1243        :param node: SASentry node
[2f4b430]1244
[df7ed14]1245        :return: Data1D/Data2D object
[2f4b430]1246
[e9b12eaf]1247        """
[df7ed14]1248        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
1249        if not node or node[0].text.lstrip().rstrip() != "Data2D":
[ac5b69d]1250            return_value, _ = self._parse_entry(dom)
1251            numpy.trim_zeros(return_value.x)
1252            numpy.trim_zeros(return_value.y)
1253            numpy.trim_zeros(return_value.dy)
1254            size_dx = return_value.dx.size
1255            size_dxl = return_value.dxl.size
1256            size_dxw = return_value.dxw.size
1257            if size_dxl == 0 and size_dxw == 0:
1258                return_value.dxl = None
1259                return_value.dxw = None
1260                numpy.trim_zeros(return_value.dx)
1261            elif size_dx == 0:
1262                return_value.dx = None
1263                size_dx = size_dxl
1264                numpy.trim_zeros(return_value.dxl)
1265                numpy.trim_zeros(return_value.dxw)
[2f4b430]1266
[ac5b69d]1267            return return_value, _
[2f4b430]1268
[df7ed14]1269        #Parse 2D
[e9b12eaf]1270        data_info = Data2D()
[2f4b430]1271
[f32d144]1272        # Look up title
[e9b12eaf]1273        self._store_content('ns:Title', dom, 'title', data_info)
[2f4b430]1274
[f32d144]1275        # Look up run number
[e9b12eaf]1276        nodes = dom.xpath('ns:Run', namespaces={'ns': CANSAS_NS})
[f32d144]1277        for item in nodes:
[e9b12eaf]1278            if item.text is not None:
1279                value = item.text.strip()
1280                if len(value) > 0:
1281                    data_info.run.append(value)
1282                    if item.get('name') is not None:
1283                        data_info.run_name[value] = item.get('name')
[2f4b430]1284
[f32d144]1285        # Look up instrument name
1286        self._store_content('ns:SASinstrument/ns:name', dom,
1287                            'instrument', data_info)
[e9b12eaf]1288
1289        # Notes
1290        note_list = dom.xpath('ns:SASnote', namespaces={'ns': CANSAS_NS})
1291        for note in note_list:
1292            try:
1293                if note.text is not None:
1294                    note_value = note.text.strip()
1295                    if len(note_value) > 0:
1296                        data_info.notes.append(note_value)
1297            except:
1298                err_mess = "cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value
1299                self.errors.append(err_mess)
1300                logging.error(err_mess)
[2f4b430]1301
[e9b12eaf]1302        # Sample info ###################
1303        entry = get_content('ns:SASsample', dom)
1304        if entry is not None:
1305            data_info.sample.name = entry.get('name')
[2f4b430]1306
[b1e609c]1307        self._store_content('ns:SASsample/ns:ID', dom, 'ID', data_info.sample)
1308        self._store_float('ns:SASsample/ns:thickness', dom, 'thickness', data_info.sample)
1309        self._store_float('ns:SASsample/ns:transmission', dom, 'transmission', data_info.sample)
1310        self._store_float('ns:SASsample/ns:temperature', dom, 'temperature', data_info.sample)
[2f4b430]1311
[b1e609c]1312        nodes = dom.xpath('ns:SASsample/ns:details', namespaces={'ns': CANSAS_NS})
[e9b12eaf]1313        for item in nodes:
1314            try:
1315                if item.text is not None:
1316                    detail_value = item.text.strip()
1317                    if len(detail_value) > 0:
1318                        data_info.sample.details.append(detail_value)
1319            except:
1320                err_mess = "cansas_reader.read: error processing sample details\n  %s" % sys.exc_value
1321                self.errors.append(err_mess)
1322                logging.error(err_mess)
[2f4b430]1323
[e9b12eaf]1324        # Position (as a vector)
[b1e609c]1325        self._store_float('ns:SASsample/ns:position/ns:x', dom, 'position.x', data_info.sample)
1326        self._store_float('ns:SASsample/ns:position/ns:y', dom, 'position.y', data_info.sample)
1327        self._store_float('ns:SASsample/ns:position/ns:z', dom, 'position.z', data_info.sample)
[2f4b430]1328
[e9b12eaf]1329        # Orientation (as a vector)
[f32d144]1330        self._store_float('ns:SASsample/ns:orientation/ns:roll',
[b1e609c]1331                          dom, 'orientation.x', data_info.sample)
[f32d144]1332        self._store_float('ns:SASsample/ns:orientation/ns:pitch',
[b1e609c]1333                          dom, 'orientation.y', data_info.sample)
[f32d144]1334        self._store_float('ns:SASsample/ns:orientation/ns:yaw',
[b1e609c]1335                          dom, 'orientation.z', data_info.sample)
[2f4b430]1336
[e9b12eaf]1337        # Source info ###################
1338        entry = get_content('ns:SASinstrument/ns:SASsource', dom)
1339        if entry is not None:
1340            data_info.source.name = entry.get('name')
[2f4b430]1341
[f32d144]1342        self._store_content('ns:SASinstrument/ns:SASsource/ns:radiation',
[b1e609c]1343                            dom, 'radiation', data_info.source)
[f32d144]1344        self._store_content('ns:SASinstrument/ns:SASsource/ns:beam_shape',
[b1e609c]1345                            dom, 'beam_shape', data_info.source)
[f32d144]1346        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength',
[b1e609c]1347                          dom, 'wavelength', data_info.source)
[f32d144]1348        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_min',
[b1e609c]1349                          dom, 'wavelength_min', data_info.source)
[f32d144]1350        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_max',
[b1e609c]1351                          dom, 'wavelength_max', data_info.source)
[f32d144]1352        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_spread',
[b1e609c]1353                          dom, 'wavelength_spread', data_info.source)
[2f4b430]1354
[f32d144]1355        # Beam size (as a vector)
[e9b12eaf]1356        entry = get_content('ns:SASinstrument/ns:SASsource/ns:beam_size', dom)
1357        if entry is not None:
1358            data_info.source.beam_size_name = entry.get('name')
[2f4b430]1359
[f32d144]1360        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:x',
[b1e609c]1361                          dom, 'beam_size.x', data_info.source)
[f32d144]1362        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:y',
[b1e609c]1363                          dom, 'beam_size.y', data_info.source)
[f32d144]1364        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:z',
[b1e609c]1365                          dom, 'beam_size.z', data_info.source)
[2f4b430]1366
[e9b12eaf]1367        # Collimation info ###################
[f32d144]1368        nodes = dom.xpath('ns:SASinstrument/ns:SAScollimation',
1369                          namespaces={'ns': CANSAS_NS})
[e9b12eaf]1370        for item in nodes:
1371            collim = Collimation()
1372            if item.get('name') is not None:
1373                collim.name = item.get('name')
[f32d144]1374            self._store_float('ns:length', item, 'length', collim)
[2f4b430]1375
[e9b12eaf]1376            # Look for apertures
[f32d144]1377            apert_list = item.xpath('ns:aperture',
1378                                    namespaces={'ns': CANSAS_NS})
[e9b12eaf]1379            for apert in apert_list:
[f32d144]1380                aperture = Aperture()
[2f4b430]1381
[e9b12eaf]1382                # Get the name and type of the aperture
1383                aperture.name = apert.get('name')
1384                aperture.type = apert.get('type')
[2f4b430]1385
[f32d144]1386                self._store_float('ns:distance', apert, 'distance', aperture)
[2f4b430]1387
[e9b12eaf]1388                entry = get_content('ns:size', apert)
1389                if entry is not None:
1390                    aperture.size_name = entry.get('name')
[2f4b430]1391
[f32d144]1392                self._store_float('ns:size/ns:x', apert, 'size.x', aperture)
1393                self._store_float('ns:size/ns:y', apert, 'size.y', aperture)
[e9b12eaf]1394                self._store_float('ns:size/ns:z', apert, 'size.z', aperture)
[2f4b430]1395
[e9b12eaf]1396                collim.aperture.append(aperture)
[2f4b430]1397
[e9b12eaf]1398            data_info.collimation.append(collim)
[2f4b430]1399
[e9b12eaf]1400        # Detector info ######################
[f32d144]1401        nodes = dom.xpath('ns:SASinstrument/ns:SASdetector',
1402                          namespaces={'ns': CANSAS_NS})
[e9b12eaf]1403        for item in nodes:
[2f4b430]1404
[e9b12eaf]1405            detector = Detector()
[2f4b430]1406
[e9b12eaf]1407            self._store_content('ns:name', item, 'name', detector)
[f32d144]1408            self._store_float('ns:SDD', item, 'distance', detector)
[2f4b430]1409
[e9b12eaf]1410            # Detector offset (as a vector)
[f32d144]1411            self._store_float('ns:offset/ns:x', item, 'offset.x', detector)
1412            self._store_float('ns:offset/ns:y', item, 'offset.y', detector)
1413            self._store_float('ns:offset/ns:z', item, 'offset.z', detector)
[2f4b430]1414
[e9b12eaf]1415            # Detector orientation (as a vector)
[f32d144]1416            self._store_float('ns:orientation/ns:roll', item,
1417                              'orientation.x', detector)
1418            self._store_float('ns:orientation/ns:pitch', item,
1419                              'orientation.y', detector)
1420            self._store_float('ns:orientation/ns:yaw', item,
1421                              'orientation.z', detector)
[2f4b430]1422
[e9b12eaf]1423            # Beam center (as a vector)
[f32d144]1424            self._store_float('ns:beam_center/ns:x', item,
1425                              'beam_center.x', detector)
1426            self._store_float('ns:beam_center/ns:y', item,
1427                              'beam_center.y', detector)
1428            self._store_float('ns:beam_center/ns:z', item,
1429                              'beam_center.z', detector)
[2f4b430]1430
[e9b12eaf]1431            # Pixel size (as a vector)
[f32d144]1432            self._store_float('ns:pixel_size/ns:x', item,
1433                              'pixel_size.x', detector)
1434            self._store_float('ns:pixel_size/ns:y', item,
1435                              'pixel_size.y', detector)
1436            self._store_float('ns:pixel_size/ns:z', item,
1437                              'pixel_size.z', detector)
[2f4b430]1438
[e9b12eaf]1439            self._store_float('ns:slit_length', item, 'slit_length', detector)
[2f4b430]1440
[f32d144]1441            data_info.detector.append(detector)
[e9b12eaf]1442
1443        # Processes info ######################
1444        nodes = dom.xpath('ns:SASprocess', namespaces={'ns': CANSAS_NS})
1445        for item in nodes:
1446            process = Process()
1447            self._store_content('ns:name', item, 'name', process)
1448            self._store_content('ns:date', item, 'date', process)
1449            self._store_content('ns:description', item, 'description', process)
[2f4b430]1450
[e9b12eaf]1451            term_list = item.xpath('ns:term', namespaces={'ns': CANSAS_NS})
1452            for term in term_list:
1453                try:
1454                    term_attr = {}
1455                    for attr in term.keys():
1456                        term_attr[attr] = term.get(attr).strip()
1457                    if term.text is not None:
1458                        term_attr['value'] = term.text.strip()
1459                        process.term.append(term_attr)
1460                except:
1461                    err_mess = "cansas_reader.read: error processing process term\n  %s" % sys.exc_value
1462                    self.errors.append(err_mess)
1463                    logging.error(err_mess)
[2f4b430]1464
[f32d144]1465            note_list = item.xpath('ns:SASprocessnote',
1466                                   namespaces={'ns': CANSAS_NS})
[e9b12eaf]1467            for note in note_list:
1468                if note.text is not None:
1469                    process.notes.append(note.text.strip())
[2f4b430]1470
[e9b12eaf]1471            data_info.process.append(process)
[2f4b430]1472
[e9b12eaf]1473        # Data info ######################
1474        nodes = dom.xpath('ns:SASdata', namespaces={'ns': CANSAS_NS})
[f32d144]1475        if len(nodes) > 1:
[e9b12eaf]1476            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
[2f4b430]1477
[df7ed14]1478        for entry in nodes:
[b1e609c]1479            for item in LIST_OF_DATA_2D_ATTR:
[df7ed14]1480                #get node
[f32d144]1481                node = get_content('ns:%s' % item[0], entry)
[b1e609c]1482                setattr(data_info, item[1], parse_entry_helper(node, item))
[2f4b430]1483
[b1e609c]1484            for item in LIST_OF_DATA_2D_VALUES:
[f32d144]1485                field = get_content('ns:%s' % item[0], entry)
[b1e609c]1486                value_list = []
[df7ed14]1487                if field is not None:
[b1e609c]1488                    value_list = [parse_entry_helper(node, item) for node in field]
1489                if len(value_list) < 2:
1490                    setattr(data_info, item[0], None)
[44f7c1b]1491                else:
[b1e609c]1492                    setattr(data_info, item[0], numpy.array(value_list))
[2f4b430]1493
[e9b12eaf]1494        return data_info
1495
[61cada5]1496    def _read_cansas(self, path):
[f32d144]1497        """
[5062bbf]1498        Load data and P(r) information from a CanSAS XML file.
[2f4b430]1499
[5062bbf]1500        :param path: file path
[2f4b430]1501
[f32d144]1502        :return: Data1D object if a single SASentry was found,
[5062bbf]1503                    or a list of Data1D objects if multiple entries were found,
1504                    or None of nothing was found
[2f4b430]1505
[5062bbf]1506        :raise RuntimeError: when the file can't be opened
1507        :raise ValueError: when the length of the data vectors are inconsistent
[2f4b430]1508
[61cada5]1509        """
1510        output = []
[f32d144]1511        basename = os.path.basename(path)
[b63dc6e]1512        root, extension = os.path.splitext(basename)
1513        ext = extension.lower()
[61cada5]1514        try:
1515            if os.path.isfile(path):
[2f4b430]1516
[61cada5]1517                #TODO: eventually remove the check for .xml once
1518                # the P(r) writer/reader is truly complete.
[b63dc6e]1519                if  ext in self.ext or \
1520                    ext == '.xml':
[2f4b430]1521
[61cada5]1522                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
1523                    # Check the format version number
[f32d144]1524                    # Specifying the namespace will take care of the file format version
[61cada5]1525                    root = tree.getroot()
[f32d144]1526                    entry_list = root.xpath('ns:SASentry',
1527                                            namespaces={'ns': CANSAS_NS})
1528                    for entry in entry_list:
[e9b12eaf]1529                        try:
[ac5b69d]1530                            sas_entry, _ = self._parse_save_state_entry(entry)
[e9b12eaf]1531                        except:
[df7ed14]1532                            raise
[61cada5]1533                        fitstate = self._parse_state(entry)
[2f4b430]1534
[b35d3d1]1535                        #state could be None when .svs file is loaded
1536                        #in this case, skip appending to output
1537                        if fitstate != None:
1538                            sas_entry.meta_data['fitstate'] = fitstate
1539                            sas_entry.filename = fitstate.file
1540                            output.append(sas_entry)
[61cada5]1541            else:
[b63dc6e]1542                self.call_back(format=ext)
[61cada5]1543                raise RuntimeError, "%s is not a file" % path
[b35d3d1]1544
[61cada5]1545            # Return output consistent with the loader's api
[f32d144]1546            if len(output) == 0:
1547                self.call_back(state=None, datainfo=None, format=ext)
[61cada5]1548                return None
1549            else:
[b35d3d1]1550                for ind in range(len(output)):
1551                    # Call back to post the new state
1552                    state = output[ind].meta_data['fitstate']
1553                    t = time.localtime(state.timestamp)
1554                    time_str = time.strftime("%b %d %H:%M", t)
1555                    # Check that no time stamp is already appended
1556                    max_char = state.file.find("[")
1557                    if max_char < 0:
1558                        max_char = len(state.file)
[ef16f59]1559                    original_fname = state.file[0:max_char]
[f32d144]1560                    state.file = original_fname + ' [' + time_str + ']'
[2f4b430]1561
[b35d3d1]1562                    if state is not None and state.is_data is not None:
[b1e609c]1563                        output[ind].is_data = state.is_data
[2f4b430]1564
[b35d3d1]1565                    output[ind].filename = state.file
1566                    state.data = output[ind]
[f32d144]1567                    state.data.name = output[ind].filename  # state.data_name
[b35d3d1]1568                    state.data.id = state.data_id
1569                    if state.is_data is not None:
1570                        state.data.is_data = state.is_data
[f32d144]1571                    if output[ind].run_name is not None\
1572                        and len(output[ind].run_name) != 0:
[ef16f59]1573                        name = output[ind].run_name
[f32d144]1574                    else:
1575                        name = original_fname
[ef16f59]1576                    state.data.group_id = name
1577                    #store state in fitting
[f32d144]1578                    self.call_back(state=state,
1579                                   datainfo=output[ind], format=ext)
1580                    self.state = state
[ef16f59]1581                return output
[61cada5]1582        except:
[4bee68d]1583            self.call_back(format=ext)
[61cada5]1584            raise
[2f4b430]1585
[61cada5]1586    def write(self, filename, datainfo=None, fitstate=None):
1587        """
[b35d3d1]1588        Write the content of a Data1D as a CanSAS XML file only for standalone
[2f4b430]1589
[5062bbf]1590        :param filename: name of the file to write
1591        :param datainfo: Data1D object
1592        :param fitstate: PageState object
[2f4b430]1593
[61cada5]1594        """
1595        # Sanity check
1596        if self.cansas == True:
1597            # Add fitting information to the XML document
[ef16f59]1598            doc = self.write_toXML(datainfo, fitstate)
[61cada5]1599            # Write the XML document
1600        else:
[ac5b69d]1601            doc = fitstate.toXML(file=filename)
[2f4b430]1602
[ac5b69d]1603        # Save the document no matter the type
1604        fd = open(filename, 'w')
1605        fd.write(doc.toprettyxml())
1606        fd.close()
[2f4b430]1607
[b35d3d1]1608    def write_toXML(self, datainfo=None, state=None):
1609        """
[f32d144]1610        Write toXML, a helper for write(),
1611        could be used by guimanager._on_save()
[2f4b430]1612
[b35d3d1]1613        : return: xml doc
1614        """
[3c44c66]1615
[b35d3d1]1616        if state.data is None:
[79492222]1617            data = sas.dataloader.data_info.Data1D(x=[], y=[])
[a805118]1618            return None
[3b148c3]1619        elif not state.data.is_data:
1620            return None
[f32d144]1621        else:
[b35d3d1]1622            #make sure title and data run is filled up.
[f32d144]1623            if state.data.title == None or state.data.title == '':
1624                state.data.title = state.data.name
1625            if state.data.run_name == None or state.data.run_name == {}:
[028a0e8]1626                state.data.run = [str(state.data.name)]
1627                state.data.run_name[0] = state.data.name
[2f4b430]1628
[f32d144]1629            if issubclass(state.data.__class__,
[79492222]1630                          sas.dataloader.data_info.Data1D):
[b35d3d1]1631                data = state.data
1632                doc, sasentry = self._to_xml_doc(data)
1633            else:
1634                data = state.data
1635                doc, sasentry = self._data2d_to_xml_doc(data)
[2f4b430]1636
[b35d3d1]1637        if state is not None:
[ac5b69d]1638            doc = state.toXML(doc=doc, file=data.filename, entry_node=sasentry)
[2f4b430]1639
[f32d144]1640        return doc
[2f4b430]1641
[f32d144]1642# Simple html report templet
[2296316]1643HEADER = "<html>\n"
1644HEADER += "<head>\n"
1645HEADER += "<meta http-equiv=Content-Type content='text/html; "
1646HEADER += "charset=windows-1252'> \n"
1647HEADER += "<meta name=Generator >\n"
1648HEADER += "</head>\n"
1649HEADER += "<body lang=EN-US>\n"
1650HEADER += "<div class=WordSection1>\n"
[14d2daa]1651HEADER += "<p class=MsoNormal><b><span ><center><font size='4' >"
1652HEADER += "%s</font></center></span></center></b></p>"
[2296316]1653HEADER += "<p class=MsoNormal>&nbsp;</p>"
[14d2daa]1654PARA = "<p class=MsoNormal><font size='4' > %s \n"
1655PARA += "</font></p>"
1656CENTRE = "<p class=MsoNormal><center><font size='4' > %s \n"
1657CENTRE += "</font></center></p>"
[2296316]1658FEET_1 = \
1659"""
[3a3dd9c]1660<p class=MsoNormal>&nbsp;</p>
[14d2daa]1661<br>
1662<p class=MsoNormal><b><span ><center> <font size='4' > Graph
[f32d144]1663</font></span></center></b></p>
1664<p class=MsoNormal>&nbsp;</p>
1665<center>
[14d2daa]1666<br><font size='4' >Model Computation</font>
[f32d144]1667<br><font size='4' >Data: "%s"</font><br>
[2296316]1668"""
1669FEET_2 = \
1670"""
[f32d144]1671<img src="%s" >
[2296316]1672</img>
1673"""
1674FEET_3 = \
1675"""
[f32d144]1676</center>
[2296316]1677</div>
1678</body>
1679</html>
1680"""
1681ELINE = "<p class=MsoNormal>&nbsp;</p>"
1682
[3c44c66]1683if __name__ == "__main__":
1684    state = PageState(parent=None)
1685    #state.toXML()
1686    """
[2f4b430]1687
[3c44c66]1688    file = open("test_state", "w")
1689    pickle.dump(state, file)
1690    print pickle.dumps(state)
1691    state.data_name = "hello---->"
1692    pickle.dump(state, file)
1693    file = open("test_state", "r")
1694    new_state= pickle.load(file)
1695    print "new state", new_state
1696    new_state= pickle.load(file)
1697    print "new state", new_state
1698    #print "state", state
1699    """
1700    import bsddb
1701    import pickle
[f32d144]1702    db = bsddb.btopen('file_state.db', 'c')
[3c44c66]1703    val = (pickle.dumps(state), "hello", "hi")
[f32d144]1704    db['state1'] = pickle.dumps(val)
[3c44c66]1705    print pickle.loads(db['state1'])
1706    state.data_name = "hello---->22"
[f32d144]1707    db['state2'] = pickle.dumps(state)
[3c44c66]1708    state.data_name = "hello---->2"
[f32d144]1709    db['state3'] = pickle.dumps(state)
[3c44c66]1710    del db['state3']
1711    state.data_name = "hello---->3"
[f32d144]1712    db['state4'] = pickle.dumps(state)
[3c44c66]1713    new_state = pickle.loads(db['state1'])
1714    #print db.last()
1715    db.set_location('state2')
1716    state.data_name = "hello---->5"
[f32d144]1717    db['aastate5'] = pickle.dumps(state)
[3c44c66]1718    db.keys().sort()
1719    print pickle.loads(db['state2'])
[2f4b430]1720
[f32d144]1721    db.close()
Note: See TracBrowser for help on using the repository browser.