source: sasmodels/sasmodels/convert.py @ f247314

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

use sasmodels/convert.json for converting new models to old

  • Property mode set to 100644
File size: 8.9 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 {
65            _byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True)
66            for key, value in data.iteritems()
67        }
68    # if it's anything else, return it in its original form
69    return data
70
71
72def _convert_pars(pars, mapping):
73    """
74    Rename the parameters and any associated polydispersity attributes.
75    """
76    newpars = pars.copy()
77    for new, old in mapping.items():
78        if old == new: continue
79        for pd, dot in PD_DOT:
80            if old+dot in newpars:
81                if new is not None:
82                    newpars[new+pd] = pars[old+dot]
83                del newpars[old+dot]
84    return newpars
85
86def _rescale_sld(pars):
87    """
88    rescale all sld parameters in the new model definition by 1e6 so the
89    numbers are nicer.  Relies on the fact that all sld parameters in the
90    new model definition end with sld.
91    """
92    return dict((p, (v*1e6 if p.endswith('sld')
93                     else v*1e-15 if 'ndensity' in p
94                     else v))
95                for p, v in pars.items())
96
97def convert_model(name, pars):
98    """
99    Convert model from old style parameter names to new style.
100    """
101    _, _ = name, pars # lint
102    raise NotImplementedError
103    # need to load all new models in order to determine old=>new
104    # model name mapping
105
106def _unscale_sld(pars):
107    """
108    rescale all sld parameters in the new model definition by 1e6 so the
109    numbers are nicer.  Relies on the fact that all sld parameters in the
110    new model definition end with sld.
111    """
112    return dict((p, (v*1e-6 if p.startswith('sld') or p.endswith('sld')
113                     else v*1e15 if 'ndensity' in p
114                     else v))
115                for p, v in pars.items())
116
117def _remove_pd(pars, key, name):
118    """
119    Remove polydispersity from the parameter list.
120
121    Note: operates in place
122    """
123    # Bumps style parameter names
124    pd = pars.pop(key+".width", 0.0)
125    pd_n = pars.pop(key+".npts", 0)
126    if pd != 0.0 and pd_n != 0:
127        warnings.warn("parameter %s not polydisperse in sasview %s"%(key, name))
128    pars.pop(key+".nsigmas", None)
129    pars.pop(key+".type", None)
130    return pars
131
132def _revert_pars(pars, mapping):
133    """
134    Rename the parameters and any associated polydispersity attributes.
135    """
136    newpars = pars.copy()
137
138    for new, old in mapping.items():
139        for pd, dot in PD_DOT:
140            if old and old+pd == new+dot:
141                continue
142            if new+pd in newpars:
143                if old is not None:
144                    newpars[old+dot] = pars[new+pd]
145                del newpars[new+pd]
146    for k in list(newpars.keys()):
147        for pd, dot in PD_DOT[1:]:  # skip "" => ""
148            if k.endswith(pd):
149                newpars[k[:-len(pd)]+dot] = newpars[k]
150                del newpars[k]
151    return newpars
152
153def revert_name(model_info):
154    _read_conversion_table()
155    oldname, oldpars = CONVERSION_TABLE.get(model_info['id'], [None, {}])
156    return oldname
157
158def _get_old_pars(model_info):
159    _read_conversion_table()
160    oldname, oldpars = CONVERSION_TABLE.get(model_info['id'], [None, {}])
161    return oldpars
162
163def revert_pars(model_info, pars):
164    """
165    Convert model from new style parameter names to old style.
166    """
167    if model_info['composition'] is not None:
168        composition_type, parts = model_info['composition']
169        if composition_type == 'product':
170            P, S = parts
171            oldpars = {'scale':'scale_factor'}
172            oldpars.update(_get_old_pars(P))
173            oldpars.update(_get_old_pars(S))
174        else:
175            raise NotImplementedError("cannot convert to sasview sum")
176    else:
177        oldpars = _get_old_pars(model_info)
178    oldpars = _revert_pars(_unscale_sld(pars), oldpars)
179
180
181    # Note: update compare.constrain_pars to match
182    name = model_info['id']
183    if name in MODELS_WITHOUT_SCALE or model_info['structure_factor']:
184        if oldpars.pop('scale', 1.0) != 1.0:
185            warnings.warn("parameter scale not used in sasview %s"%name)
186    if name in MODELS_WITHOUT_BACKGROUND or model_info['structure_factor']:
187        if oldpars.pop('background', 0.0) != 0.0:
188            warnings.warn("parameter background not used in sasview %s"%name)
189
190
191    # If it is a product model P*S, then check the individual forms for special
192    # cases.  Note: despite the structure factor alone not having scale or
193    # background, the product model does, so this is below the test for
194    # models without scale or background.
195    namelist = name.split('*') if '*' in name else [name]
196    for name in namelist:
197        if name == 'stacked_disks':
198            _remove_pd(oldpars, 'n_stacking', name)
199        elif name == 'pearl_necklace':
200            _remove_pd(oldpars, 'num_pearls', name)
201            _remove_pd(oldpars, 'thick_string', name)
202        elif name == 'core_shell_parallelepiped':
203            _remove_pd(oldpars, 'rimA', name)
204            _remove_pd(oldpars, 'rimB', name)
205            _remove_pd(oldpars, 'rimC', name)
206        elif name == 'rpa':
207            # convert scattering lengths from femtometers to centimeters
208            for p in "La", "Lb", "Lc", "Ld":
209                if p in oldpars: oldpars[p] *= 1e-13
210        elif name == 'core_shell_parallelepiped':
211            _remove_pd(oldpars, 'rimA', name)
212        elif name in ['mono_gauss_coil','poly_gauss_coil']:
213            del oldpars['i_zero']
214        elif name == 'fractal':
215            del oldpars['volfraction']
216        elif name == 'vesicle':
217            del oldpars['volfraction']
218        elif name == 'multilayer_vesicle':
219            del oldpars['volfraction']
220
221    return oldpars
222
223def constrain_new_to_old(model_info, pars):
224    """
225    Restrict parameter values to those that will match sasview.
226    """
227    name = model_info['id']
228    # Note: update convert.revert_model to match
229    if name in MODELS_WITHOUT_SCALE or model_info['structure_factor']:
230        pars['scale'] = 1
231    if name in MODELS_WITHOUT_BACKGROUND or model_info['structure_factor']:
232        pars['background'] = 0
233    # sasview multiplies background by structure factor
234    if '*' in name:
235        pars['background'] = 0
236
237    # If it is a product model P*S, then check the individual forms for special
238    # cases.  Note: despite the structure factor alone not having scale or
239    # background, the product model does, so this is below the test for
240    # models without scale or background.
241    namelist = name.split('*') if '*' in name else [name]
242    for name in namelist:
243        if name == 'pearl_necklace':
244            pars['string_thickness_pd_n'] = 0
245            pars['number_of_pearls_pd_n'] = 0
246        elif name == 'line':
247            pars['scale'] = 1
248            pars['background'] = 0
249        elif name == 'rpa':
250            pars['case_num'] = int(pars['case_num'])
251        elif name == 'mono_gauss_coil':
252            pars['i_zero'] = 1
253        elif name == 'poly_gauss_coil':
254            pars['i_zero'] = 1
255        elif name == 'fractal':
256            pars['volfraction'] = 1
257        elif name == 'vesicle':
258            pars['volfraction'] = 1
259        elif name == 'multilayer_vesicle':
260            pars['volfraction'] = 1
261           
Note: See TracBrowser for help on using the repository browser.