source: sasmodels/sasmodels/convert.py @ 7ae2b7f

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 7ae2b7f was 7ae2b7f, checked in by Paul Kienzle <pkienzle@…>, 8 years ago

still more linting; ignore numpy types

  • Property mode set to 100644
File size: 8.8 KB
Line 
1"""
2Convert models to and from sasview.
3"""
4from os.path import join as joinpath, abspath, dirname
5import warnings
6import json
7
8# List of models which SasView versions don't contain the explicit 'scale' argument.
9# When converting such a model, please update this list.
10MODELS_WITHOUT_SCALE = [
11    'teubner_strey',
12    'broad_peak',
13    'two_lorentzian',
14    "two_power_law",
15    'gel_fit',
16    'gauss_lorentz_gel',
17    'be_polyelectrolyte',
18    'correlation_length',
19    'fractal_core_shell',
20    'binary_hard_sphere',
21    'raspberry'
22]
23
24# List of models which SasView versions don't contain the explicit 'background' argument.
25# When converting such a model, please update this list.
26MODELS_WITHOUT_BACKGROUND = [
27    'guinier',
28]
29
30# Convert new style names for polydispersity info to old style names
31PD_DOT = [
32    ("", ""),
33    ("_pd", ".width"),
34    ("_pd_n", ".npts"),
35    ("_pd_nsigma", ".nsigmas"),
36    ("_pd_type", ".type"),
37    ]
38
39CONVERSION_TABLE = None
40
41def _read_conversion_table():
42    global CONVERSION_TABLE
43    if CONVERSION_TABLE is None:
44        path = joinpath(dirname(abspath(__file__)), "convert.json")
45        with open(path) as fid:
46            CONVERSION_TABLE = json_load_byteified(fid)
47
48def json_load_byteified(file_handle):
49    return _byteify(
50        json.load(file_handle, object_hook=_byteify),
51        ignore_dicts=True
52    )
53
54def _byteify(data, ignore_dicts = False):
55    # if this is a unicode string, return its string representation
56    if isinstance(data, unicode):
57        return data.encode('utf-8')
58    # if this is a list of values, return list of byteified values
59    if isinstance(data, list):
60        return [ _byteify(item, ignore_dicts=True) for item in data ]
61    # if this is a dictionary, return dictionary of byteified keys and values
62    # but only if we haven't already byteified it
63    if isinstance(data, dict) and not ignore_dicts:
64        return dict((_byteify(key, ignore_dicts=True),
65                     _byteify(value, ignore_dicts=True))
66                    for key, value in data.items())
67    # if it's anything else, return it in its original form
68    return data
69
70
71def _convert_pars(pars, mapping):
72    """
73    Rename the parameters and any associated polydispersity attributes.
74    """
75    newpars = pars.copy()
76    for new, old in mapping.items():
77        if old == new: continue
78        for pd, dot in PD_DOT:
79            if old+dot in newpars:
80                if new is not None:
81                    newpars[new+pd] = pars[old+dot]
82                del newpars[old+dot]
83    return newpars
84
85def _rescale_sld(pars):
86    """
87    rescale all sld parameters in the new model definition by 1e6 so the
88    numbers are nicer.  Relies on the fact that all sld parameters in the
89    new model definition end with sld.
90    """
91    return dict((p, (v*1e6 if p.endswith('sld')
92                     else v*1e-15 if 'ndensity' in p
93                     else v))
94                for p, v in pars.items())
95
96def convert_model(name, pars):
97    """
98    Convert model from old style parameter names to new style.
99    """
100    _, _ = name, pars # lint
101    raise NotImplementedError
102    # need to load all new models in order to determine old=>new
103    # model name mapping
104
105def _unscale_sld(pars):
106    """
107    rescale all sld parameters in the new model definition by 1e6 so the
108    numbers are nicer.  Relies on the fact that all sld parameters in the
109    new model definition end with sld.
110    """
111    return dict((p, (v*1e-6 if p.startswith('sld') or p.endswith('sld')
112                     else v*1e15 if 'ndensity' in p
113                     else v))
114                for p, v in pars.items())
115
116def _remove_pd(pars, key, name):
117    """
118    Remove polydispersity from the parameter list.
119
120    Note: operates in place
121    """
122    # Bumps style parameter names
123    pd = pars.pop(key+".width", 0.0)
124    pd_n = pars.pop(key+".npts", 0)
125    if pd != 0.0 and pd_n != 0:
126        warnings.warn("parameter %s not polydisperse in sasview %s"%(key, name))
127    pars.pop(key+".nsigmas", None)
128    pars.pop(key+".type", None)
129    return pars
130
131def _revert_pars(pars, mapping):
132    """
133    Rename the parameters and any associated polydispersity attributes.
134    """
135    newpars = pars.copy()
136
137    for new, old in mapping.items():
138        for pd, dot in PD_DOT:
139            if old and old+pd == new+dot:
140                continue
141            if new+pd in newpars:
142                if old is not None:
143                    newpars[old+dot] = pars[new+pd]
144                del newpars[new+pd]
145    for k in list(newpars.keys()):
146        for pd, dot in PD_DOT[1:]:  # skip "" => ""
147            if k.endswith(pd):
148                newpars[k[:-len(pd)]+dot] = newpars[k]
149                del newpars[k]
150    return newpars
151
152def revert_name(model_info):
153    _read_conversion_table()
154    oldname, oldpars = CONVERSION_TABLE.get(model_info.id, [None, {}])
155    return oldname
156
157def _get_old_pars(model_info):
158    _read_conversion_table()
159    oldname, oldpars = CONVERSION_TABLE.get(model_info.id, [None, {}])
160    return oldpars
161
162def revert_pars(model_info, pars):
163    """
164    Convert model from new style parameter names to old style.
165    """
166    if model_info.composition is not None:
167        composition_type, parts = model_info.composition
168        if composition_type == 'product':
169            P, S = parts
170            oldpars = {'scale':'scale_factor'}
171            oldpars.update(_get_old_pars(P))
172            oldpars.update(_get_old_pars(S))
173        else:
174            raise NotImplementedError("cannot convert to sasview sum")
175    else:
176        oldpars = _get_old_pars(model_info)
177    oldpars = _revert_pars(_unscale_sld(pars), oldpars)
178
179
180    # Note: update compare.constrain_pars to match
181    name = model_info.id
182    if name in MODELS_WITHOUT_SCALE or model_info.structure_factor:
183        if oldpars.pop('scale', 1.0) != 1.0:
184            warnings.warn("parameter scale not used in sasview %s"%name)
185    if name in MODELS_WITHOUT_BACKGROUND or model_info.structure_factor:
186        if oldpars.pop('background', 0.0) != 0.0:
187            warnings.warn("parameter background not used in sasview %s"%name)
188
189
190    # If it is a product model P*S, then check the individual forms for special
191    # cases.  Note: despite the structure factor alone not having scale or
192    # background, the product model does, so this is below the test for
193    # models without scale or background.
194    namelist = name.split('*') if '*' in name else [name]
195    for name in namelist:
196        if name == 'stacked_disks':
197            _remove_pd(oldpars, 'n_stacking', name)
198        elif name == 'pearl_necklace':
199            _remove_pd(oldpars, 'num_pearls', name)
200            _remove_pd(oldpars, 'thick_string', name)
201        elif name == 'core_shell_parallelepiped':
202            _remove_pd(oldpars, 'rimA', name)
203            _remove_pd(oldpars, 'rimB', name)
204            _remove_pd(oldpars, 'rimC', name)
205        elif name == 'rpa':
206            # convert scattering lengths from femtometers to centimeters
207            for p in "L1", "L2", "L3", "L4":
208                if p in oldpars: oldpars[p] *= 1e-13
209        elif name == 'core_shell_parallelepiped':
210            _remove_pd(oldpars, 'rimA', name)
211        elif name in ['mono_gauss_coil','poly_gauss_coil']:
212            del oldpars['i_zero']
213        elif name == 'fractal':
214            del oldpars['volfraction']
215        elif name == 'vesicle':
216            del oldpars['volfraction']
217        elif name == 'multilayer_vesicle':
218            del oldpars['volfraction']
219
220    return oldpars
221
222def constrain_new_to_old(model_info, pars):
223    """
224    Restrict parameter values to those that will match sasview.
225    """
226    name = model_info.id
227    # Note: update convert.revert_model to match
228    if name in MODELS_WITHOUT_SCALE or model_info.structure_factor:
229        pars['scale'] = 1
230    if name in MODELS_WITHOUT_BACKGROUND or model_info.structure_factor:
231        pars['background'] = 0
232    # sasview multiplies background by structure factor
233    if '*' in name:
234        pars['background'] = 0
235
236    # If it is a product model P*S, then check the individual forms for special
237    # cases.  Note: despite the structure factor alone not having scale or
238    # background, the product model does, so this is below the test for
239    # models without scale or background.
240    namelist = name.split('*') if '*' in name else [name]
241    for name in namelist:
242        if name == 'pearl_necklace':
243            pars['string_thickness_pd_n'] = 0
244            pars['number_of_pearls_pd_n'] = 0
245        elif name == 'line':
246            pars['scale'] = 1
247            pars['background'] = 0
248        elif name == 'rpa':
249            pars['case_num'] = int(pars['case_num'])
250        elif name == 'mono_gauss_coil':
251            pars['i_zero'] = 1
252        elif name == 'poly_gauss_coil':
253            pars['i_zero'] = 1
254        elif name == 'fractal':
255            pars['volfraction'] = 1
256        elif name == 'vesicle':
257            pars['volfraction'] = 1
258        elif name == 'multilayer_vesicle':
259            pars['volfraction'] = 1
260           
Note: See TracBrowser for help on using the repository browser.