source: sasmodels/sasmodels/convert.py @ 32e3c9b

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

dll version of magnetic sld

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