source: sasview/src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py @ 3ae70f9

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 3ae70f9 was 3ae70f9, checked in by ibressler, 6 years ago

plot the polydispersity SASVIEW-1035

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