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

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

plotPolydispersities(): used param unit provided by the model

  • Property mode set to 100644
File size: 28.9 KB
RevLine 
[fde5bcd]1import copy
[1bc27f1]2
[4992ff2]3from PyQt5 import QtCore
4from PyQt5 import QtGui
[4d457df]5
[6fd4e36]6import numpy
7
[dc5ef15]8from sas.qtgui.Plotting.PlotterData import Data1D
9from sas.qtgui.Plotting.PlotterData import Data2D
[6fd4e36]10
[04f775d]11from sas.qtgui.Perspectives.Fitting.AssociatedComboBox import AssociatedComboBox
12
[f54ce30]13model_header_captions = ['Parameter', 'Value', 'Min', 'Max', 'Units']
14
15model_header_tooltips = ['Select parameter for fitting',
[d0dfcb2]16                         'Enter parameter value',
17                         'Enter minimum value for parameter',
18                         'Enter maximum value for parameter',
19                         'Unit of the parameter']
[f54ce30]20
21poly_header_captions = ['Parameter', 'PD[ratio]', 'Min', 'Max', 'Npts', 'Nsigs',
[d0dfcb2]22                        'Function', 'Filename']
[f54ce30]23
24poly_header_tooltips = ['Select parameter for fitting',
[1a15ada]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',
[d0dfcb2]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']
[f54ce30]34
35error_tooltip = 'Error value for fitted parameter'
36header_error_caption = 'Error'
37
[4d457df]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    """
[b3e8629]49    return list([par for par in model.iq_parameters if "[" in par.name])
[4d457df]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)
[a9b568c]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)
[4d457df]65
[04f775d]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.
[4d457df]72    """
[04f775d]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
[04ce9ac]78    if isinstance(param.choices, (list, tuple)) and len(param.choices) > 0:
[04f775d]79        # The choices property is concrete in sasmodels, probably will use this
80        choices = param.choices
[04ce9ac]81    elif isinstance(param.units, (list, tuple)):
82        choices = [str(x) for x in param.units]
[04f775d]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
[a758043]94def addParametersToModel(parameters, kernel_module, is2D, model=None, view=None):
[4d457df]95    """
[a758043]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.
[4d457df]99    """
100    multishell_parameters = getIterParams(parameters)
101    multishell_param_name, _ = getMultiplicity(parameters)
[57be490]102
[b5cc06e]103    if is2D:
104        params = [p for p in parameters.kernel_parameters if p.type != 'magnetic']
105    else:
[8b745c36]106        params = parameters.iq_parameters
[04f775d]107
[a758043]108    rows = []
[1970780]109    for param in params:
[4d457df]110        # don't include shell parameters
111        if param.name == multishell_param_name:
112            continue
[04f775d]113
[4d457df]114        # Modify parameter name from <param>[n] to <param>1
115        item_name = param.name
116        if param in multishell_parameters:
[b1e36a3]117            continue
[4d457df]118
119        item1 = QtGui.QStandardItem(item_name)
120        item1.setCheckable(True)
[2add354]121        item1.setEditable(False)
[04f775d]122
[4d457df]123        # check for polydisp params
124        if param.polydisperse:
125            poly_item = QtGui.QStandardItem("Polydispersity")
[2add354]126            poly_item.setEditable(False)
[4d457df]127            item1_1 = QtGui.QStandardItem("Distribution")
[2add354]128            item1_1.setEditable(False)
[04f775d]129
[4d457df]130            # Find param in volume_params
[6889ba2]131            poly_pars = copy.deepcopy(parameters.form_volume_parameters)
[f3cc979]132            if is2D:
133                poly_pars += parameters.orientation_parameters
134            for p in poly_pars:
[4d457df]135                if p.name != param.name:
136                    continue
[aca8418]137                width = kernel_module.getParam(p.name+'.width')
[8e2cd79]138                ptype = kernel_module.getParam(p.name+'.type')
[aca8418]139                item1_2 = QtGui.QStandardItem(str(width))
[2add354]140                item1_2.setEditable(False)
[aca8418]141                item1_3 = QtGui.QStandardItem()
[2add354]142                item1_3.setEditable(False)
[aca8418]143                item1_4 = QtGui.QStandardItem()
[2add354]144                item1_4.setEditable(False)
[8e2cd79]145                item1_5 = QtGui.QStandardItem(ptype)
[2add354]146                item1_5.setEditable(False)
[4d457df]147                poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5])
148                break
[04f775d]149
[4d457df]150            # Add the polydisp item as a child
151            item1.appendRow([poly_item])
[04f775d]152
[4d457df]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]))
[04f775d]157        item5 = QtGui.QStandardItem(str(param.units))
[2add354]158        item5.setEditable(False)
[4d457df]159
[04f775d]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
[a758043]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
[04f775d]172
[01b4877]173def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=None, row_num=None):
[4d457df]174    """
[04f775d]175    Update local ModelModel with sasmodel parameters (non-dispersed, non-magnetic)
[bc7371fd]176    Actually appends to model, if model and view params are not None.
177    Always returns list of lists of QStandardItems.
[b69b549]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)
[4d457df]181    """
[b5cc06e]182    if is2D:
183        params = [p for p in parameters.kernel_parameters if p.type != 'magnetic']
184    else:
185        params = parameters.iq_parameters
[04f775d]186
[700b03b]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
[a758043]199    rows = []
[700b03b]200    for param, param_orig in zip(params, params_orig):
[7248d75d]201        # Create the top level, checkable item
[700b03b]202        item_name = param_orig.name
[4d457df]203        item1 = QtGui.QStandardItem(item_name)
[700b03b]204        item1.setData(param.name, QtCore.Qt.UserRole)
[4d457df]205        item1.setCheckable(True)
[2add354]206        item1.setEditable(False)
[04f775d]207
[4d457df]208        # Param values
[2add354]209        # TODO: add delegate for validation of cells
[4d457df]210        item2 = QtGui.QStandardItem(str(param.default))
[04f775d]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
[a758043]221        if None not in (model, view):
[01b4877]222            if row_num is None:
223                model.appendRow(row)
224            else:
225                model.insertRow(row_num, row)
226                row_num += 1
227
[a758043]228            if cbox:
229                view.setIndexWidget(item2.index(), cbox)
[01b4877]230
[a758043]231        rows.append(row)
232
233    return rows
[4d457df]234
[18d5c94a]235def markParameterDisabled(model, row):
[b87dc1a]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)]
[18d5c94a]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
[4d457df]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
[00b7ddf0]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
[4d457df]284def addHeadersToModel(model):
285    """
286    Adds predefined headers to the model
287    """
[f54ce30]288    for i, item in enumerate(model_header_captions):
[b3e8629]289        model.setHeaderData(i, QtCore.Qt.Horizontal, item)
[f54ce30]290
[fde5bcd]291    model.header_tooltips = copy.copy(model_header_tooltips)
[4d457df]292
[f182f93]293def addErrorHeadersToModel(model):
294    """
295    Adds predefined headers to the model
296    """
[fde5bcd]297    model_header_error_captions = copy.copy(model_header_captions)
[f54ce30]298    model_header_error_captions.insert(2, header_error_caption)
299    for i, item in enumerate(model_header_error_captions):
[b3e8629]300        model.setHeaderData(i, QtCore.Qt.Horizontal, item)
[f182f93]301
[fde5bcd]302    model_header_error_tooltips = copy.copy(model_header_tooltips)
[f54ce30]303    model_header_error_tooltips.insert(2, error_tooltip)
[fde5bcd]304    model.header_tooltips = copy.copy(model_header_error_tooltips)
[a95c44b]305
[4d457df]306def addPolyHeadersToModel(model):
307    """
308    Adds predefined headers to the model
309    """
[f54ce30]310    for i, item in enumerate(poly_header_captions):
[b3e8629]311        model.setHeaderData(i, QtCore.Qt.Horizontal, item)
[f54ce30]312
[fde5bcd]313    model.header_tooltips = copy.copy(poly_header_tooltips)
[4d457df]314
[a95c44b]315
[aca8418]316def addErrorPolyHeadersToModel(model):
317    """
318    Adds predefined headers to the model
319    """
[fde5bcd]320    poly_header_error_captions = copy.copy(poly_header_captions)
[f54ce30]321    poly_header_error_captions.insert(2, header_error_caption)
322    for i, item in enumerate(poly_header_error_captions):
[b3e8629]323        model.setHeaderData(i, QtCore.Qt.Horizontal, item)
[f54ce30]324
[fde5bcd]325    poly_header_error_tooltips = copy.copy(poly_header_tooltips)
[f54ce30]326    poly_header_error_tooltips.insert(2, error_tooltip)
[fde5bcd]327    model.header_tooltips = copy.copy(poly_header_error_tooltips)
[a95c44b]328
[b69b549]329def addShellsToModel(parameters, model, index, row_num=None, view=None):
[4d457df]330    """
[70f4458]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.
[b69b549]333    If view param is not None, supports fixed-choice params.
[70f4458]334    Returns a list of lists of QStandardItem objects.
[4d457df]335    """
336    multishell_parameters = getIterParams(parameters)
337
[a758043]338    rows = []
[b3e8629]339    for i in range(index):
[4d457df]340        for par in multishell_parameters:
[b1e36a3]341            # Create the name: <param>[<i>], e.g. "sld1" for parameter "sld[n]"
342            param_name = replaceShellName(par.name, i+1)
[4d457df]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]))
[88ada06]356                    item1_5 = QtGui.QStandardItem(str(p.units))
[4d457df]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]))
[88ada06]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
[b69b549]371            # Always add to the model
[70f4458]372            if row_num is None:
373                model.appendRow(row)
374            else:
375                model.insertRow(row_num, row)
376                row_num += 1
[a758043]377
378            # Apply combobox if required
379            if None not in (view, cbox):
[88ada06]380                view.setIndexWidget(item2.index(), cbox)
[4d457df]381
[a758043]382            rows.append(row)
383
384    return rows
[4d457df]385
[6fd4e36]386def calculateChi2(reference_data, current_data):
387    """
388    Calculate Chi2 value between two sets of data
389    """
[ff3b293]390    if reference_data is None or current_data is None:
391        return None
[6fd4e36]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)
[1bc27f1]396    chisqr = None
397    if reference_data is None:
398        return chisqr
[6fd4e36]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):
[1bc27f1]406        if index is None:
[6fd4e36]407            index = numpy.ones(len(current_data.data), dtype=bool)
[1bc27f1]408        if weight is not None:
[6fd4e36]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
[1bc27f1]418        if index is None:
[6fd4e36]419            index = numpy.ones(len(current_data.y), dtype=bool)
[1bc27f1]420        if weight is not None:
[6fd4e36]421            current_data.dy = weight
[1bc27f1]422        if current_data.dy is None or current_data.dy == []:
[6fd4e36]423            dy = numpy.ones(len(current_data.y))
424        else:
425            ## Set consistently w/AbstractFitengine:
426            # But this should be corrected later.
[fde5bcd]427            dy = copy.deepcopy(current_data.dy)
[6fd4e36]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:
[180bd54]436        #print "Chi2 calculations: Unmatched lengths %s, %s, %s" % (len(fn), len(gn), len(en))
[0268aed]437        return None
[6fd4e36]438
439    residuals = res[numpy.isfinite(res)]
440    chisqr = numpy.average(residuals * residuals)
441
442    return chisqr
443
[0268aed]444def residualsData1D(reference_data, current_data):
445    """
[7d077d1]446    Calculate the residuals for difference of two Data1D sets
[0268aed]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
[180bd54]453    if current_data.dy is None or current_data.dy == []:
[0268aed]454        dy = numpy.ones(len(current_data.y))
455    else:
[180bd54]456        dy = weight if weight is not None else numpy.ones(len(current_data.y))
[0268aed]457        dy[dy == 0] = 1
458    fn = current_data.y[index][0]
459    gn = reference_data.y
460    en = dy[index][0]
[f7d39c9]461
462    # x values
463    x_current = current_data.x
464    x_reference = reference_data.x
465
[0268aed]466    # build residuals
467    residuals = Data1D()
[180bd54]468    if len(fn) == len(gn):
[0268aed]469        y = (fn - gn)/en
470        residuals.y = -y
[f7d39c9]471    elif len(fn) > len(gn):
472        residuals.y = (fn - gn[1:len(fn)])/en
[180bd54]473    else:
[689222c]474        try:
[f7d39c9]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
[689222c]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
[180bd54]496
[0268aed]497    residuals.x = current_data.x[index][0]
[f6c19cf]498    residuals.dy = numpy.ones(len(residuals.y))
[0268aed]499    residuals.dx = None
500    residuals.dxl = None
501    residuals.dxw = None
502    residuals.ytransform = 'y'
[1bc27f1]503    # For latter scale changes
[0268aed]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    """
[7d077d1]511    Calculate the residuals for difference of two Data2D sets
[0268aed]512    """
513    # temporary default values for index and weight
[1bc27f1]514    # index = None
[0268aed]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
[180bd54]524    en = current_data.err_data if weight is None else weight
[0268aed]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    """
[fde5bcd]546    data_copy = copy.deepcopy(current_data)
[0268aed]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])
[6b50296]555    res_name = reference_data.filename if reference_data.filename else reference_data.name
556    residuals.name = "Residuals for " + str(theory_name) + "[" + res_name + "]"
[0268aed]557    residuals.title = residuals.name
[f182f93]558    residuals.ytransform = 'y'
559
[0268aed]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)
[1bc27f1]566
[0268aed]567    # Symbol
568    residuals.symbol = 0
569    residuals.hide_error = False
570
571    return residuals
572
[3ae70f9]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])
[db500cb]594        xunit = ""
595        if name in model.details and len(model.details[name]):
596            xunit = model.details[name][0]
597        data1d.xaxis('\\rm{{{}}}'.format(name.replace('_', '\_')), xunit)
[3ae70f9]598        data1d.yaxis('\\rm{{{weight}}}', 'normalized')
599        data1d.scale = 'linear'
600        data1d.symbol = 'Line'
601        data1d.name = "{} polydispersity".format(name)
602        data1d.id = data1d.name # placeholder, has to be completed later
[5990185]603        data1d.plot_role = Data1D.ROLE_RESIDUAL
[3ae70f9]604        plots.append(data1d)
605    return plots
606
[6fd4e36]607def binary_encode(i, digits):
[b3e8629]608    return [i >> d & 1 for d in range(digits)]
[6fd4e36]609
[fd1ae6d1]610def getWeight(data, is2d, flag=None):
611    """
612    Received flag and compute error on data.
613    :param flag: flag to transform error of data.
614    """
615    weight = None
[b764ae5]616    if data is None:
617        return []
[fd1ae6d1]618    if is2d:
[b764ae5]619        if not hasattr(data, 'err_data'):
620            return []
[fd1ae6d1]621        dy_data = data.err_data
622        data = data.data
623    else:
[b764ae5]624        if not hasattr(data, 'dy'):
625            return []
[fd1ae6d1]626        dy_data = data.dy
627        data = data.y
628
629    if flag == 0:
630        weight = numpy.ones_like(data)
631    elif flag == 1:
632        weight = dy_data
633    elif flag == 2:
634        weight = numpy.sqrt(numpy.abs(data))
635    elif flag == 3:
636        weight = numpy.abs(data)
637    return weight
[d4dac80]638
639def updateKernelWithResults(kernel, results):
640    """
641    Takes model kernel and applies results dict to its parameters,
642    returning the modified (deep) copy of the kernel.
643    """
[8e2cd79]644    assert isinstance(results, dict)
[d4dac80]645    local_kernel = copy.deepcopy(kernel)
646
647    for parameter in results.keys():
648        # Update the parameter value - note: this supports +/-inf as well
649        local_kernel.setParam(parameter, results[parameter][0])
650
651    return local_kernel
652
653
[57be490]654def getStandardParam(model=None):
655    """
656    Returns a list with standard parameters for the current model
657    """
658    param = []
659    num_rows = model.rowCount()
660    if num_rows < 1:
661        return None
662
663    for row in range(num_rows):
664        param_name = model.item(row, 0).text()
[8e2cd79]665        checkbox_state = model.item(row, 0).checkState() == QtCore.Qt.Checked
666        value = model.item(row, 1).text()
[57be490]667        column_shift = 0
668        if model.columnCount() == 5: # no error column
669            error_state = False
670            error_value = 0.0
671        else:
672            error_state = True
673            error_value = model.item(row, 2).text()
674            column_shift = 1
675        min_state = True
676        max_state = True
677        min_value = model.item(row, 2+column_shift).text()
678        max_value = model.item(row, 3+column_shift).text()
679        unit = ""
680        if model.item(row, 4+column_shift) is not None:
681            unit = model.item(row, 4+column_shift).text()
682
683        param.append([checkbox_state, param_name, value, "",
684                        [error_state, error_value],
685                        [min_state, min_value],
686                        [max_state, max_value], unit])
687
688    return param
689
690def getOrientationParam(kernel_module=None):
691    """
692    Get the dictionary with orientation parameters
693    """
694    param = []
[8e2cd79]695    if kernel_module is None:
[57be490]696        return None
697    for param_name in list(kernel_module.params.keys()):
698        name = param_name
699        value = kernel_module.params[param_name]
700        min_state = True
701        max_state = True
702        error_state = False
703        error_value = 0.0
704        checkbox_state = True #??
705        details = kernel_module.details[param_name] #[unit, mix, max]
706        param.append([checkbox_state, name, value, "",
707                     [error_state, error_value],
708                     [min_state, details[1]],
709                     [max_state, details[2]], details[0]])
710
711    return param
[8e2cd79]712
713def formatParameters(parameters):
714    """
715    Prepare the parameter string in the standard SasView layout
716    """
717    assert parameters is not None
718    assert isinstance(parameters, list)
719    output_string = "sasview_parameter_values:"
720    for parameter in parameters:
721        output_string += ",".join([p for p in parameter if p is not None])
722        output_string += ":"
723    return output_string
724
725def formatParametersExcel(parameters):
726    """
727    Prepare the parameter string in the Excel format (tab delimited)
728    """
729    assert parameters is not None
730    assert isinstance(parameters, list)
731    crlf = chr(13) + chr(10)
732    tab = chr(9)
733
734    output_string = ""
735    # names
736    names = ""
737    values = ""
738    for parameter in parameters:
739        names += parameter[0]+tab
740        # Add the error column if fitted
741        if parameter[1] == "True" and parameter[3] is not None:
742            names += parameter[0]+"_err"+tab
743
744        values += parameter[2]+tab
745        if parameter[1] == "True" and parameter[3] is not None:
746            values += parameter[3]+tab
747        # add .npts and .nsigmas when necessary
748        if parameter[0][-6:] == ".width":
749            names += parameter[0].replace('.width', '.nsigmas') + tab
750            names += parameter[0].replace('.width', '.npts') + tab
751            values += parameter[5] + tab + parameter[4] + tab
752
753    output_string = names + crlf + values
754    return output_string
755
756def formatParametersLatex(parameters):
757    """
758    Prepare the parameter string in latex
759    """
760    assert parameters is not None
761    assert isinstance(parameters, list)
762    output_string = r'\begin{table}'
763    output_string += r'\begin{tabular}[h]'
764
765    crlf = chr(13) + chr(10)
766    output_string += '{|'
767    output_string += 'l|l|'*len(parameters)
768    output_string += r'}\hline'
769    output_string += crlf
770
771    for index, parameter in enumerate(parameters):
772        name = parameter[0] # Parameter name
773        output_string += name.replace('_', r'\_')  # Escape underscores
774        # Add the error column if fitted
775        if parameter[1] == "True" and parameter[3] is not None:
776            output_string += ' & '
777            output_string += parameter[0]+r'\_err'
778
779        if index < len(parameters) - 1:
780            output_string += ' & '
781
782        # add .npts and .nsigmas when necessary
783        if parameter[0][-6:] == ".width":
784            output_string += parameter[0].replace('.width', '.nsigmas') + ' & '
785            output_string += parameter[0].replace('.width', '.npts')
786
787            if index < len(parameters) - 1:
788                output_string += ' & '
789
790    output_string += r'\\ \hline'
791    output_string += crlf
792
793    # Construct row of values and errors
794    for index, parameter in enumerate(parameters):
795        output_string += parameter[2]
796        if parameter[1] == "True" and parameter[3] is not None:
797            output_string += ' & '
798            output_string += parameter[3]
799
800        if index < len(parameters) - 1:
801            output_string += ' & '
802
803        # add .npts and .nsigmas when necessary
804        if parameter[0][-6:] == ".width":
805            output_string += parameter[5] + ' & '
806            output_string += parameter[4]
807
808            if index < len(parameters) - 1:
809                output_string += ' & '
810
811    output_string += r'\\ \hline'
812    output_string += crlf
813    output_string += r'\end{tabular}'
814    output_string += r'\end{table}'
815
816    return output_string
[305114c]817
818def isParamPolydisperse(param_name, kernel_params, is2D=False):
819    """
820    Simple lookup for polydispersity for the given param name
821    """
822    parameters = kernel_params.form_volume_parameters
823    if is2D:
824        parameters += kernel_params.orientation_parameters
825    has_poly = False
826    for param in parameters:
827        if param.name==param_name and param.polydisperse:
828            has_poly = True
829            break
830    return has_poly
831
Note: See TracBrowser for help on using the repository browser.