source: sasview/sansview/perspectives/fitting/pagestate.py @ e58c280

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 e58c280 was c0ff8cc, checked in by Jae Cho <jhjcho@…>, 14 years ago

fixed problem in saving w/multifunctional models

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