source: sasview/src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py @ 5d14851a

ESS_GUIESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_opencl
Last change on this file since 5d14851a was b38c8c8, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 6 years ago

Allow for constrain copy/paste after formatting of the field changed.
SASVIEW-1278

  • Property mode set to 100644
File size: 28.8 KB
Line 
1import copy
2
3from PyQt5 import QtCore
4from PyQt5 import QtGui
5
6import numpy
7
8from sas.qtgui.Plotting.PlotterData import Data1D
9from sas.qtgui.Plotting.PlotterData import Data2D
10
11from sas.qtgui.Perspectives.Fitting.AssociatedComboBox import AssociatedComboBox
12
13model_header_captions = ['Parameter', 'Value', 'Min', 'Max', 'Units']
14
15model_header_tooltips = ['Select parameter for fitting',
16                         'Enter parameter value',
17                         'Enter minimum value for parameter',
18                         'Enter maximum value for parameter',
19                         'Unit of the parameter']
20
21poly_header_captions = ['Parameter', 'PD[ratio]', 'Min', 'Max', 'Npts', 'Nsigs',
22                        'Function', 'Filename']
23
24poly_header_tooltips = ['Select parameter for fitting',
25                        'Enter polydispersity ratio (Std deviation/mean).\n'+
26                        'For angles this can be either std deviation or half width (for uniform distributions) in degrees',
27                        'Enter minimum value for parameter',
28                        'Enter maximum value for parameter',
29                        'Enter number of points for parameter',
30                        'Enter number of sigmas parameter',
31                        'Select distribution function',
32                        'Select filename with user-definable distribution']
33
34error_tooltip = 'Error value for fitted parameter'
35header_error_caption = 'Error'
36
37def replaceShellName(param_name, value):
38    """
39    Updates parameter name from <param_name>[n_shell] to <param_name>value
40    """
41    assert '[' in param_name
42    return param_name[:param_name.index('[')]+str(value)
43
44def getIterParams(model):
45    """
46    Returns a list of all multi-shell parameters in 'model'
47    """
48    return list([par for par in model.iq_parameters if "[" in par.name])
49
50def getMultiplicity(model):
51    """
52    Finds out if 'model' has multishell parameters.
53    If so, returns the name of the counter parameter and the number of shells
54    """
55    iter_params = getIterParams(model)
56    param_name = ""
57    param_length = 0
58    if iter_params:
59        param_length = iter_params[0].length
60        param_name = iter_params[0].length_control
61        if param_name is None and '[' in iter_params[0].name:
62            param_name = iter_params[0].name[:iter_params[0].name.index('[')]
63    return (param_name, param_length)
64
65def createFixedChoiceComboBox(param, item_row):
66    """
67    Determines whether param is a fixed-choice parameter, modifies items in item_row appropriately and returns a combo
68    box containing the fixed choices. Returns None if param is not fixed-choice.
69   
70    item_row is a list of QStandardItem objects for insertion into the parameter table.
71    """
72
73    # Determine whether this is a fixed-choice parameter. There are lots of conditionals, simply because the
74    # implementation is not yet concrete; there are several possible indicators that the parameter is fixed-choice.
75    # TODO: (when the sasmodels implementation is concrete, clean this up)
76    choices = None
77    if isinstance(param.choices, (list, tuple)) and len(param.choices) > 0:
78        # The choices property is concrete in sasmodels, probably will use this
79        choices = param.choices
80    elif isinstance(param.units, (list, tuple)):
81        choices = [str(x) for x in param.units]
82
83    cbox = None
84    if choices is not None:
85        # Use combo box for input, if it is fixed-choice
86        cbox = AssociatedComboBox(item_row[1], idx_as_value=True)
87        cbox.addItems(choices)
88        item_row[2].setEditable(False)
89        item_row[3].setEditable(False)
90
91    return cbox
92
93def addParametersToModel(parameters, kernel_module, is2D, model=None, view=None):
94    """
95    Update local ModelModel with sasmodel parameters.
96    Actually appends to model, if model and view params are not None.
97    Always returns list of lists of QStandardItems.
98    """
99    multishell_parameters = getIterParams(parameters)
100    multishell_param_name, _ = getMultiplicity(parameters)
101
102    if is2D:
103        params = [p for p in parameters.kernel_parameters if p.type != 'magnetic']
104    else:
105        params = parameters.iq_parameters
106
107    rows = []
108    for param in params:
109        # don't include shell parameters
110        if param.name == multishell_param_name:
111            continue
112
113        # Modify parameter name from <param>[n] to <param>1
114        item_name = param.name
115        if param in multishell_parameters:
116            continue
117
118        item1 = QtGui.QStandardItem(item_name)
119        item1.setCheckable(True)
120        item1.setEditable(False)
121
122        # check for polydisp params
123        if param.polydisperse:
124            poly_item = QtGui.QStandardItem("Polydispersity")
125            poly_item.setEditable(False)
126            item1_1 = QtGui.QStandardItem("Distribution")
127            item1_1.setEditable(False)
128
129            # Find param in volume_params
130            poly_pars = copy.deepcopy(parameters.form_volume_parameters)
131            if is2D:
132                poly_pars += parameters.orientation_parameters
133            for p in poly_pars:
134                if p.name != param.name:
135                    continue
136                width = kernel_module.getParam(p.name+'.width')
137                ptype = kernel_module.getParam(p.name+'.type')
138                item1_2 = QtGui.QStandardItem(str(width))
139                item1_2.setEditable(False)
140                item1_3 = QtGui.QStandardItem()
141                item1_3.setEditable(False)
142                item1_4 = QtGui.QStandardItem()
143                item1_4.setEditable(False)
144                item1_5 = QtGui.QStandardItem(ptype)
145                item1_5.setEditable(False)
146                poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5])
147                break
148
149            # Add the polydisp item as a child
150            item1.appendRow([poly_item])
151
152        # Param values
153        item2 = QtGui.QStandardItem(str(param.default))
154        item3 = QtGui.QStandardItem(str(param.limits[0]))
155        item4 = QtGui.QStandardItem(str(param.limits[1]))
156        item5 = QtGui.QStandardItem(str(param.units))
157        item5.setEditable(False)
158
159        # Check if fixed-choice (returns combobox, if so, also makes some items uneditable)
160        row = [item1, item2, item3, item4, item5]
161        cbox = createFixedChoiceComboBox(param, row)
162
163        # Append to the model and use the combobox, if required
164        if None not in (model, view):
165            model.appendRow(row)
166            if cbox:
167                view.setIndexWidget(item2.index(), cbox)
168        rows.append(row)
169
170    return rows
171
172def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=None, row_num=None):
173    """
174    Update local ModelModel with sasmodel parameters (non-dispersed, non-magnetic)
175    Actually appends to model, if model and view params are not None.
176    Always returns list of lists of QStandardItems.
177
178    parameters_original: list of parameters before any tagging on their IDs, e.g. for product model (so that those are
179    the display names; see below)
180    """
181    if is2D:
182        params = [p for p in parameters.kernel_parameters if p.type != 'magnetic']
183    else:
184        params = parameters.iq_parameters
185
186    if parameters_original:
187        # 'parameters_original' contains the parameters as they are to be DISPLAYED, while 'parameters'
188        # contains the parameters as they were renamed; this is for handling name collisions in product model.
189        # The 'real name' of the parameter will be stored in the item's user data.
190        if is2D:
191            params_orig = [p for p in parameters_original.kernel_parameters if p.type != 'magnetic']
192        else:
193            params_orig = parameters_original.iq_parameters
194    else:
195        # no difference in names anyway
196        params_orig = params
197
198    rows = []
199    for param, param_orig in zip(params, params_orig):
200        # Create the top level, checkable item
201        item_name = param_orig.name
202        item1 = QtGui.QStandardItem(item_name)
203        item1.setData(param.name, QtCore.Qt.UserRole)
204        item1.setCheckable(True)
205        item1.setEditable(False)
206
207        # Param values
208        # TODO: add delegate for validation of cells
209        item2 = QtGui.QStandardItem(str(param.default))
210        item3 = QtGui.QStandardItem(str(param.limits[0]))
211        item4 = QtGui.QStandardItem(str(param.limits[1]))
212        item5 = QtGui.QStandardItem(str(param.units))
213        item5.setEditable(False)
214
215        # Check if fixed-choice (returns combobox, if so, also makes some items uneditable)
216        row = [item1, item2, item3, item4, item5]
217        cbox = createFixedChoiceComboBox(param, row)
218
219        # Append to the model and use the combobox, if required
220        if None not in (model, view):
221            if row_num is None:
222                model.appendRow(row)
223            else:
224                model.insertRow(row_num, row)
225                row_num += 1
226
227            if cbox:
228                view.setIndexWidget(item2.index(), cbox)
229
230        rows.append(row)
231
232    return rows
233
234def markParameterDisabled(model, row):
235    """Given the QModel row number, format to show it is not available for fitting"""
236
237    # If an error column is present, there are a total of 6 columns.
238    items = [model.item(row, c) for c in range(6)]
239
240    model.blockSignals(True)
241
242    for item in items:
243        if item is None:
244            continue
245        item.setEditable(False)
246        item.setCheckable(False)
247
248    item = items[0]
249
250    font = QtGui.QFont()
251    font.setItalic(True)
252    item.setFont(font)
253    item.setForeground(QtGui.QBrush(QtGui.QColor(100, 100, 100)))
254    item.setToolTip("This parameter cannot be fitted.")
255
256    model.blockSignals(False)
257
258def addCheckedListToModel(model, param_list):
259    """
260    Add a QItem to model. Makes the QItem checkable
261    """
262    assert isinstance(model, QtGui.QStandardItemModel)
263    item_list = [QtGui.QStandardItem(item) for item in param_list]
264    item_list[0].setCheckable(True)
265    model.appendRow(item_list)
266
267def addHeadingRowToModel(model, name):
268    """adds a non-interactive top-level row to the model"""
269    header_row = [QtGui.QStandardItem() for i in range(5)]
270    header_row[0].setText(name)
271
272    font = header_row[0].font()
273    font.setBold(True)
274    header_row[0].setFont(font)
275
276    for item in header_row:
277        item.setEditable(False)
278        item.setCheckable(False)
279        item.setSelectable(False)
280
281    model.appendRow(header_row)
282
283def addHeadersToModel(model):
284    """
285    Adds predefined headers to the model
286    """
287    for i, item in enumerate(model_header_captions):
288        model.setHeaderData(i, QtCore.Qt.Horizontal, item)
289
290    model.header_tooltips = copy.copy(model_header_tooltips)
291
292def addErrorHeadersToModel(model):
293    """
294    Adds predefined headers to the model
295    """
296    model_header_error_captions = copy.copy(model_header_captions)
297    model_header_error_captions.insert(2, header_error_caption)
298    for i, item in enumerate(model_header_error_captions):
299        model.setHeaderData(i, QtCore.Qt.Horizontal, item)
300
301    model_header_error_tooltips = copy.copy(model_header_tooltips)
302    model_header_error_tooltips.insert(2, error_tooltip)
303    model.header_tooltips = copy.copy(model_header_error_tooltips)
304
305def addPolyHeadersToModel(model):
306    """
307    Adds predefined headers to the model
308    """
309    for i, item in enumerate(poly_header_captions):
310        model.setHeaderData(i, QtCore.Qt.Horizontal, item)
311
312    model.header_tooltips = copy.copy(poly_header_tooltips)
313
314
315def addErrorPolyHeadersToModel(model):
316    """
317    Adds predefined headers to the model
318    """
319    poly_header_error_captions = copy.copy(poly_header_captions)
320    poly_header_error_captions.insert(2, header_error_caption)
321    for i, item in enumerate(poly_header_error_captions):
322        model.setHeaderData(i, QtCore.Qt.Horizontal, item)
323
324    poly_header_error_tooltips = copy.copy(poly_header_tooltips)
325    poly_header_error_tooltips.insert(2, error_tooltip)
326    model.header_tooltips = copy.copy(poly_header_error_tooltips)
327
328def addShellsToModel(parameters, model, index, row_num=None, view=None):
329    """
330    Find out multishell parameters and update the model with the requested number of them.
331    Inserts them after the row at row_num, if not None; otherwise, appends to end.
332    If view param is not None, supports fixed-choice params.
333    Returns a list of lists of QStandardItem objects.
334    """
335    multishell_parameters = getIterParams(parameters)
336
337    rows = []
338    for i in range(index):
339        for par in multishell_parameters:
340            # Create the name: <param>[<i>], e.g. "sld1" for parameter "sld[n]"
341            param_name = replaceShellName(par.name, i+1)
342            item1 = QtGui.QStandardItem(param_name)
343            item1.setCheckable(True)
344            # check for polydisp params
345            if par.polydisperse:
346                poly_item = QtGui.QStandardItem("Polydispersity")
347                item1_1 = QtGui.QStandardItem("Distribution")
348                # Find param in volume_params
349                for p in parameters.form_volume_parameters:
350                    if p.name != par.name:
351                        continue
352                    item1_2 = QtGui.QStandardItem(str(p.default))
353                    item1_3 = QtGui.QStandardItem(str(p.limits[0]))
354                    item1_4 = QtGui.QStandardItem(str(p.limits[1]))
355                    item1_5 = QtGui.QStandardItem(str(p.units))
356                    poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5])
357                    break
358                item1.appendRow([poly_item])
359
360            item2 = QtGui.QStandardItem(str(par.default))
361            item3 = QtGui.QStandardItem(str(par.limits[0]))
362            item4 = QtGui.QStandardItem(str(par.limits[1]))
363            item5 = QtGui.QStandardItem(str(par.units))
364            item5.setEditable(False)
365
366            # Check if fixed-choice (returns combobox, if so, also makes some items uneditable)
367            row = [item1, item2, item3, item4, item5]
368            cbox = createFixedChoiceComboBox(par, row)
369
370            # Apply combobox if required
371            if None not in (view, cbox):
372                # set the min/max cell to be empty
373                item3.setText("")
374                item4.setText("")
375
376            # Always add to the model
377            if row_num is None:
378                model.appendRow(row)
379            else:
380                model.insertRow(row_num, row)
381                row_num += 1
382
383            if cbox is not None:
384                view.setIndexWidget(item2.index(), cbox)
385
386            rows.append(row)
387
388    return rows
389
390def calculateChi2(reference_data, current_data):
391    """
392    Calculate Chi2 value between two sets of data
393    """
394    if reference_data is None or current_data is None:
395        return None
396    # WEIGHING INPUT
397    #from sas.sasgui.perspectives.fitting.utils import get_weight
398    #flag = self.get_weight_flag()
399    #weight = get_weight(data=self.data, is2d=self._is_2D(), flag=flag)
400    chisqr = None
401    if reference_data is None:
402        return chisqr
403
404    # temporary default values for index and weight
405    index = None
406    weight = None
407
408    # Get data: data I, theory I, and data dI in order
409    if isinstance(reference_data, Data2D):
410        if index is None:
411            index = numpy.ones(len(current_data.data), dtype=bool)
412        if weight is not None:
413            current_data.err_data = weight
414        # get rid of zero error points
415        index = index & (current_data.err_data != 0)
416        index = index & (numpy.isfinite(current_data.data))
417        fn = current_data.data[index]
418        gn = reference_data.data[index]
419        en = current_data.err_data[index]
420    else:
421        # 1 d theory from model_thread is only in the range of index
422        if index is None:
423            index = numpy.ones(len(current_data.y), dtype=bool)
424        if weight is not None:
425            current_data.dy = weight
426        if current_data.dy is None or current_data.dy == []:
427            dy = numpy.ones(len(current_data.y))
428        else:
429            ## Set consistently w/AbstractFitengine:
430            # But this should be corrected later.
431            dy = copy.deepcopy(current_data.dy)
432            dy[dy == 0] = 1
433        fn = current_data.y[index]
434        gn = reference_data.y
435        en = dy[index]
436    # Calculate the residual
437    try:
438        res = (fn - gn) / en
439    except ValueError:
440        #print "Chi2 calculations: Unmatched lengths %s, %s, %s" % (len(fn), len(gn), len(en))
441        return None
442
443    residuals = res[numpy.isfinite(res)]
444    chisqr = numpy.average(residuals * residuals)
445
446    return chisqr
447
448def residualsData1D(reference_data, current_data):
449    """
450    Calculate the residuals for difference of two Data1D sets
451    """
452    # temporary default values for index and weight
453    index = None
454    weight = None
455
456    # 1d theory from model_thread is only in the range of index
457    if current_data.dy is None or current_data.dy == []:
458        dy = numpy.ones(len(current_data.y))
459    else:
460        dy = weight if weight is not None else numpy.ones(len(current_data.y))
461        dy[dy == 0] = 1
462    fn = current_data.y[index][0]
463    gn = reference_data.y
464    en = dy[index][0]
465
466    # x values
467    x_current = current_data.x
468    x_reference = reference_data.x
469
470    # build residuals
471    residuals = Data1D()
472    if len(fn) == len(gn):
473        y = (fn - gn)/en
474        residuals.y = -y
475    elif len(fn) > len(gn):
476        residuals.y = (fn - gn[1:len(fn)])/en
477    else:
478        try:
479            y = numpy.zeros(len(current_data.y))
480            begin = 0
481            for i, x_value in enumerate(x_reference):
482                if x_value in x_current:
483                    begin = i
484                    break
485            end = len(x_reference)
486            endl = 0
487            for i, x_value in enumerate(list(x_reference)[::-1]):
488                if x_value in x_current:
489                    endl = i
490                    break
491
492            y = (fn - gn[begin:end-endl])/en
493            residuals.y = y
494        except ValueError:
495            # value errors may show up every once in a while for malformed columns,
496            # just reuse what's there already
497            pass
498
499    residuals.x = current_data.x[index][0]
500    residuals.dy = numpy.ones(len(residuals.y))
501    residuals.dx = None
502    residuals.dxl = None
503    residuals.dxw = None
504    residuals.ytransform = 'y'
505    # For latter scale changes
506    residuals.xaxis('\\rm{Q} ', 'A^{-1}')
507    residuals.yaxis('\\rm{Residuals} ', 'normalized')
508
509    return residuals
510
511def residualsData2D(reference_data, current_data):
512    """
513    Calculate the residuals for difference of two Data2D sets
514    """
515    # temporary default values for index and weight
516    # index = None
517    weight = None
518
519    # build residuals
520    residuals = Data2D()
521    # Not for trunk the line below, instead use the line above
522    current_data.clone_without_data(len(current_data.data), residuals)
523    residuals.data = None
524    fn = current_data.data
525    gn = reference_data.data
526    en = current_data.err_data if weight is None else weight
527    residuals.data = (fn - gn) / en
528    residuals.qx_data = current_data.qx_data
529    residuals.qy_data = current_data.qy_data
530    residuals.q_data = current_data.q_data
531    residuals.err_data = numpy.ones(len(residuals.data))
532    residuals.xmin = min(residuals.qx_data)
533    residuals.xmax = max(residuals.qx_data)
534    residuals.ymin = min(residuals.qy_data)
535    residuals.ymax = max(residuals.qy_data)
536    residuals.q_data = current_data.q_data
537    residuals.mask = current_data.mask
538    residuals.scale = 'linear'
539    # check the lengths
540    if len(residuals.data) != len(residuals.q_data):
541        return None
542    return residuals
543
544def plotResiduals(reference_data, current_data):
545    """
546    Create Data1D/Data2D with residuals, ready for plotting
547    """
548    data_copy = copy.deepcopy(current_data)
549    # Get data: data I, theory I, and data dI in order
550    method_name = current_data.__class__.__name__
551    residuals_dict = {"Data1D": residualsData1D,
552                      "Data2D": residualsData2D}
553
554    try:
555        residuals = residuals_dict[method_name](reference_data, data_copy)
556    except ValueError:
557        return None
558
559    theory_name = str(current_data.name.split()[0])
560    res_name = reference_data.filename if reference_data.filename else reference_data.name
561    residuals.name = "Residuals for " + str(theory_name) + "[" + res_name + "]"
562    residuals.title = residuals.name
563    residuals.ytransform = 'y'
564
565    # when 2 data have the same id override the 1 st plotted
566    # include the last part if keeping charts for separate models is required
567    residuals.id = "res" + str(reference_data.id) # + str(theory_name)
568    # group_id specify on which panel to plot this data
569    group_id = reference_data.group_id
570    residuals.group_id = "res" + str(group_id)
571
572    # Symbol
573    residuals.symbol = 0
574    residuals.hide_error = False
575
576    return residuals
577
578def plotPolydispersities(model):
579    plots = []
580    if model is None:
581        return plots
582    # test for model being a sasmodels.sasview_model.SasviewModel?
583    for name in model.dispersion.keys():
584        xarr, yarr = model.get_weights(name)
585        if len(xarr) <= 1: # param name not found or no polydisp.
586            continue
587        # create Data1D as in residualsData1D() and fill x/y members
588        # similar to FittingLogic._create1DPlot() but different data/axes
589        data1d = Data1D(x=xarr, y=yarr)
590        xunit = model.details[name][0]
591        data1d.xaxis(r'\rm{{{}}}'.format(name.replace('_', '\_')), xunit)
592        data1d.yaxis(r'\rm{weight}', 'normalized')
593        data1d.scale = 'linear'
594        data1d.symbol = 'Line'
595        data1d.name = "{} polydispersity".format(name)
596        data1d.id = data1d.name # placeholder, has to be completed later
597        data1d.plot_role = Data1D.ROLE_RESIDUAL
598        plots.append(data1d)
599    return plots
600
601def binary_encode(i, digits):
602    return [i >> d & 1 for d in range(digits)]
603
604def getWeight(data, is2d, flag=None):
605    """
606    Received flag and compute error on data.
607    :param flag: flag to transform error of data.
608    """
609    weight = None
610    if data is None:
611        return []
612    if is2d:
613        if not hasattr(data, 'err_data'):
614            return []
615        dy_data = data.err_data
616        data = data.data
617    else:
618        if not hasattr(data, 'dy'):
619            return []
620        dy_data = data.dy
621        data = data.y
622
623    if flag == 0:
624        weight = numpy.ones_like(data)
625    elif flag == 1:
626        weight = dy_data
627    elif flag == 2:
628        weight = numpy.sqrt(numpy.abs(data))
629    elif flag == 3:
630        weight = numpy.abs(data)
631    return weight
632
633def updateKernelWithResults(kernel, results):
634    """
635    Takes model kernel and applies results dict to its parameters,
636    returning the modified (deep) copy of the kernel.
637    """
638    assert isinstance(results, dict)
639    local_kernel = copy.deepcopy(kernel)
640
641    for parameter in results.keys():
642        # Update the parameter value - note: this supports +/-inf as well
643        local_kernel.setParam(parameter, results[parameter][0])
644
645    return local_kernel
646
647
648def getStandardParam(model=None):
649    """
650    Returns a list with standard parameters for the current model
651    """
652    param = []
653    num_rows = model.rowCount()
654    if num_rows < 1:
655        return param
656
657    for row in range(num_rows):
658        param_name = model.item(row, 0).text()
659        checkbox_state = model.item(row, 0).checkState() == QtCore.Qt.Checked
660        value = model.item(row, 1).text()
661        column_shift = 0
662        if model.columnCount() == 5: # no error column
663            error_state = False
664            error_value = 0.0
665        else:
666            error_state = True
667            error_value = model.item(row, 2).text()
668            column_shift = 1
669        min_state = True
670        max_state = True
671        min_value = model.item(row, 2+column_shift).text()
672        max_value = model.item(row, 3+column_shift).text()
673        unit = ""
674        if model.item(row, 4+column_shift) is not None:
675            u = model.item(row, 4+column_shift).text()
676            # This isn't a unit if it is a number (polyd./magn.)
677            unit = "" if isNumber(u) else u
678        param.append([checkbox_state, param_name, value, "",
679                     [error_state, error_value],
680                     [min_state, min_value],
681                     [max_state, max_value], unit])
682
683    return param
684
685def isNumber(s):
686    """
687    Checks if string 's' is an int/float
688    """
689    if s.isdigit():
690        # check int
691        return True
692    else:
693        try:
694            # check float
695            _ = float(s)
696        except ValueError:
697            return False
698    return True
699
700def getOrientationParam(kernel_module=None):
701    """
702    Get the dictionary with orientation parameters
703    """
704    param = []
705    if kernel_module is None:
706        return None
707    for param_name in list(kernel_module.params.keys()):
708        name = param_name
709        value = kernel_module.params[param_name]
710        min_state = True
711        max_state = True
712        error_state = False
713        error_value = 0.0
714        checkbox_state = True #??
715        details = kernel_module.details[param_name] #[unit, mix, max]
716        param.append([checkbox_state, name, value, "",
717                     [error_state, error_value],
718                     [min_state, details[1]],
719                     [max_state, details[2]], details[0]])
720
721    return param
722
723def formatParameters(parameters):
724    """
725    Prepare the parameter string in the standard SasView layout
726    """
727    assert parameters is not None
728    assert isinstance(parameters, list)
729    output_string = "sasview_parameter_values:"
730    for parameter in parameters:
731        # recast tuples into strings
732        parameter = [str(p) for p in parameter]
733        output_string += ",".join([p for p in parameter if p is not None])
734        output_string += ":"
735    return output_string
736
737def formatParametersExcel(parameters):
738    """
739    Prepare the parameter string in the Excel format (tab delimited)
740    """
741    assert parameters is not None
742    assert isinstance(parameters, list)
743    crlf = chr(13) + chr(10)
744    tab = chr(9)
745
746    output_string = ""
747    # names
748    names = ""
749    values = ""
750    for parameter in parameters:
751        names += parameter[0]+tab
752        # Add the error column if fitted
753        if parameter[1] == "True" and parameter[3] is not None:
754            names += parameter[0]+"_err"+tab
755
756        values += parameter[2]+tab
757        if parameter[1] == "True" and parameter[3] is not None:
758            values += parameter[3]+tab
759        # add .npts and .nsigmas when necessary
760        if parameter[0][-6:] == ".width":
761            names += parameter[0].replace('.width', '.nsigmas') + tab
762            names += parameter[0].replace('.width', '.npts') + tab
763            values += parameter[5] + tab + parameter[4] + tab
764
765    output_string = names + crlf + values
766    return output_string
767
768def formatParametersLatex(parameters):
769    """
770    Prepare the parameter string in latex
771    """
772    assert parameters is not None
773    assert isinstance(parameters, list)
774    output_string = r'\begin{table}'
775    output_string += r'\begin{tabular}[h]'
776
777    crlf = chr(13) + chr(10)
778    output_string += '{|'
779    output_string += 'l|l|'*len(parameters)
780    output_string += r'}\hline'
781    output_string += crlf
782
783    for index, parameter in enumerate(parameters):
784        name = parameter[0] # Parameter name
785        output_string += name.replace('_', r'\_')  # Escape underscores
786        # Add the error column if fitted
787        if parameter[1] == "True" and parameter[3] is not None:
788            output_string += ' & '
789            output_string += parameter[0]+r'\_err'
790
791        if index < len(parameters) - 1:
792            output_string += ' & '
793
794        # add .npts and .nsigmas when necessary
795        if parameter[0][-6:] == ".width":
796            output_string += parameter[0].replace('.width', '.nsigmas') + ' & '
797            output_string += parameter[0].replace('.width', '.npts')
798
799            if index < len(parameters) - 1:
800                output_string += ' & '
801
802    output_string += r'\\ \hline'
803    output_string += crlf
804
805    # Construct row of values and errors
806    for index, parameter in enumerate(parameters):
807        output_string += parameter[2]
808        if parameter[1] == "True" and parameter[3] is not None:
809            output_string += ' & '
810            output_string += parameter[3]
811
812        if index < len(parameters) - 1:
813            output_string += ' & '
814
815        # add .npts and .nsigmas when necessary
816        if parameter[0][-6:] == ".width":
817            output_string += parameter[5] + ' & '
818            output_string += parameter[4]
819
820            if index < len(parameters) - 1:
821                output_string += ' & '
822
823    output_string += r'\\ \hline'
824    output_string += crlf
825    output_string += r'\end{tabular}'
826    output_string += r'\end{table}'
827
828    return output_string
829
830def isParamPolydisperse(param_name, kernel_params, is2D=False):
831    """
832    Simple lookup for polydispersity for the given param name
833    """
834    parameters = kernel_params.form_volume_parameters
835    if is2D:
836        parameters += kernel_params.orientation_parameters
837    has_poly = False
838    for param in parameters:
839        if param.name==param_name and param.polydisperse:
840            has_poly = True
841            break
842    return has_poly
843
Note: See TracBrowser for help on using the repository browser.