source: sasmodels/sasmodels/convert.py @ 077666e

core_shell_microgelscostrafo411magnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 077666e was 077666e, checked in by krzywon, 7 years ago

#795: Gel fit, Lamellar Caille, Debye, and Spherical SLD issues resolved.

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