source: sasmodels/sasmodels/convert.py @ e65c3ba

core_shell_microgelsmagnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since e65c3ba was e65c3ba, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

lint

  • Property mode set to 100644
File size: 24.0 KB
Line 
1"""
2Convert models to and from sasview.
3"""
4from __future__ import print_function, division
5
6import math
7import warnings
8
9from .conversion_table import CONVERSION_TABLE
10from .core import load_model_info
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    'gauss_lorentz_gel',
20    'be_polyelectrolyte',
21    'correlation_length',
22    'fractal_core_shell',
23    'binary_hard_sphere',
24    'raspberry'
25]
26
27# List of models which SasView versions don't contain the explicit 'background' argument.
28# When converting such a model, please update this list.
29MODELS_WITHOUT_BACKGROUND = [
30    'guinier',
31]
32
33MODELS_WITHOUT_VOLFRACTION = [
34    'fractal',
35    'vesicle',
36    'multilayer_vesicle',
37]
38
39MAGNETIC_SASVIEW_MODELS = [
40    'core_shell',
41    'core_multi_shell',
42    'cylinder',
43    'parallelepiped',
44    'sphere',
45]
46
47
48# Convert new style names for polydispersity info to old style names
49PD_DOT = [
50    ("_pd", ".width"),
51    ("_pd_n", ".npts"),
52    ("_pd_nsigma", ".nsigmas"),
53    ("_pd_type", ".type"),
54    (".lower", ".lower"),
55    (".upper", ".upper"),
56    (".fittable", ".fittable"),
57    (".std", ".std"),
58    (".units", ".units"),
59    ("", "")
60    ]
61
62def _rescale(par, scale):
63    return [pk*scale for pk in par] if isinstance(par, list) else par*scale
64
65def _is_sld(model_info, par):
66    """
67    Return True if parameter is a magnetic magnitude or SLD parameter.
68    """
69    if par.startswith('M0:'):
70        return True
71    if '_pd' in par or '.' in par:
72        return False
73    for p in model_info.parameters.call_parameters:
74        if p.id == par:
75            return p.type == 'sld'
76    # check through kernel parameters in case it is a named as a vector
77    for p in model_info.parameters.kernel_parameters:
78        if p.id == par:
79            return p.type == 'sld'
80    return False
81
82def _rescale_sld(model_info, pars, scale):
83    """
84    rescale all sld parameters in the new model definition by *scale* so the
85    numbers are nicer.  Relies on the fact that all sld parameters in the
86    new model definition end with sld.  For backward conversion use
87    *scale=1e-6*.  For forward conversion use *scale=1e6*.
88    """
89    return dict((par, (_rescale(v, scale) if _is_sld(model_info, par) else v))
90                for par, v in pars.items())
91
92
93def _get_translation_table(model_info, version=(3, 1, 2)):
94    conv_param = CONVERSION_TABLE.get(version, {}).get(model_info.id, [None, {}])
95    translation = conv_param[1].copy()
96    for p in model_info.parameters.kernel_parameters:
97        if p.length > 1:
98            newid = p.id
99            oldid = translation.get(p.id, p.id)
100            translation.pop(newid, None)
101            for k in range(1, p.length+1):
102                if newid+str(k) not in translation:
103                    translation[newid+str(k)] = oldid+str(k)
104    # Remove control parameter from the result
105    if model_info.control:
106        translation[model_info.control] = "CONTROL"
107    return translation
108
109# ========= FORWARD CONVERSION sasview 3.x => sasmodels ===========
110def _dot_pd_to_underscore_pd(par):
111    if par.endswith(".width"):
112        return par[:-6]+"_pd"
113    elif par.endswith(".type"):
114        return par[:-5]+"_pd_type"
115    elif par.endswith(".nsigmas"):
116        return par[:-8]+"_pd_nsigma"
117    elif par.endswith(".npts"):
118        return par[:-5]+"_pd_n"
119    else:
120        return par
121
122def _pd_to_underscores(pars):
123    return dict((_dot_pd_to_underscore_pd(k), v) for k, v in pars.items())
124
125def _convert_pars(pars, mapping):
126    """
127    Rename the parameters and any associated polydispersity attributes.
128    """
129    newpars = pars.copy()
130    for new, old in mapping.items():
131        if old == new:
132            continue
133        if old is None:
134            continue
135        for _, dot in PD_DOT:
136            source = old+dot
137            if source in newpars:
138                if new is not None:
139                    target = new+dot
140                else:
141                    target = None
142                if source != target:
143                    if target:
144                        newpars[target] = pars[old+dot]
145                    del newpars[source]
146    return newpars
147
148def _conversion_target(model_name, version=(3,1,2)):
149    """
150    Find the sasmodel name which translates into the sasview name.
151
152    Note: *CoreShellEllipsoidModel* translates into *core_shell_ellipsoid:1*.
153    This is necessary since there is only one variant in sasmodels for the
154    two variants in sasview.
155    """
156    for sasmodels_name, sasview_dict in \
157            CONVERSION_TABLE.get(version, {}).items():
158        if sasview_dict[0] == model_name:
159            return sasmodels_name
160    return None
161
162def _hand_convert(name, oldpars, version=(3, 1, 2)):
163    if version == (3, 1, 2):
164        oldpars = _hand_convert_3_1_2_to_4_1(name, oldpars)
165    return oldpars
166
167def _hand_convert_3_1_2_to_4_1(name, oldpars):
168    if name == 'core_shell_parallelepiped':
169        # Make sure pd on rim parameters defaults to zero
170        # ... probably not necessary.
171        oldpars['rimA.width'] = 0.0
172        oldpars['rimB.width'] = 0.0
173        oldpars['rimC.width'] = 0.0
174    elif name == 'core_shell_ellipsoid:1':
175        # Reverse translation (from new to old), from core_shell_ellipsoid.c
176        #    equat_shell = equat_core + thick_shell
177        #    polar_core = equat_core * x_core
178        #    polar_shell = equat_core * x_core + thick_shell*x_polar_shell
179        # Forward translation (from old to new), inverting reverse translation:
180        #    thick_shell = equat_shell - equat_core
181        #    x_core = polar_core / equat_core
182        #    x_polar_shell = (polar_shell - polar_core)/(equat_shell - equat_core)
183        # Auto translation (old <=> new) happens after hand_convert
184        #    equat_shell <=> thick_shell
185        #    polar_core <=> x_core
186        #    polar_shell <=> x_polar_shell
187        # So...
188        equat_core, equat_shell = oldpars['equat_core'], oldpars['equat_shell']
189        polar_core, polar_shell = oldpars['polar_core'], oldpars['polar_shell']
190        oldpars['equat_shell'] = equat_shell - equat_core
191        oldpars['polar_core'] = polar_core / equat_core
192        oldpars['polar_shell'] = (polar_shell-polar_core)/(equat_shell-equat_core)
193    elif name == 'hollow_cylinder':
194        # now uses radius and thickness
195        thickness = oldpars['radius'] - oldpars['core_radius']
196        oldpars['radius'] = thickness
197        if 'radius.width' in oldpars:
198            pd = oldpars['radius.width']*oldpars['radius']/thickness
199            oldpars['radius.width'] = pd
200    elif name == 'multilayer_vesicle':
201        if 'scale' in oldpars:
202            oldpars['volfraction'] = oldpars['scale']
203            oldpars['scale'] = 1.0
204        if 'scale.lower' in oldpars:
205            oldpars['volfraction.lower'] = oldpars['scale.lower']
206        if 'scale.upper' in oldpars:
207            oldpars['volfraction.upper'] = oldpars['scale.upper']
208        if 'scale.fittable' in oldpars:
209            oldpars['volfraction.fittable'] = oldpars['scale.fittable']
210        if 'scale.std' in oldpars:
211            oldpars['volfraction.std'] = oldpars['scale.std']
212        if 'scale.units' in oldpars:
213            oldpars['volfraction.units'] = oldpars['scale.units']
214    elif name == 'pearl_necklace':
215        pass
216        #_remove_pd(oldpars, 'num_pearls', name)
217        #_remove_pd(oldpars, 'thick_string', name)
218    elif name == 'polymer_micelle':
219        if 'ndensity' in oldpars:
220            oldpars['ndensity'] /= 1e15
221        if 'ndensity.lower' in oldpars:
222            oldpars['ndensity.lower'] /= 1e15
223        if 'ndensity.upper' in oldpars:
224            oldpars['ndensity.upper'] /= 1e15
225    elif name == 'rpa':
226        # convert scattering lengths from femtometers to centimeters
227        for p in "L1", "L2", "L3", "L4":
228            if p in oldpars:
229                oldpars[p] /= 1e-13
230            if p + ".lower" in oldpars:
231                oldpars[p + ".lower"] /= 1e-13
232            if p + ".upper" in oldpars:
233                oldpars[p + ".upper"] /= 1e-13
234    elif name == 'spherical_sld':
235        j = 0
236        while "func_inter" + str(j) in oldpars:
237            name = "func_inter" + str(j)
238            new_name = "shape" + str(j + 1)
239            if oldpars[name] == 'Erf(|nu|*z)':
240                oldpars[new_name] = int(0)
241            elif oldpars[name] == 'RPower(z^|nu|)':
242                oldpars[new_name] = int(1)
243            elif oldpars[name] == 'LPower(z^|nu|)':
244                oldpars[new_name] = int(2)
245            elif oldpars[name] == 'RExp(-|nu|*z)':
246                oldpars[new_name] = int(3)
247            elif oldpars[name] == 'LExp(-|nu|*z)':
248                oldpars[new_name] = int(4)
249            else:
250                oldpars[new_name] = int(0)
251            oldpars.pop(name)
252            oldpars['n_shells'] = str(j + 1)
253            j += 1
254    elif name == 'teubner_strey':
255        # basically undoing the entire Teubner-Strey calculations here.
256        #    drho = (sld_a - sld_b)
257        #    k = 2.0*math.pi*xi/d
258        #    a2 = (1.0 + k**2)**2
259        #    c1 = 2.0 * xi**2 * (1.0 - k**2)
260        #    c2 = xi**4
261        #    prefactor = 8.0*math.pi*phi*(1.0-phi)*drho**2*c2/xi
262        #    scale = 1e-4*prefactor
263        #    oldpars['scale'] = a2/scale
264        #    oldpars['c1'] = c1/scale
265        #    oldpars['c2'] = c2/scale
266
267        # need xi, d, sld_a, sld_b, phi=volfraction_a
268        # assume contrast is 1.0e-6, scale=1, background=0
269        sld_a, sld_b = 1.0, 0.
270        drho = sld_a - sld_b
271
272        # find xi
273        p_scale = oldpars['scale']
274        p_c1 = oldpars['c1']
275        p_c2= oldpars['c2']
276        i_1 = 0.5*p_c1/p_c2
277        i_2 = math.sqrt(math.fabs(p_scale/p_c2))
278        i_3 = 2/(i_1 + i_2)
279        xi = math.sqrt(math.fabs(i_3))
280
281        # find d from xi
282        k = math.sqrt(math.fabs(1 - 0.5*p_c1/p_c2*xi**2))
283        d = 2*math.pi*xi/k
284
285        # solve quadratic phi (1-phi) = xi/(1e-4 8 pi drho^2 c2)
286        # favour volume fraction in [0, 0.5]
287        c = xi / (1e-4 * 8.0 * math.pi * drho**2 * p_c2)
288        phi = 0.5 - math.sqrt(0.25 - c)
289
290        # scale sld_a by 1e-6 because the translator will scale it back
291        oldpars.update(volfraction_a=phi, xi=xi, d=d, sld_a=sld_a*1e-6,
292                       sld_b=sld_b, scale=1.0)
293        oldpars.pop('c1')
294        oldpars.pop('c2')
295
296    return oldpars
297
298def convert_model(name, pars, use_underscore=False, model_version=(3, 1, 2)):
299    """
300    Convert model from old style parameter names to new style.
301    """
302    newpars = pars
303    keys = sorted(CONVERSION_TABLE.keys())
304    for i, version in enumerate(keys):
305        # Don't allow indices outside list
306        next_i = i + 1
307        if next_i == len(keys):
308            next_i = i
309        # If the save state is from a later version, skip the check
310        if model_version <= keys[next_i]:
311            newname = _conversion_target(name, version)
312        else:
313            newname = None
314        # If no conversion is found, move on
315        if newname is None:
316            newname = name
317            continue
318        if ':' in newname:   # core_shell_ellipsoid:1
319            model_info = load_model_info(newname[:-2])
320            # Know the table exists and isn't multiplicity so grab it directly
321            # Can't use _get_translation_table since that will return the 'bare'
322            # version.
323            translation = CONVERSION_TABLE.get(version, {})[newname][1]
324        else:
325            model_info = load_model_info(newname)
326            translation = _get_translation_table(model_info, version)
327        newpars = _hand_convert(newname, newpars, version)
328        newpars = _convert_pars(newpars, translation)
329        # TODO: Still not convinced this is the best check
330        if not model_info.structure_factor and version == (3, 1, 2):
331            newpars = _rescale_sld(model_info, newpars, 1e6)
332        newpars.setdefault('scale', 1.0)
333        newpars.setdefault('background', 0.0)
334        if use_underscore:
335            newpars = _pd_to_underscores(newpars)
336        name = newname
337    return newname, newpars
338
339# ========= BACKWARD CONVERSION sasmodels => sasview 3.x ===========
340
341def _revert_pars(pars, mapping):
342    """
343    Rename the parameters and any associated polydispersity attributes.
344    """
345    newpars = pars.copy()
346
347    for new, old in mapping.items():
348        for underscore, dot in PD_DOT:
349            if old and old+underscore == new+dot:
350                continue
351            if new+underscore in newpars:
352                if old is not None:
353                    newpars[old+dot] = pars[new+underscore]
354                del newpars[new+underscore]
355    for k in list(newpars.keys()):
356        for underscore, dot in PD_DOT[1:]:  # skip "" => ""
357            if k.endswith(underscore):
358                newpars[k[:-len(underscore)]+dot] = newpars[k]
359                del newpars[k]
360    return newpars
361
362def revert_name(model_info):
363    oldname, _ = CONVERSION_TABLE.get(model_info.id, [None, {}])
364    return oldname
365
366def _remove_pd(pars, key, name):
367    """
368    Remove polydispersity from the parameter list.
369
370    Note: operates in place
371    """
372    # Bumps style parameter names
373    width = pars.pop(key+".width", 0.0)
374    n_points = pars.pop(key+".npts", 0)
375    if width != 0.0 and n_points != 0:
376        warnings.warn("parameter %s not polydisperse in sasview %s"%(key, name))
377    pars.pop(key+".nsigmas", None)
378    pars.pop(key+".type", None)
379    return pars
380
381def _trim_vectors(model_info, pars, oldpars):
382    _, translation = CONVERSION_TABLE.get(model_info.id, [None, {}])
383    for p in model_info.parameters.kernel_parameters:
384        if p.length_control is not None:
385            n = int(pars[p.length_control])
386            oldname = translation.get(p.id, p.id)
387            for k in range(n+1, p.length+1):
388                for _, old in PD_DOT:
389                    oldpars.pop(oldname+str(k)+old, None)
390    return oldpars
391
392def revert_pars(model_info, pars):
393    """
394    Convert model from new style parameter names to old style.
395    """
396    if model_info.composition is not None:
397        composition_type, parts = model_info.composition
398        if composition_type == 'product':
399            translation = _get_translation_table(parts[0])
400            # structure factor models include scale:scale_factor mapping
401            translation.update(_get_translation_table(parts[1]))
402        else:
403            raise NotImplementedError("cannot convert to sasview sum")
404    else:
405        translation = _get_translation_table(model_info)
406    oldpars = _revert_pars(_rescale_sld(model_info, pars, 1e-6), translation)
407    oldpars = _trim_vectors(model_info, pars, oldpars)
408
409    # Make sure the control parameter is an integer
410    if "CONTROL" in oldpars:
411        oldpars["CONTROL"] = int(oldpars["CONTROL"])
412
413    # Note: update compare.constrain_pars to match
414    name = model_info.id
415    if name in MODELS_WITHOUT_SCALE or model_info.structure_factor:
416        if oldpars.pop('scale', 1.0) != 1.0:
417            warnings.warn("parameter scale not used in sasview %s"%name)
418    if name in MODELS_WITHOUT_BACKGROUND or model_info.structure_factor:
419        if oldpars.pop('background', 0.0) != 0.0:
420            warnings.warn("parameter background not used in sasview %s"%name)
421
422    # Remove magnetic parameters from non-magnetic sasview models
423    if name not in MAGNETIC_SASVIEW_MODELS:
424        oldpars = dict((k, v) for k, v in oldpars.items() if ':' not in k)
425
426    # If it is a product model P*S, then check the individual forms for special
427    # cases.  Note: despite the structure factor alone not having scale or
428    # background, the product model does, so this is below the test for
429    # models without scale or background.
430    namelist = name.split('*') if '*' in name else [name]
431    for name in namelist:
432        if name in MODELS_WITHOUT_VOLFRACTION:
433            del oldpars['volfraction']
434        elif name == 'core_multi_shell':
435            # kill extra shells
436            for k in range(5, 11):
437                oldpars.pop('sld_shell'+str(k), 0)
438                oldpars.pop('thick_shell'+str(k), 0)
439                oldpars.pop('mtheta:sld'+str(k), 0)
440                oldpars.pop('mphi:sld'+str(k), 0)
441                oldpars.pop('M0:sld'+str(k), 0)
442                _remove_pd(oldpars, 'sld_shell'+str(k), 'sld')
443                _remove_pd(oldpars, 'thick_shell'+str(k), 'thickness')
444        elif name == 'core_shell_parallelepiped':
445            _remove_pd(oldpars, 'rimA', name)
446            _remove_pd(oldpars, 'rimB', name)
447            _remove_pd(oldpars, 'rimC', name)
448        elif name == 'hollow_cylinder':
449            # now uses radius and thickness
450            thickness = oldpars['core_radius']
451            oldpars['radius'] += thickness
452            oldpars['radius.width'] *= thickness/oldpars['radius']
453        #elif name in ['mono_gauss_coil', 'poly_gauss_coil']:
454        #    del oldpars['i_zero']
455        elif name == 'onion':
456            oldpars.pop('n_shells', None)
457        elif name == 'pearl_necklace':
458            _remove_pd(oldpars, 'num_pearls', name)
459            _remove_pd(oldpars, 'thick_string', name)
460        elif name == 'polymer_micelle':
461            if 'ndensity' in oldpars:
462                oldpars['ndensity'] *= 1e15
463        elif name == 'rpa':
464            # convert scattering lengths from femtometers to centimeters
465            for p in "L1", "L2", "L3", "L4":
466                if p in oldpars: oldpars[p] *= 1e-13
467            if pars['case_num'] < 2:
468                for k in ("a", "b"):
469                    for p in ("L", "N", "Phi", "b", "v"):
470                        oldpars.pop(p+k, None)
471                for k in "Kab,Kac,Kad,Kbc,Kbd".split(','):
472                    oldpars.pop(k, None)
473            elif pars['case_num'] < 5:
474                for k in ("a",):
475                    for p in ("L", "N", "Phi", "b", "v"):
476                        oldpars.pop(p+k, None)
477                for k in "Kab,Kac,Kad".split(','):
478                    oldpars.pop(k, None)
479        elif name == 'spherical_sld':
480            oldpars["CONTROL"] -= 1
481            # remove polydispersity from shells
482            for k in range(1, 11):
483                _remove_pd(oldpars, 'thick_flat'+str(k), 'thickness')
484                _remove_pd(oldpars, 'thick_inter'+str(k), 'interface')
485            # remove extra shells
486            for k in range(int(pars['n_shells']), 11):
487                oldpars.pop('sld_flat'+str(k), 0)
488                oldpars.pop('thick_flat'+str(k), 0)
489                oldpars.pop('thick_inter'+str(k), 0)
490                oldpars.pop('func_inter'+str(k), 0)
491                oldpars.pop('nu_inter'+str(k), 0)
492        elif name == 'stacked_disks':
493            _remove_pd(oldpars, 'n_stacking', name)
494        elif name == 'teubner_strey':
495            # basically redoing the entire Teubner-Strey calculations here.
496            volfraction = oldpars.pop('volfraction_a')
497            xi = oldpars.pop('xi')
498            d = oldpars.pop('d')
499            sld_a = oldpars.pop('sld_a')
500            sld_b = oldpars.pop('sld_b')
501            drho = 1e6*(sld_a - sld_b)  # conversion autoscaled these
502            k = 2.0*math.pi*xi/d
503            a2 = (1.0 + k**2)**2
504            c1 = 2.0 * xi**2 * (1.0 - k**2)
505            c2 = xi**4
506            prefactor = 8.0*math.pi*volfraction*(1.0-volfraction)*drho**2*c2/xi
507            scale = 1e-4*prefactor
508            oldpars['scale'] = a2/scale
509            oldpars['c1'] = c1/scale
510            oldpars['c2'] = c2/scale
511
512    #print("convert from",list(sorted(pars)))
513    #print("convert to",list(sorted(oldpars.items())))
514    return oldpars
515
516def constrain_new_to_old(model_info, pars):
517    """
518    Restrict parameter values to those that will match sasview.
519    """
520    name = model_info.id
521    # Note: update convert.revert_model to match
522    if name in MODELS_WITHOUT_SCALE or model_info.structure_factor:
523        pars['scale'] = 1
524    if name in MODELS_WITHOUT_BACKGROUND or model_info.structure_factor:
525        pars['background'] = 0
526    # sasview multiplies background by structure factor
527    if '*' in name:
528        pars['background'] = 0
529
530    # Shut off magnetism when comparing non-magnetic sasview models
531    if name not in MAGNETIC_SASVIEW_MODELS:
532        suppress_magnetism = False
533        for key in pars.keys():
534            if key.startswith("M0:"):
535                suppress_magnetism = suppress_magnetism or (pars[key] != 0)
536                pars[key] = 0
537        if suppress_magnetism:
538            warnings.warn("suppressing magnetism for comparison with sasview")
539
540    # Shut off theta polydispersity since algorithm has changed
541    if 'theta_pd_n' in pars:
542        if pars['theta_pd_n'] != 0:
543            warnings.warn("suppressing theta polydispersity for comparison with sasview")
544        pars['theta_pd_n'] = 0
545
546    # If it is a product model P*S, then check the individual forms for special
547    # cases.  Note: despite the structure factor alone not having scale or
548    # background, the product model does, so this is below the test for
549    # models without scale or background.
550    namelist = name.split('*') if '*' in name else [name]
551    for name in namelist:
552        if name in MODELS_WITHOUT_VOLFRACTION:
553            pars['volfraction'] = 1
554        if name == 'core_multi_shell':
555            pars['n'] = min(math.ceil(pars['n']), 4)
556        elif name == 'gel_fit':
557            pars['scale'] = 1
558        elif name == 'line':
559            pars['scale'] = 1
560            pars['background'] = 0
561        elif name == 'mono_gauss_coil':
562            pars['scale'] = 1
563        elif name == 'onion':
564            pars['n_shells'] = math.ceil(pars['n_shells'])
565        elif name == 'pearl_necklace':
566            pars['string_thickness_pd_n'] = 0
567            pars['number_of_pearls_pd_n'] = 0
568        elif name == 'poly_gauss_coil':
569            pars['scale'] = 1
570        elif name == 'rpa':
571            pars['case_num'] = int(pars['case_num'])
572        elif name == 'spherical_sld':
573            pars['n_shells'] = math.ceil(pars['n_shells'])
574            pars['n_steps'] = math.ceil(pars['n_steps'])
575            for k in range(1, 11):
576                pars['shape%d'%k] = math.trunc(pars['shape%d'%k]+0.5)
577            for k in range(2, 11):
578                pars['thickness%d_pd_n'%k] = 0
579                pars['interface%d_pd_n'%k] = 0
580        elif name == 'teubner_strey':
581            pars['scale'] = 1
582            if pars['volfraction_a'] > 0.5:
583                pars['volfraction_a'] = 1.0 - pars['volfraction_a']
584        elif name == 'unified_power_Rg':
585            pars['level'] = int(pars['level'])
586
587def _check_one(name, seed=None):
588    """
589    Generate a random set of parameters for *name*, and check that they can
590    be converted back to SasView 3.x and forward again to sasmodels.  Raises
591    an error if the parameters are changed.
592    """
593    from . import compare
594
595    model_info = load_model_info(name)
596
597    old_name = revert_name(model_info)
598    if old_name is None:
599        return
600
601    pars = compare.get_pars(model_info, use_demo=False)
602    pars = compare.randomize_pars(model_info, pars, seed=seed)
603    if name == "teubner_strey":
604        # T-S model is underconstrained, so fix the assumptions.
605        pars['sld_a'], pars['sld_b'] = 1.0, 0.0
606    compare.constrain_pars(model_info, pars)
607    constrain_new_to_old(model_info, pars)
608    old_pars = revert_pars(model_info, pars)
609    new_name, new_pars = convert_model(old_name, old_pars, use_underscore=True)
610    if 1:
611        print("==== %s in ====="%name)
612        print(str(compare.parlist(model_info, pars, True)))
613        print("==== %s ====="%old_name)
614        for k, v in sorted(old_pars.items()):
615            print(k, v)
616        print("==== %s out ====="%new_name)
617        print(str(compare.parlist(model_info, new_pars, True)))
618    assert name == new_name, "%r != %r"%(name, new_name)
619    for k, v in new_pars.items():
620        assert k in pars, "%s: %r appeared from conversion"%(name, k)
621        if isinstance(v, float):
622            assert abs(v-pars[k]) <= abs(1e-12*v), \
623                "%s: %r  %s != %s"%(name, k, v, pars[k])
624        else:
625            assert v == pars[k], "%s: %r  %s != %s"%(name, k, v, pars[k])
626    for k, v in pars.items():
627        assert k in pars, "%s: %r not converted"%(name, k)
628
629def test_backward_forward():
630    from .core import list_models
631    for name in list_models('all'):
632        L = lambda: _check_one(name, seed=1)
633        L.description = name
634        yield L
Note: See TracBrowser for help on using the repository browser.