source: sasview/src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py @ 30bed93

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 30bed93 was 30bed93, checked in by GitHub <noreply@…>, 6 years ago

Merge pull request #181 from SasView?/ESS_GUI_poly_plot2

plot polydispersity (SASVIEW-1035 and trac ticket 17)

  • Property mode set to 100644
File size: 28.3 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            # Always add to the model
371            if row_num is None:
372                model.appendRow(row)
373            else:
374                model.insertRow(row_num, row)
375                row_num += 1
376
377            # Apply combobox if required
378            if None not in (view, cbox):
379                view.setIndexWidget(item2.index(), cbox)
380
381            rows.append(row)
382
383    return rows
384
385def calculateChi2(reference_data, current_data):
386    """
387    Calculate Chi2 value between two sets of data
388    """
389    if reference_data is None or current_data is None:
390        return None
391    # WEIGHING INPUT
392    #from sas.sasgui.perspectives.fitting.utils import get_weight
393    #flag = self.get_weight_flag()
394    #weight = get_weight(data=self.data, is2d=self._is_2D(), flag=flag)
395    chisqr = None
396    if reference_data is None:
397        return chisqr
398
399    # temporary default values for index and weight
400    index = None
401    weight = None
402
403    # Get data: data I, theory I, and data dI in order
404    if isinstance(reference_data, Data2D):
405        if index is None:
406            index = numpy.ones(len(current_data.data), dtype=bool)
407        if weight is not None:
408            current_data.err_data = weight
409        # get rid of zero error points
410        index = index & (current_data.err_data != 0)
411        index = index & (numpy.isfinite(current_data.data))
412        fn = current_data.data[index]
413        gn = reference_data.data[index]
414        en = current_data.err_data[index]
415    else:
416        # 1 d theory from model_thread is only in the range of index
417        if index is None:
418            index = numpy.ones(len(current_data.y), dtype=bool)
419        if weight is not None:
420            current_data.dy = weight
421        if current_data.dy is None or current_data.dy == []:
422            dy = numpy.ones(len(current_data.y))
423        else:
424            ## Set consistently w/AbstractFitengine:
425            # But this should be corrected later.
426            dy = copy.deepcopy(current_data.dy)
427            dy[dy == 0] = 1
428        fn = current_data.y[index]
429        gn = reference_data.y
430        en = dy[index]
431    # Calculate the residual
432    try:
433        res = (fn - gn) / en
434    except ValueError:
435        #print "Chi2 calculations: Unmatched lengths %s, %s, %s" % (len(fn), len(gn), len(en))
436        return None
437
438    residuals = res[numpy.isfinite(res)]
439    chisqr = numpy.average(residuals * residuals)
440
441    return chisqr
442
443def residualsData1D(reference_data, current_data):
444    """
445    Calculate the residuals for difference of two Data1D sets
446    """
447    # temporary default values for index and weight
448    index = None
449    weight = None
450
451    # 1d theory from model_thread is only in the range of index
452    if current_data.dy is None or current_data.dy == []:
453        dy = numpy.ones(len(current_data.y))
454    else:
455        dy = weight if weight is not None else numpy.ones(len(current_data.y))
456        dy[dy == 0] = 1
457    fn = current_data.y[index][0]
458    gn = reference_data.y
459    en = dy[index][0]
460
461    # x values
462    x_current = current_data.x
463    x_reference = reference_data.x
464
465    # build residuals
466    residuals = Data1D()
467    if len(fn) == len(gn):
468        y = (fn - gn)/en
469        residuals.y = -y
470    elif len(fn) > len(gn):
471        residuals.y = (fn - gn[1:len(fn)])/en
472    else:
473        try:
474            y = numpy.zeros(len(current_data.y))
475            begin = 0
476            for i, x_value in enumerate(x_reference):
477                if x_value in x_current:
478                    begin = i
479                    break
480            end = len(x_reference)
481            endl = 0
482            for i, x_value in enumerate(list(x_reference)[::-1]):
483                if x_value in x_current:
484                    endl = i
485                    break
486            # make sure we have correct lengths
487            assert len(x_current) == len(x_reference[begin:end-endl])
488
489            y = (fn - gn[begin:end-endl])/en
490            residuals.y = y
491        except ValueError:
492            # value errors may show up every once in a while for malformed columns,
493            # just reuse what's there already
494            pass
495
496    residuals.x = current_data.x[index][0]
497    residuals.dy = numpy.ones(len(residuals.y))
498    residuals.dx = None
499    residuals.dxl = None
500    residuals.dxw = None
501    residuals.ytransform = 'y'
502    # For latter scale changes
503    residuals.xaxis('\\rm{Q} ', 'A^{-1}')
504    residuals.yaxis('\\rm{Residuals} ', 'normalized')
505
506    return residuals
507
508def residualsData2D(reference_data, current_data):
509    """
510    Calculate the residuals for difference of two Data2D sets
511    """
512    # temporary default values for index and weight
513    # index = None
514    weight = None
515
516    # build residuals
517    residuals = Data2D()
518    # Not for trunk the line below, instead use the line above
519    current_data.clone_without_data(len(current_data.data), residuals)
520    residuals.data = None
521    fn = current_data.data
522    gn = reference_data.data
523    en = current_data.err_data if weight is None else weight
524    residuals.data = (fn - gn) / en
525    residuals.qx_data = current_data.qx_data
526    residuals.qy_data = current_data.qy_data
527    residuals.q_data = current_data.q_data
528    residuals.err_data = numpy.ones(len(residuals.data))
529    residuals.xmin = min(residuals.qx_data)
530    residuals.xmax = max(residuals.qx_data)
531    residuals.ymin = min(residuals.qy_data)
532    residuals.ymax = max(residuals.qy_data)
533    residuals.q_data = current_data.q_data
534    residuals.mask = current_data.mask
535    residuals.scale = 'linear'
536    # check the lengths
537    if len(residuals.data) != len(residuals.q_data):
538        return None
539    return residuals
540
541def plotResiduals(reference_data, current_data):
542    """
543    Create Data1D/Data2D with residuals, ready for plotting
544    """
545    data_copy = copy.deepcopy(current_data)
546    # Get data: data I, theory I, and data dI in order
547    method_name = current_data.__class__.__name__
548    residuals_dict = {"Data1D": residualsData1D,
549                      "Data2D": residualsData2D}
550
551    residuals = residuals_dict[method_name](reference_data, data_copy)
552
553    theory_name = str(current_data.name.split()[0])
554    res_name = reference_data.filename if reference_data.filename else reference_data.name
555    residuals.name = "Residuals for " + str(theory_name) + "[" + res_name + "]"
556    residuals.title = residuals.name
557    residuals.ytransform = 'y'
558
559    # when 2 data have the same id override the 1 st plotted
560    # include the last part if keeping charts for separate models is required
561    residuals.id = "res" + str(reference_data.id) # + str(theory_name)
562    # group_id specify on which panel to plot this data
563    group_id = reference_data.group_id
564    residuals.group_id = "res" + str(group_id)
565
566    # Symbol
567    residuals.symbol = 0
568    residuals.hide_error = False
569
570    return residuals
571
572def plotPolydispersities(model):
573    plots = []
574    if model is None:
575        return plots
576    # test for model being a sasmodels.sasview_model.SasviewModel?
577    for name in model.dispersion.keys():
578        xarr, yarr = model.get_weights(name)
579        if len(xarr) <= 1: # param name not found or no polydisp.
580            continue
581        # create Data1D as in residualsData1D() and fill x/y members
582        # similar to FittingLogic._create1DPlot() but different data/axes
583        data1d = Data1D(x=xarr, y=yarr)
584        xunit = model.details[name][0]
585        data1d.xaxis(r'\rm{{{}}}'.format(name.replace('_', '\_')), xunit)
586        data1d.yaxis(r'\rm{weight}', 'normalized')
587        data1d.scale = 'linear'
588        data1d.symbol = 'Line'
589        data1d.name = "{} polydispersity".format(name)
590        data1d.id = data1d.name # placeholder, has to be completed later
591        data1d.plot_role = Data1D.ROLE_RESIDUAL
592        plots.append(data1d)
593    return plots
594
595def binary_encode(i, digits):
596    return [i >> d & 1 for d in range(digits)]
597
598def getWeight(data, is2d, flag=None):
599    """
600    Received flag and compute error on data.
601    :param flag: flag to transform error of data.
602    """
603    weight = None
604    if data is None:
605        return []
606    if is2d:
607        if not hasattr(data, 'err_data'):
608            return []
609        dy_data = data.err_data
610        data = data.data
611    else:
612        if not hasattr(data, 'dy'):
613            return []
614        dy_data = data.dy
615        data = data.y
616
617    if flag == 0:
618        weight = numpy.ones_like(data)
619    elif flag == 1:
620        weight = dy_data
621    elif flag == 2:
622        weight = numpy.sqrt(numpy.abs(data))
623    elif flag == 3:
624        weight = numpy.abs(data)
625    return weight
626
627def updateKernelWithResults(kernel, results):
628    """
629    Takes model kernel and applies results dict to its parameters,
630    returning the modified (deep) copy of the kernel.
631    """
632    assert isinstance(results, dict)
633    local_kernel = copy.deepcopy(kernel)
634
635    for parameter in results.keys():
636        # Update the parameter value - note: this supports +/-inf as well
637        local_kernel.setParam(parameter, results[parameter][0])
638
639    return local_kernel
640
641
642def getStandardParam(model=None):
643    """
644    Returns a list with standard parameters for the current model
645    """
646    param = []
647    num_rows = model.rowCount()
648    if num_rows < 1:
649        return None
650
651    for row in range(num_rows):
652        param_name = model.item(row, 0).text()
653        checkbox_state = model.item(row, 0).checkState() == QtCore.Qt.Checked
654        value = model.item(row, 1).text()
655        column_shift = 0
656        if model.columnCount() == 5: # no error column
657            error_state = False
658            error_value = 0.0
659        else:
660            error_state = True
661            error_value = model.item(row, 2).text()
662            column_shift = 1
663        min_state = True
664        max_state = True
665        min_value = model.item(row, 2+column_shift).text()
666        max_value = model.item(row, 3+column_shift).text()
667        unit = ""
668        if model.item(row, 4+column_shift) is not None:
669            unit = model.item(row, 4+column_shift).text()
670
671        param.append([checkbox_state, param_name, value, "",
672                        [error_state, error_value],
673                        [min_state, min_value],
674                        [max_state, max_value], unit])
675
676    return param
677
678def getOrientationParam(kernel_module=None):
679    """
680    Get the dictionary with orientation parameters
681    """
682    param = []
683    if kernel_module is None:
684        return None
685    for param_name in list(kernel_module.params.keys()):
686        name = param_name
687        value = kernel_module.params[param_name]
688        min_state = True
689        max_state = True
690        error_state = False
691        error_value = 0.0
692        checkbox_state = True #??
693        details = kernel_module.details[param_name] #[unit, mix, max]
694        param.append([checkbox_state, name, value, "",
695                     [error_state, error_value],
696                     [min_state, details[1]],
697                     [max_state, details[2]], details[0]])
698
699    return param
700
701def formatParameters(parameters):
702    """
703    Prepare the parameter string in the standard SasView layout
704    """
705    assert parameters is not None
706    assert isinstance(parameters, list)
707    output_string = "sasview_parameter_values:"
708    for parameter in parameters:
709        output_string += ",".join([p for p in parameter if p is not None])
710        output_string += ":"
711    return output_string
712
713def formatParametersExcel(parameters):
714    """
715    Prepare the parameter string in the Excel format (tab delimited)
716    """
717    assert parameters is not None
718    assert isinstance(parameters, list)
719    crlf = chr(13) + chr(10)
720    tab = chr(9)
721
722    output_string = ""
723    # names
724    names = ""
725    values = ""
726    for parameter in parameters:
727        names += parameter[0]+tab
728        # Add the error column if fitted
729        if parameter[1] == "True" and parameter[3] is not None:
730            names += parameter[0]+"_err"+tab
731
732        values += parameter[2]+tab
733        if parameter[1] == "True" and parameter[3] is not None:
734            values += parameter[3]+tab
735        # add .npts and .nsigmas when necessary
736        if parameter[0][-6:] == ".width":
737            names += parameter[0].replace('.width', '.nsigmas') + tab
738            names += parameter[0].replace('.width', '.npts') + tab
739            values += parameter[5] + tab + parameter[4] + tab
740
741    output_string = names + crlf + values
742    return output_string
743
744def formatParametersLatex(parameters):
745    """
746    Prepare the parameter string in latex
747    """
748    assert parameters is not None
749    assert isinstance(parameters, list)
750    output_string = r'\begin{table}'
751    output_string += r'\begin{tabular}[h]'
752
753    crlf = chr(13) + chr(10)
754    output_string += '{|'
755    output_string += 'l|l|'*len(parameters)
756    output_string += r'}\hline'
757    output_string += crlf
758
759    for index, parameter in enumerate(parameters):
760        name = parameter[0] # Parameter name
761        output_string += name.replace('_', r'\_')  # Escape underscores
762        # Add the error column if fitted
763        if parameter[1] == "True" and parameter[3] is not None:
764            output_string += ' & '
765            output_string += parameter[0]+r'\_err'
766
767        if index < len(parameters) - 1:
768            output_string += ' & '
769
770        # add .npts and .nsigmas when necessary
771        if parameter[0][-6:] == ".width":
772            output_string += parameter[0].replace('.width', '.nsigmas') + ' & '
773            output_string += parameter[0].replace('.width', '.npts')
774
775            if index < len(parameters) - 1:
776                output_string += ' & '
777
778    output_string += r'\\ \hline'
779    output_string += crlf
780
781    # Construct row of values and errors
782    for index, parameter in enumerate(parameters):
783        output_string += parameter[2]
784        if parameter[1] == "True" and parameter[3] is not None:
785            output_string += ' & '
786            output_string += parameter[3]
787
788        if index < len(parameters) - 1:
789            output_string += ' & '
790
791        # add .npts and .nsigmas when necessary
792        if parameter[0][-6:] == ".width":
793            output_string += parameter[5] + ' & '
794            output_string += parameter[4]
795
796            if index < len(parameters) - 1:
797                output_string += ' & '
798
799    output_string += r'\\ \hline'
800    output_string += crlf
801    output_string += r'\end{tabular}'
802    output_string += r'\end{table}'
803
804    return output_string
805
806def isParamPolydisperse(param_name, kernel_params, is2D=False):
807    """
808    Simple lookup for polydispersity for the given param name
809    """
810    parameters = kernel_params.form_volume_parameters
811    if is2D:
812        parameters += kernel_params.orientation_parameters
813    has_poly = False
814    for param in parameters:
815        if param.name==param_name and param.polydisperse:
816            has_poly = True
817            break
818    return has_poly
819
Note: See TracBrowser for help on using the repository browser.