source: sasmodels/sasmodels/autoc.py @ 765d025

Last change on this file since 765d025 was 765d025, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

Merge remote-tracking branch 'upstream/beta_approx'

  • Property mode set to 100644
File size: 5.0 KB
RevLine 
[db03406]1"""
2Automatically translate python models to C
3"""
4from __future__ import print_function
5
6import inspect
7
8import numpy as np
9
[71c5f4d]10from . import py2c
[db03406]11from . import special
12
13# pylint: disable=unused-import
14try:
15    from types import ModuleType
16    #from .modelinfo import ModelInfo  # circular import
17except ImportError:
18    pass
19# pylint: enable=unused-import
20
21DEPENDENCY = {
22    'core_shell_kernel': ['lib/core_shell.c'],
23    'fractal_sq': ['lib/fractal_sq.c'],
24    'gfn4': ['lib/gfn.c'],
25    'polevl': ['lib/polevl.c'],
26    'p1evl': ['lib/polevl.c'],
27    'sas_2J1x_x': ['lib/polevl.c', 'lib/sas_J1.c'],
28    'sas_3j1x_x': ['lib/sas_3j1x_x.c'],
29    'sas_erf': ['lib/polevl.c', 'lib/sas_erf.c'],
30    'sas_erfc': ['lib/polevl.c', 'lib/sas_erf.c'],
31    'sas_gamma': ['lib/sas_gamma.c'],
[765d025]32    'sas_gammaln': ['lib/sas_gammainc.c'],
33    'sas_gammainc': ['lib/sas_gammainc.c'],
34    'sas_gammaincc': ['lib/sas_gammainc.c'],
[db03406]35    'sas_J0': ['lib/polevl.c', 'lib/sas_J0.c'],
36    'sas_J1': ['lib/polevl.c', 'lib/sas_J1.c'],
37    'sas_JN': ['lib/polevl.c', 'lib/sas_J0.c', 'lib/sas_J1.c', 'lib/sas_JN.c'],
38    'sas_Si': ['lib/Si.c'],
39}
40
[ef6a512]41DEFINES = frozenset("M_PI M_PI_2 M_PI_4 M_SQRT1_2 M_E NAN INFINITY M_PI_180 M_4PI_3".split())
42
[db03406]43def convert(info, module):
44    # type: ("ModelInfo", ModuleType) -> bool
45    """
[765d025]46    Convert Iq, Iqxy, form_volume, etc. to c
47
48    Returns list of warnings
[db03406]49    """
50    # Check if there is already C code
51    if info.source or info.c_code is not None:
52        return
53
[765d025]54    public_methods = ("Iq", "Iqac", "Iqabc", "Iqxy", 
55            "form_volume", "shell_volume", "effective_radius")
[db03406]56
[ef6a512]57    tagged = [] # type: List[str]
58    translate = [] # type: List[Callable]
[db03406]59    for function_name in public_methods:
60        function = getattr(info, function_name)
61        if callable(function):
[bf88ef1]62            if getattr(function, 'vectorized', None):
63                return  # Don't try to translate vectorized code
[db03406]64            tagged.append(function_name)
[ef6a512]65            translate.append((function_name, function))
[db03406]66    if not translate:
[ef6a512]67        # nothing to translate---maybe Iq, etc. are already C snippets?
68        return
[db03406]69
[ef6a512]70    libs = []  # type: List[str]
[50b5464]71    snippets = []  # type: List[str]
72    constants = {} # type: Dict[str, Any]
[ef6a512]73    code = {}  # type: Dict[str, str]
74    depends = {}  # type: Dict[str, List[str]]
[db03406]75    while translate:
[ef6a512]76        function_name, function = translate.pop(0)
[db03406]77        filename = function.__code__.co_filename
[1ddb794]78        escaped_filename = filename.replace('\\', '\\\\')
[db03406]79        offset = function.__code__.co_firstlineno
80        refs = function.__code__.co_names
[ef6a512]81        depends[function_name] = set(refs)
[0a9fcab]82        source = inspect.getsource(function)
[db03406]83        for name in refs:
[ef6a512]84            if name in tagged or name in DEFINES:
85                continue
86            tagged.append(name)
[db03406]87            obj = getattr(module, name, None)
88            if obj is None:
89                pass # ignore unbound variables for now
90                #raise ValueError("global %s is not defined" % name)
91            elif callable(obj):
[ef6a512]92                if getattr(special, name, None):
93                    # special symbol: look up depenencies
94                    libs.extend(DEPENDENCY.get(name, []))
95                else:
96                    # not special: add function to translate stack
97                    translate.append((name, obj))
[8224d24]98            elif isinstance(obj, (int, float, list, tuple, np.ndarray)):
[50b5464]99                constants[name] = obj
[8224d24]100                # Claim all constants are declared on line 1
[15be191]101                snippets.append('#line 1 "%s"\n'%escaped_filename)
[c01ed3e]102                snippets.append(py2c.define_constant(name, obj))
[db03406]103            elif isinstance(obj, special.Gauss):
[67cc0ff]104                for var, value in zip(("N", "Z", "W"), (obj.n, obj.z, obj.w)):
105                    var = "GAUSS_"+var
106                    constants[var] = value
[15be191]107                    snippets.append('#line 1 "%s"\n'%escaped_filename)
[c01ed3e]108                    snippets.append(py2c.define_constant(var, value))
[67cc0ff]109                #libs.append('lib/gauss%d.c'%obj.n)
[0a9fcab]110                source = (source.replace(name+'.n', 'GAUSS_N')
111                          .replace(name+'.z', 'GAUSS_Z')
112                          .replace(name+'.w', 'GAUSS_W'))
[db03406]113            else:
114                raise TypeError("Could not convert global %s of type %s"
115                                % (name, str(type(obj))))
116
[50b5464]117        # add (possibly modified) source to set of functions to compile
118        code[function_name] = (source, filename, offset)
[0a9fcab]119
[db03406]120    # remove duplicates from the dependecy list
[0a9fcab]121    unique_libs = []
[ef6a512]122    for filename in libs:
123        if filename not in unique_libs:
124            unique_libs.append(filename)
[db03406]125
[50b5464]126    # translate source
[c01ed3e]127    ordered_code = [code[name] for name in py2c.ordered_dag(depends) if name in code]
[765d025]128    functions, warnings = py2c.translate(ordered_code, constants)
[1ddb794]129    snippets.extend(functions)
[db03406]130
[50b5464]131    # update model info
132    info.source = unique_libs
[15be191]133    info.c_code = "".join(snippets)
[67cc0ff]134    info.Iq = info.Iqac = info.Iqabc = info.Iqxy = info.form_volume = None
[765d025]135
136    return warnings
137
Note: See TracBrowser for help on using the repository browser.