Index: sasmodels/autoc.py
===================================================================
--- sasmodels/autoc.py	(revision 67cc0fff8de4365704eb57c72afe343290c477d4)
+++ sasmodels/autoc.py	(revision c01ed3e2bc363908dd28daf057e445c91561293d)
@@ -4,7 +4,5 @@
 from __future__ import print_function
 
-import ast
 import inspect
-from functools import reduce
 
 import numpy as np
@@ -96,5 +94,5 @@
                 # Claim all constants are declared on line 1
                 snippets.append('#line 1 "%s"'%escaped_filename)
-                snippets.append(define_constant(name, obj))
+                snippets.append(py2c.define_constant(name, obj))
             elif isinstance(obj, special.Gauss):
                 for var, value in zip(("N", "Z", "W"), (obj.n, obj.z, obj.w)):
@@ -102,5 +100,5 @@
                     constants[var] = value
                     snippets.append('#line 1 "%s"'%escaped_filename)
-                    snippets.append(define_constant(var, value))
+                    snippets.append(py2c.define_constant(var, value))
                 #libs.append('lib/gauss%d.c'%obj.n)
                 source = (source.replace(name+'.n', 'GAUSS_N')
@@ -121,5 +119,5 @@
 
     # translate source
-    ordered_code = [code[name] for name in ordered_dag(depends) if name in code]
+    ordered_code = [code[name] for name in py2c.ordered_dag(depends) if name in code]
     functions = py2c.translate(ordered_code, constants)
     snippets.extend(functions)
@@ -129,44 +127,2 @@
     info.c_code = "\n".join(snippets)
     info.Iq = info.Iqac = info.Iqabc = info.Iqxy = info.form_volume = None
-
-def define_constant(name, value):
-    if isinstance(value, int):
-        parts = ["int ", name, " = ", "%d"%value, ";"]
-    elif isinstance(value, float):
-        parts = ["double ", name, " = ", "%.15g"%value, ";"]
-    else:
-        # extend constant arrays to a multiple of 4; not sure if this
-        # is necessary, but some OpenCL targets broke if the number
-        # of parameters in the parameter table was not a multiple of 4,
-        # so do it for all constant arrays to be safe.
-        if len(value)%4 != 0:
-            value = list(value) + [0.]*(4 - len(value)%4)
-        elements = ["%.15g"%v for v in value]
-        parts = ["double ", name, "[]", " = ",
-                 "{\n   ", ", ".join(elements), "\n};"]
-    return "".join(parts)
-
-
-# Modified from the following:
-#
-#    http://code.activestate.com/recipes/578272-topological-sort/
-#    Copyright (C) 2012 Sam Denton
-#    License: MIT
-def ordered_dag(dag):
-    # type: (Dict[T, Set[T]]) -> Iterator[T]
-    dag = dag.copy()
-
-    # make leaves depend on the empty set
-    leaves = reduce(set.union, dag.values()) - set(dag.keys())
-    dag.update({node: set() for node in leaves})
-    while True:
-        leaves = set(node for node, links in dag.items() if not links)
-        if not leaves:
-            break
-        for node in leaves:
-            yield node
-        dag = {node: (links-leaves)
-               for node, links in dag.items() if node not in leaves}
-    if dag:
-        raise ValueError("Cyclic dependes exists amongst these items:\n%s"
-                            % ", ".join(str(node) for node in dag.keys()))
Index: smodels/codegen.py
===================================================================
--- sasmodels/codegen.py	(revision 59ee4dbe6d75245e5e0e840fdc8f449c1139d3c2)
+++ 	(revision )
@@ -1,686 +1,0 @@
-"""
-    cdegen
-    ~~~~~~~
-
-    Extension to ast that allow ast -> python code generation.
-
-    :copyright: Copyright 2008 by Armin Ronacher.
-    :license: BSD.
-"""
-from __future__ import print_function, division
-
-import ast
-from ast import NodeVisitor
-
-BINOP_SYMBOLS = {}
-BINOP_SYMBOLS[ast.Add] = '+'
-BINOP_SYMBOLS[ast.Sub] = '-'
-BINOP_SYMBOLS[ast.Mult] = '*'
-BINOP_SYMBOLS[ast.Div] = '/'
-BINOP_SYMBOLS[ast.Mod] = '%'
-BINOP_SYMBOLS[ast.Pow] = '**'
-BINOP_SYMBOLS[ast.LShift] = '<<'
-BINOP_SYMBOLS[ast.RShift] = '>>'
-BINOP_SYMBOLS[ast.BitOr] = '|'
-BINOP_SYMBOLS[ast.BitXor] = '^'
-BINOP_SYMBOLS[ast.BitAnd] = '&'
-BINOP_SYMBOLS[ast.FloorDiv] = '//'
-
-BOOLOP_SYMBOLS = {}
-BOOLOP_SYMBOLS[ast.And] = 'and'
-BOOLOP_SYMBOLS[ast.Or] = 'or'
-
-CMPOP_SYMBOLS = {}
-CMPOP_SYMBOLS[ast.Eq] = '=='
-CMPOP_SYMBOLS[ast.NotEq] = '!='
-CMPOP_SYMBOLS[ast.Lt] = '<'
-CMPOP_SYMBOLS[ast.LtE] = '<='
-CMPOP_SYMBOLS[ast.Gt] = '>'
-CMPOP_SYMBOLS[ast.GtE] = '>='
-CMPOP_SYMBOLS[ast.Is] = 'is'
-CMPOP_SYMBOLS[ast.IsNot] = 'is not'
-CMPOP_SYMBOLS[ast.In] = 'in'
-CMPOP_SYMBOLS[ast.NotIn] = 'not in'
-
-UNARYOP_SYMBOLS = {}
-UNARYOP_SYMBOLS[ast.Invert] = '~'
-UNARYOP_SYMBOLS[ast.Not] = 'not'
-UNARYOP_SYMBOLS[ast.UAdd] = '+'
-UNARYOP_SYMBOLS[ast.USub] = '-'
-
-
-def translate(functions, constants):
-    # type: (List[Tuple[str, str, int]], Dict[str, Any]) -> str
-    snippets = []
-    for source, filename, offset in functions:
-        tree = ast.parse(source)
-        snippet = to_source(tree) #, filename, offset)
-        snippets.append(snippet)
-    return "\n".join(snippets)
-
-def to_source(node, indent_with=' ' * 4, add_line_information=False):
-    """This function can convert a node tree back into python sourcecode.
-    This is useful for debugging purposes, especially if you're dealing with
-    custom asts not generated by python itself.
-
-    It could be that the sourcecode is evaluable when the AST itself is not
-    compilable / evaluable.  The reason for this is that the AST contains some
-    more data than regular sourcecode does, which is dropped during
-    conversion.
-
-    Each level of indentation is replaced with `indent_with`.  Per default this
-    parameter is equal to four spaces as suggested by PEP 8, but it might be
-    adjusted to match the application's styleguide.
-
-    If `add_line_information` is set to `True` comments for the line numbers
-    of the nodes are added to the output.  This can be used to spot wrong line
-    number information of statement nodes.
-    """
-    generator = SourceGenerator(indent_with, add_line_information)
-    generator.visit(node)
-
-    return ''.join(generator.result)
-
-class SourceGenerator(NodeVisitor):
-    """This visitor is able to transform a well formed syntax tree into python
-    sourcecode.  For more details have a look at the docstring of the
-    `node_to_source` function.
-    """
-
-    def __init__(self, indent_with, add_line_information=False):
-        self.result = []
-        self.indent_with = indent_with
-        self.add_line_information = add_line_information
-        self.indentation = 0
-        self.new_lines = 0
-
-    def write(self, x):
-        if self.new_lines:
-            if self.result:
-                self.result.append('\n' * self.new_lines)
-            self.result.append(self.indent_with * self.indentation)
-            self.new_lines = 0
-        self.result.append(x)
-
-    def newline(self, node=None, extra=0):
-        self.new_lines = max(self.new_lines, 1 + extra)
-        if node is not None and self.add_line_information:
-            self.write('# line: %s' % node.lineno)
-            self.new_lines = 1
-
-    def body(self, statements):
-        self.new_line = True
-        self.indentation += 1
-        for stmt in statements:
-            self.visit(stmt)
-        self.indentation -= 1
-
-    def body_or_else(self, node):
-        self.body(node.body)
-        if node.orelse:
-            self.newline()
-            self.write('else:')
-            self.body(node.orelse)
-
-    def signature(self, node):
-        want_comma = []
-        def write_comma():
-            if want_comma:
-                self.write(', ')
-            else:
-                want_comma.append(True)
-
-        padding = [None] * (len(node.args) - len(node.defaults))
-        for arg, default in zip(node.args, padding + node.defaults):
-            write_comma()
-            self.visit(arg)
-            if default is not None:
-                self.write('=')
-                self.visit(default)
-        if node.vararg is not None:
-            write_comma()
-            try:
-                self.write('*' + node.vararg.arg)
-            except AttributeError:  # CRUFT: python 2
-                self.write('*' + node.vararg)
-        if node.kwarg is not None:
-            write_comma()
-            try:
-                self.write('**' + node.kwarg.arg)
-            except AttributeError:  # CRUFT: python 2
-                self.write('*' + node.vararg)
-
-    def decorators(self, node):
-        for decorator in node.decorator_list:
-            self.newline(decorator)
-            self.write('@')
-            self.visit(decorator)
-
-    # Statements
-
-    def visit_Assert(self, node):
-        self.newline(node)
-        self.write('assert ')
-        self.visit(node.test)
-        if node.msg is not None:
-           self.write(', ')
-           self.visit(node.msg)
-
-    def visit_Assign(self, node):
-        self.newline(node)
-        for idx, target in enumerate(node.targets):
-            if idx:
-                self.write(', ')
-            self.visit(target)
-        self.write(' = ')
-        self.visit(node.value)
-
-    def visit_AugAssign(self, node):
-        self.newline(node)
-        self.visit(node.target)
-        self.write(' ' + BINOP_SYMBOLS[type(node.op)] + '= ')
-        self.visit(node.value)
-
-    def visit_ImportFrom(self, node):
-        self.newline(node)
-        self.write('from %s%s import ' % ('.' * node.level, node.module))
-        for idx, item in enumerate(node.names):
-            if idx:
-                self.write(', ')
-            self.write(item)
-
-    def visit_Import(self, node):
-        self.newline(node)
-        for item in node.names:
-            self.write('import ')
-            self.visit(item)
-
-    def visit_Expr(self, node):
-        self.newline(node)
-        self.generic_visit(node)
-
-    def visit_FunctionDef(self, node):
-        self.newline(extra=1)
-        self.decorators(node)
-        self.newline(node)
-        self.write('def %s(' % node.name)
-        self.visit(node.args)
-        self.write('):')
-        self.body(node.body)
-
-    def visit_ClassDef(self, node):
-        have_args = []
-        def paren_or_comma():
-            if have_args:
-                self.write(', ')
-            else:
-                have_args.append(True)
-                self.write('(')
-
-        self.newline(extra=2)
-        self.decorators(node)
-        self.newline(node)
-        self.write('class %s' % node.name)
-        for base in node.bases:
-            paren_or_comma()
-            self.visit(base)
-        # XXX: the if here is used to keep this module compatible
-        #      with python 2.6.
-        if hasattr(node, 'keywords'):
-            for keyword in node.keywords:
-                paren_or_comma()
-                self.write(keyword.arg + '=')
-                self.visit(keyword.value)
-            if node.starargs is not None:
-                paren_or_comma()
-                self.write('*')
-                self.visit(node.starargs)
-            if node.kwargs is not None:
-                paren_or_comma()
-                self.write('**')
-                self.visit(node.kwargs)
-        self.write(have_args and '):' or ':')
-        self.body(node.body)
-
-    def visit_If(self, node):
-        self.newline(node)
-        self.write('if ')
-        self.visit(node.test)
-        self.write(':')
-        self.body(node.body)
-        while True:
-            else_ = node.orelse
-            if len(else_) == 0:
-                break
-            elif len(else_) == 1 and isinstance(else_[0], ast.If):
-                node = else_[0]
-                self.newline()
-                self.write('elif ')
-                self.visit(node.test)
-                self.write(':')
-                self.body(node.body)
-            else:
-                self.newline()
-                self.write('else:')
-                self.body(else_)
-                break
-
-    def visit_For(self, node):
-        self.newline(node)
-        self.write('for ')
-        self.visit(node.target)
-        self.write(' in ')
-        self.visit(node.iter)
-        self.write(':')
-        self.body_or_else(node)
-
-    def visit_While(self, node):
-        self.newline(node)
-        self.write('while ')
-        self.visit(node.test)
-        self.write(':')
-        self.body_or_else(node)
-
-    def visit_With(self, node):
-        self.newline(node)
-        self.write('with ')
-        self.visit(node.context_expr)
-        if node.optional_vars is not None:
-            self.write(' as ')
-            self.visit(node.optional_vars)
-        self.write(':')
-        self.body(node.body)
-
-    def visit_Pass(self, node):
-        self.newline(node)
-        self.write('pass')
-
-    def visit_Print(self, node):
-        # XXX: python 2.6 only
-        self.newline(node)
-        self.write('print ')
-        want_comma = False
-        if node.dest is not None:
-            self.write(' >> ')
-            self.visit(node.dest)
-            want_comma = True
-        for value in node.values:
-            if want_comma:
-                self.write(', ')
-            self.visit(value)
-            want_comma = True
-        if not node.nl:
-            self.write(',')
-
-    def visit_Delete(self, node):
-        self.newline(node)
-        self.write('del ')
-        for idx, target in enumerate(node):
-            if idx:
-                self.write(', ')
-            self.visit(target)
-
-    def visit_TryExcept(self, node):
-        self.newline(node)
-        self.write('try:')
-        self.body(node.body)
-        for handler in node.handlers:
-            self.visit(handler)
-
-    def visit_TryFinally(self, node):
-        self.newline(node)
-        self.write('try:')
-        self.body(node.body)
-        self.newline(node)
-        self.write('finally:')
-        self.body(node.finalbody)
-
-    def visit_Global(self, node):
-        self.newline(node)
-        self.write('global ' + ', '.join(node.names))
-
-    def visit_Nonlocal(self, node):
-        self.newline(node)
-        self.write('nonlocal ' + ', '.join(node.names))
-
-    def visit_Return(self, node):
-        self.newline(node)
-        if node.value is None:
-            self.write('return')
-        else:
-            self.write('return ')
-            self.visit(node.value)
-
-    def visit_Break(self, node):
-        self.newline(node)
-        self.write('break')
-
-    def visit_Continue(self, node):
-        self.newline(node)
-        self.write('continue')
-
-    def visit_Raise(self, node):
-        # XXX: Python 2.6 / 3.0 compatibility
-        self.newline(node)
-        self.write('raise')
-        if hasattr(node, 'exc') and node.exc is not None:
-            self.write(' ')
-            self.visit(node.exc)
-            if node.cause is not None:
-                self.write(' from ')
-                self.visit(node.cause)
-        elif hasattr(node, 'type') and node.type is not None:
-            self.visit(node.type)
-            if node.inst is not None:
-                self.write(', ')
-                self.visit(node.inst)
-            if node.tback is not None:
-                self.write(', ')
-                self.visit(node.tback)
-
-    # Expressions
-
-    def visit_Attribute(self, node):
-        self.visit(node.value)
-        self.write('.' + node.attr)
-
-    def visit_Call(self, node):
-        want_comma = []
-        def write_comma():
-            if want_comma:
-                self.write(', ')
-            else:
-                want_comma.append(True)
-
-        self.visit(node.func)
-        self.write('(')
-        for arg in node.args:
-            write_comma()
-            self.visit(arg)
-        for keyword in node.keywords:
-            write_comma()
-            self.write(keyword.arg + '=')
-            self.visit(keyword.value)
-        if getattr(node, 'starargs', None) is not None:
-            write_comma()
-            self.write('*')
-            self.visit(node.starargs)
-        if getattr(node, 'kwargs', None) is not None:
-            write_comma()
-            self.write('**')
-            self.visit(node.kwargs)
-        self.write(')')
-
-    def visit_Name(self, node):
-        self.write(node.id)
-
-    def visit_Str(self, node):
-        self.write(repr(node.s))
-
-    def visit_Bytes(self, node):
-        self.write(repr(node.s))
-
-    def visit_Num(self, node):
-        self.write(repr(node.n))
-
-    def visit_Tuple(self, node):
-        self.write('(')
-        idx = -1
-        for idx, item in enumerate(node.elts):
-            if idx:
-                self.write(', ')
-            self.visit(item)
-        self.write(idx and ')' or ',)')
-
-    def sequence_visit(left, right):
-        def visit(self, node):
-            self.write(left)
-            for idx, item in enumerate(node.elts):
-                if idx:
-                    self.write(', ')
-                self.visit(item)
-            self.write(right)
-        return visit
-
-    visit_List = sequence_visit('[', ']')
-    visit_Set = sequence_visit('{', '}')
-    del sequence_visit
-
-    def visit_Dict(self, node):
-        self.write('{')
-        for idx, (key, value) in enumerate(zip(node.keys, node.values)):
-            if idx:
-                self.write(', ')
-            self.visit(key)
-            self.write(': ')
-            self.visit(value)
-        self.write('}')
-
-    def visit_BinOp(self, node):
-        self.visit(node.left)
-        self.write(' %s ' % BINOP_SYMBOLS[type(node.op)])
-        self.visit(node.right)
-
-    def visit_BoolOp(self, node):
-        self.write('(')
-        for idx, value in enumerate(node.values):
-            if idx:
-                self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)])
-            self.visit(value)
-        self.write(')')
-
-    def visit_Compare(self, node):
-        self.write('(')
-        self.visit(node.left)
-        for op, right in zip(node.ops, node.comparators):
-            self.write(' %s ' % CMPOP_SYMBOLS[type(op)])
-            self.visit(right)
-        self.write(')')
-
-    def visit_UnaryOp(self, node):
-        self.write('(')
-        op = UNARYOP_SYMBOLS[type(node.op)]
-        self.write(op)
-        if op == 'not':
-            self.write(' ')
-        self.visit(node.operand)
-        self.write(')')
-
-    def visit_Subscript(self, node):
-        self.visit(node.value)
-        self.write('[')
-        self.visit(node.slice)
-        self.write(']')
-
-    def visit_Slice(self, node):
-        if node.lower is not None:
-            self.visit(node.lower)
-        self.write(':')
-        if node.upper is not None:
-            self.visit(node.upper)
-        if node.step is not None:
-            self.write(':')
-            if not (isinstance(node.step, ast.Name) and node.step.id == 'None'):
-                self.visit(node.step)
-
-    def visit_ExtSlice(self, node):
-        for idx, item in node.dims:
-            if idx:
-                self.write(', ')
-            self.visit(item)
-
-    def visit_Yield(self, node):
-        self.write('yield ')
-        self.visit(node.value)
-
-    def visit_Lambda(self, node):
-        self.write('lambda ')
-        self.visit(node.args)
-        self.write(': ')
-        self.visit(node.body)
-
-    def visit_Ellipsis(self, node):
-        self.write('Ellipsis')
-
-    def generator_visit(left, right):
-        def visit(self, node):
-            self.write(left)
-            self.visit(node.elt)
-            for comprehension in node.generators:
-                self.visit(comprehension)
-            self.write(right)
-        return visit
-
-    visit_ListComp = generator_visit('[', ']')
-    visit_GeneratorExp = generator_visit('(', ')')
-    visit_SetComp = generator_visit('{', '}')
-    del generator_visit
-
-    def visit_DictComp(self, node):
-        self.write('{')
-        self.visit(node.key)
-        self.write(': ')
-        self.visit(node.value)
-        for comprehension in node.generators:
-            self.visit(comprehension)
-        self.write('}')
-
-    def visit_IfExp(self, node):
-        self.visit(node.body)
-        self.write(' if ')
-        self.visit(node.test)
-        self.write(' else ')
-        self.visit(node.orelse)
-
-    def visit_Starred(self, node):
-        self.write('*')
-        self.visit(node.value)
-
-    def visit_Repr(self, node):
-        # XXX: python 2.6 only
-        self.write('`')
-        self.visit(node.value)
-        self.write('`')
-
-    # Helper Nodes
-
-    def visit_alias(self, node):
-        self.write(node.name)
-        if node.asname is not None:
-            self.write(' as ' + node.asname)
-
-    def visit_comprehension(self, node):
-        self.write(' for ')
-        self.visit(node.target)
-        self.write(' in ')
-        self.visit(node.iter)
-        if node.ifs:
-            for if_ in node.ifs:
-                self.write(' if ')
-                self.visit(if_)
-
-    def visit_excepthandler(self, node):
-        self.newline(node)
-        self.write('except')
-        if node.type is not None:
-            self.write(' ')
-            self.visit(node.type)
-            if node.name is not None:
-                self.write(' as ')
-                self.visit(node.name)
-        self.write(':')
-        self.body(node.body)
-
-    def visit_arguments(self, node):
-        self.signature(node)
-
-# ===== inspect.getclosurevars backport begin =====
-
-# copied from python 3
-from inspect import ismethod, isfunction, ismodule
-from collections import namedtuple
-builtins = __builtins__
-ClosureVars = namedtuple('ClosureVars', 'nonlocals globals builtins unbound')
-def py2_getclosurevars(func):
-    """
-    Get the mapping of free variables to their current values.
-
-    Returns a named tuple of dicts mapping the current nonlocal, global
-    and builtin references as seen by the body of the function. A final
-    set of unbound names that could not be resolved is also provided.
-    """
-
-    if ismethod(func):
-        func = func.__func__
-
-    if not isfunction(func):
-        raise TypeError("'{!r}' is not a Python function".format(func))
-
-    code = func.__code__
-    # Nonlocal references are named in co_freevars and resolved
-    # by looking them up in __closure__ by positional index
-    if func.__closure__ is None:
-        nonlocal_vars = {}
-    else:
-        nonlocal_vars = {
-            var : cell.cell_contents
-            for var, cell in zip(code.co_freevars, func.__closure__)
-       }
-
-    # Global and builtin references are named in co_names and resolved
-    # by looking them up in __globals__ or __builtins__
-    global_ns = func.__globals__
-    builtin_ns = global_ns.get("__builtins__", builtins.__dict__)
-    if ismodule(builtin_ns):
-        builtin_ns = builtin_ns.__dict__
-    global_vars = {}
-    builtin_vars = {}
-    unbound_names = set()
-    for name in code.co_names:
-        if name in ("None", "True", "False"):
-            # Because these used to be builtins instead of keywords, they
-            # may still show up as name references. We ignore them.
-            continue
-        try:
-            global_vars[name] = global_ns[name]
-        except KeyError:
-            try:
-                builtin_vars[name] = builtin_ns[name]
-            except KeyError:
-                unbound_names.add(name)
-
-    return ClosureVars(nonlocal_vars, global_vars,
-                       builtin_vars, unbound_names)
-
-import inspect
-if not hasattr(inspect, 'getclosurevars'):
-    inspect.getclosurevars = py2_getclosurevars
-
-# ===== inspect.getclosurevars backport end ======
-
-def print_function(f=None):
-    """
-    Print out the code for the function
-    """
-    # Include some comments to see if they get printed
-    import ast
-    import inspect
-    print("function:", f.__code__.co_name)
-    print("closure:", inspect.getclosurevars(f))
-    print("locals:", f.__code__.co_nlocals, f.__code__.co_names)
-    if f is not None:
-        tree = ast.parse(inspect.getsource(f))
-        print(to_source(tree))
-
-from math import sin
-outside = '40 C'
-def _hello(*args, **kw):
-    x = sin(y) + cos(z.real)
-    print("world", outside)
-    a, b = x, y
-    [a, b] = (x, y)
-    (a, b) = [x, y]
-
-if __name__ == "__main__":
-    #print_function(print_function)
-    print_function(_hello)
Index: sasmodels/modelinfo.py
===================================================================
--- sasmodels/modelinfo.py	(revision 67cc0fff8de4365704eb57c72afe343290c477d4)
+++ sasmodels/modelinfo.py	(revision c01ed3e2bc363908dd28daf057e445c91561293d)
@@ -810,6 +810,4 @@
     info.sesans = getattr(kernel_module, 'sesans', None) # type: ignore
     # Default single and opencl to True for C models.  Python models have callable Iq.
-    info.opencl = getattr(kernel_module, 'opencl', not callable(info.Iq))
-    info.single = getattr(kernel_module, 'single', not callable(info.Iq))
     info.random = getattr(kernel_module, 'random', None)
 
@@ -827,4 +825,9 @@
         except Exception as exc:
             logger.warn(str(exc) + " while converting %s from C to python"%name)
+
+    # Needs to come after autoc.convert since the Iq symbol may have been
+    # converted from python to C
+    info.opencl = getattr(kernel_module, 'opencl', not callable(info.Iq))
+    info.single = getattr(kernel_module, 'single', not callable(info.Iq))
 
     if callable(info.Iq) and parameters.has_2d:
Index: sasmodels/models/_cylpy.py
===================================================================
--- sasmodels/models/_cylpy.py	(revision 67cc0fff8de4365704eb57c72afe343290c477d4)
+++ sasmodels/models/_cylpy.py	(revision c01ed3e2bc363908dd28daf057e445c91561293d)
@@ -140,4 +140,5 @@
 py2c = True
 
+# TODO: "#define INVALID (expr)" is not supported
 def invalid(v):
     return v.radius < 0 or v.length < 0
@@ -206,5 +207,5 @@
             phi_pd=10, phi_pd_n=5)
 
-qx, qy = 0.2 * np.cos(2.5), 0.2 * np.sin(2.5)
+qx, qy = 0.2 * cos(2.5), 0.2 * sin(2.5)
 # After redefinition of angles, find new tests values.  Was 10 10 in old coords
 tests = [
Index: sasmodels/py2c.py
===================================================================
--- sasmodels/py2c.py	(revision 7b1dcf924220a1a38691997b1962d9b6c8c934d1)
+++ sasmodels/py2c.py	(revision c01ed3e2bc363908dd28daf057e445c91561293d)
@@ -1,17 +1,14 @@
-
 """
-    codegen
-    ~~~~~~~
-
-    Extension to ast that allow ast -> python code generation.
-
-    :copyright: Copyright 2008 by Armin Ronacher.
-    :license: BSD.
-"""
-"""
+    py2c
+    ~~~~
+
+    Convert simple numeric python code into C code.
+
+    The translate() function works on
+
     Variables definition in C
     -------------------------
-    Defining variables within the Translate function is a bit of a guess work,
-    using following rules.
+    Defining variables within the translate function is a bit of a guess work,
+    using following rules:
     *   By default, a variable is a 'double'.
     *   Variable in a for loop is an int.
@@ -19,24 +16,32 @@
         variable within the brackets is integer. For example, in the
         reference 'var1[var2]', var1 is a double array, and var2 is an integer.
-    *   Assignment to an argument makes that argument an array, and the index in
-        that assignment is 0.
-        For example, the following python code
+    *   Assignment to an argument makes that argument an array, and the index
+        in that assignment is 0.
+        For example, the following python code::
             def func(arg1, arg2):
                 arg2 = 17.
-        is translated to the following C code
+        is translated to the following C code::
             double func(double arg1)
             {
                 arg2[0] = 17.0;
             }
-        For example, the following python code is translated to the following C code
+        For example, the following python code is translated to the
+        following C code::
+
             def func(arg1, arg2):          double func(double arg1) {
                 arg2 = 17.                      arg2[0] = 17.0;
                                             }
-    *   All functions are defined as double, even if there is no return statement.
-
-
+    *   All functions are defined as double, even if there is no
+        return statement.
+
+Based on codegen.py:
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: BSD.
+"""
+"""
 Update Notes
 ============
-11/22 14:15, O.E.   Each 'visit_*' method is to build a C statement string. It
+11/22/2017, O.E.   Each 'visit_*' method is to build a C statement string. It
                     shold insert 4 blanks per indentation level.
                     The 'body' method will combine all the strings, by adding
@@ -52,5 +57,5 @@
 12/07/2017, OE: Translation of integer division, '\\' in python, implemented
                 in translate_integer_divide, called from visit_BinOp
-12/07/2017, OE: C variable definition handled in 'define_C_Vars'
+12/07/2017, OE: C variable definition handled in 'define_c_vars'
               : Python integer division, '//', translated to C in
                 'translate_integer_divide'
@@ -102,26 +107,12 @@
 
 
-def to_source(node, func_name, constants=None):
-    """This function can convert a node tree back into python sourcecode.
-    This is useful for debugging purposes, especially if you're dealing with
-    custom asts not generated by python itself.
-
-    It could be that the sourcecode is evaluable when the AST itself is not
-    compilable / evaluable.  The reason for this is that the AST contains some
-    more data than regular sourcecode does, which is dropped during
-    conversion.
-
-    Each level of indentation is replaced with `indent_with`.  Per default this
-    parameter is equal to four spaces as suggested by PEP 8, but it might be
-    adjusted to match the application's styleguide.
-
-    If `add_line_information` is set to `True` comments for the line numbers
-    of the nodes are added to the output.  This can be used to spot wrong line
-    number information of statement nodes.
+def to_source(tree, constants=None, fname=None, lineno=0):
     """
-    generator = SourceGenerator(' ' * 4, False, constants)
-    generator.visit(node)
-
-    return ''.join(generator.c_proc)
+    This function can convert a syntax tree into C sourcecode.
+    """
+    generator = SourceGenerator(constants=constants, fname=fname, lineno=lineno)
+    generator.visit(tree)
+    c_code = "\n".join(generator.c_proc)
+    return c_code
 
 def isevaluable(s):
@@ -129,5 +120,5 @@
         eval(s)
         return True
-    except:
+    except Exception:
         return False
 
@@ -138,5 +129,6 @@
     """
 
-    def __init__(self, indent_with, add_line_information=False, constants=None):
+    def __init__(self, indent_with="    ", add_line_information=False,
+                 constants=None, fname=None, lineno=0):
         self.result = []
         self.indent_with = indent_with
@@ -144,24 +136,26 @@
         self.indentation = 0
         self.new_lines = 0
+
+        # for C
         self.c_proc = []
-        # for C
         self.signature_line = 0
         self.arguments = []
-        self.name = ""
+        self.current_function = ""
+        self.fname = fname
+        self.lineno_offset = lineno
         self.warnings = []
-        self.Statements = []
+        self.statements = []
         self.current_statement = ""
-        self.strMethodSignature = ""
-        self.C_Vars = []
-        self.C_IntVars = []
-        self.MathIncludeed = False
-        self.C_Pointers = []
-        self.C_DclPointers = []
-        self.C_Functions = []
-        self.C_Vectors = []
-        self.C_Constants = constants
-        self.SubRef = False
-        self.InSubscript = False
-        self.Tuples = []
+        # TODO: use set rather than list for c_vars, ...
+        self.c_vars = []
+        self.c_int_vars = []
+        self.c_pointers = []
+        self.c_dcl_pointers = []
+        self.c_functions = []
+        self.c_vectors = []
+        self.c_constants = constants if constants is not None else {}
+        self.in_subref = False
+        self.in_subscript = False
+        self.tuples = []
         self.required_functions = []
         self.is_sequence = False
@@ -176,14 +170,11 @@
         self.result.append(x)
 
-    def write_c(self, x):
-        self.current_statement += x
-
-    def add_c_line(self, x):
-        string = ''
-        for _ in range(self.indentation):
-            string += ("    ")
-        string += str(x)
-        self.c_proc.append(str(string + "\n"))
-        x = ''
+    def write_c(self, statement):
+        # TODO: build up as a list rather than adding to string
+        self.current_statement += statement
+
+    def add_c_line(self, line):
+        indentation = self.indent_with * self.indentation
+        self.c_proc.append("".join((indentation, line, "\n")))
 
     def add_current_line(self):
@@ -192,9 +183,9 @@
             self.current_statement = ''
 
-    def AddUniqueVar(self, new_var):
-        if new_var not in self.C_Vars:
-            self.C_Vars.append(str(new_var))
-
-    def WriteSincos(self, node):
+    def add_unique_var(self, new_var):
+        if new_var not in self.c_vars:
+            self.c_vars.append(str(new_var))
+
+    def write_sincos(self, node):
         angle = str(node.args[0].id)
         self.write_c(node.args[1].id + " = sin(" + angle + ");")
@@ -203,5 +194,5 @@
         self.add_current_line()
         for arg in node.args:
-            self.AddUniqueVar(arg.id)
+            self.add_unique_var(arg.id)
 
     def newline(self, node=None, extra=0):
@@ -211,5 +202,5 @@
             self.new_lines = 1
         if self.current_statement:
-            self.Statements.append(self.current_statement)
+            self.statements.append(self.current_statement)
             self.current_statement = ''
 
@@ -278,5 +269,5 @@
             self.visit(node.msg)
 
-    def define_C_Vars(self, target):
+    def define_c_vars(self, target):
         if hasattr(target, 'id'):
         # a variable is considered an array if it apears in the agrument list
@@ -287,13 +278,13 @@
         #  return
         #
-            if target.id not in self.C_Vars:
+            if target.id not in self.c_vars:
                 if target.id in self.arguments:
                     idx = self.arguments.index(target.id)
                     new_target = self.arguments[idx] + "[0]"
-                    if new_target not in self.C_Pointers:
+                    if new_target not in self.c_pointers:
                         target.id = new_target
-                        self.C_Pointers.append(self.arguments[idx])
+                        self.c_pointers.append(self.arguments[idx])
                 else:
-                    self.C_Vars.append(target.id)
+                    self.c_vars.append(target.id)
 
     def add_semi_colon(self):
@@ -308,9 +299,9 @@
             if idx:
                 self.write_c(' = ')
-            self.define_C_Vars(target)
+            self.define_c_vars(target)
             self.visit(target)
-        if self.Tuples:
-            tplTargets = list(self.Tuples)
-            del self.Tuples[:]
+        # Capture assigned tuple names, if any
+        targets = self.tuples[:]
+        del self.tuples[:]
         self.write_c(' = ')
         self.is_sequence = False
@@ -319,6 +310,8 @@
         self.add_semi_colon()
         self.add_current_line()
-        for n, item in enumerate(self.Tuples):
-            self.visit(tplTargets[n])
+        # Assign tuples to tuples, if any
+        # TODO: doesn't handle swap:  a,b = b,a
+        for target, item in zip(targets, self.tuples):
+            self.visit(target)
             self.write_c(' = ')
             self.visit(item)
@@ -328,15 +321,15 @@
             for target in node.targets:
                 if hasattr(target, 'id'):
-                    if target.id in self.C_Vars and target.id not in self.C_DclPointers:
-                        if target.id not in self.C_DclPointers:
-                            self.C_DclPointers.append(target.id)
-                            if target.id in self.C_Vars:
-                                self.C_Vars.remove(target.id)
+                    if target.id in self.c_vars and target.id not in self.c_dcl_pointers:
+                        if target.id not in self.c_dcl_pointers:
+                            self.c_dcl_pointers.append(target.id)
+                            if target.id in self.c_vars:
+                                self.c_vars.remove(target.id)
         self.current_statement = ''
 
     def visit_AugAssign(self, node):
-        if node.target.id not in self.C_Vars:
+        if node.target.id not in self.c_vars:
             if node.target.id not in self.arguments:
-                self.C_Vars.append(node.target.id)
+                self.c_vars.append(node.target.id)
         self.visit(node.target)
         self.write_c(' ' + BINOP_SYMBOLS[type(node.op)] + '= ')
@@ -346,4 +339,5 @@
 
     def visit_ImportFrom(self, node):
+        return  # import ignored
         self.newline(node)
         self.write_python('from %s%s import ' %('.' * node.level, node.module))
@@ -354,4 +348,5 @@
 
     def visit_Import(self, node):
+        return  # import ignored
         self.newline(node)
         for item in node.names:
@@ -363,17 +358,12 @@
         self.generic_visit(node)
 
-    def listToDeclare(self, vars):
-        return ", ".join(vars)
-
-    def write_C_Pointers(self, start_var):
-        if self.C_DclPointers:
+    def write_c_pointers(self, start_var):
+        if self.c_dcl_pointers:
             var_list = []
-            for c_ptr in self.C_DclPointers:
-                if(len(vars) > 0):
-                    vars += ", "
+            for c_ptr in self.c_dcl_pointers:
                 if c_ptr not in self.arguments:
                     var_list.append("*" + c_ptr)
-                if c_ptr in self.C_Vars:
-                    self.C_Vars.remove(c_ptr)
+                if c_ptr in self.c_vars:
+                    self.c_vars.remove(c_ptr)
             if var_list:
                 c_dcl = "    double " + ", ".join(var_list) + ";\n"
@@ -382,71 +372,69 @@
         return start_var
 
-    def insert_C_Vars(self, start_var):
-        fLine = False
-        start_var = self.write_C_Pointers(start_var)
-        if self.C_IntVars:
-            for var in self.C_IntVars:
-                if var in self.C_Vars:
-                    self.C_Vars.remove(var)
-            s = self.listToDeclare(self.C_IntVars)
-            self.c_proc.insert(start_var, "    int " + s + ";\n")
-            fLine = True
+    def insert_c_vars(self, start_var):
+        have_decls = False
+        start_var = self.write_c_pointers(start_var)
+        if self.c_int_vars:
+            for var in self.c_int_vars:
+                if var in self.c_vars:
+                    self.c_vars.remove(var)
+            decls = ", ".join(self.c_int_vars)
+            self.c_proc.insert(start_var, "    int " + decls + ";\n")
+            have_decls = True
             start_var += 1
 
-        if self.C_Vars:
-            s = self.listToDeclare(self.C_Vars)
-            self.c_proc.insert(start_var, "    double " + s + ";\n")
-            fLine = True
+        if self.c_vars:
+            decls = ", ".join(self.c_vars)
+            self.c_proc.insert(start_var, "    double " + decls + ";\n")
+            have_decls = True
             start_var += 1
 
-        if self.C_Vectors:
-            s = self.listToDeclare(self.C_Vectors)
-            for n in range(len(self.C_Vectors)):
-                name = "vec" + str(n+1)
-                c_dcl = "    double " + name + "[] = {" + self.C_Vectors[n] + "};"
-                self.c_proc.insert(start_var, c_dcl + "\n")
+        if self.c_vectors:
+            for vec_number, vec_value  in enumerate(self.c_vectors):
+                name = "vec" + str(vec_number + 1)
+                decl = "    double " + name + "[] = {" + vec_value + "};"
+                self.c_proc.insert(start_var, decl + "\n")
                 start_var += 1
 
-        del self.C_Vars[:]
-        del self.C_IntVars[:]
-        del self.C_Vectors[:]
-        del self.C_Pointers[:]
-        self.C_DclPointers
-        if fLine:
+        del self.c_vars[:]
+        del self.c_int_vars[:]
+        del self.c_vectors[:]
+        del self.c_pointers[:]
+        del self.c_dcl_pointers[:]
+        if have_decls:
             self.c_proc.insert(start_var, "\n")
 
-    def InsertSignature(self):
+    def insert_signature(self):
         arg_decls = []
         for arg in self.arguments:
             decl = "double " + arg
-            if arg in self.C_Pointers:
+            if arg in self.c_pointers:
                 decl += "[]"
             arg_decls.append(decl)
         args_str = ", ".join(arg_decls)
-        self.strMethodSignature = 'double ' + self.name + '(' + args_str + ")"
+        method_sig = 'double ' + self.current_function + '(' + args_str + ")"
         if self.signature_line >= 0:
-            self.c_proc.insert(self.signature_line, self.strMethodSignature)
+            self.c_proc.insert(self.signature_line, method_sig)
 
     def visit_FunctionDef(self, node):
+        if self.current_function:
+            self.unsupported(node, "function within a function")
+        self.current_function = node.name
+
         self.newline(extra=1)
         self.decorators(node)
         self.newline(node)
         self.arguments = []
-        self.name = node.name
-        #if self.name not in self.required_functions[0]:
-        #   return
-        #print("Parsing '" + self.name + "'")
-
         self.visit(node.args)
         # for C
         self.signature_line = len(self.c_proc)
-        #self.add_c_line(self.strMethodSignature)
         self.add_c_line("\n{")
         start_vars = len(self.c_proc) + 1
         self.body(node.body)
         self.add_c_line("}\n")
-        self.InsertSignature()
-        self.insert_C_Vars(start_vars)
-        self.C_Pointers = []
+        self.insert_signature()
+        self.insert_c_vars(start_vars)
+        self.c_pointers = []
+        self.current_function = ""
 
     def visit_ClassDef(self, node):
@@ -511,22 +499,5 @@
                 break
 
-    def getNodeLineNo(self, node):
-        line_number = -1
-        if hasattr(node, 'value'):
-            line_number = node.value.lineno
-        elif hasattr(node, 'iter'):
-            if hasattr(node.iter, 'lineno'):
-                line_number = node.iter.lineno
-        return line_number
-
-    def GetNodeAsString(self, node):
-        res = ''
-        if hasattr(node, 'n'):
-            res = str(node.n)
-        elif hasattr(node, 'id'):
-            res = node.id
-        return res
-
-    def GetForRange(self, node):
+    def get_for_range(self, node):
         stop = ""
         start = '0'
@@ -565,7 +536,7 @@
                     iterator = self.current_statement
                     self.current_statement = ''
-                    if iterator not in self.C_IntVars:
-                        self.C_IntVars.append(iterator)
-                    start, stop, step = self.GetForRange(node)
+                    if iterator not in self.c_int_vars:
+                        self.c_int_vars.append(iterator)
+                    start, stop, step = self.get_for_range(node)
                     self.write_c("for(" + iterator + "=" + str(start) +
                                  " ; " + iterator + " < " + str(stop) +
@@ -575,5 +546,5 @@
                     fForDone = True
         if not fForDone:
-            line_number = self.getNodeLineNo(node)
+            # Generate the statement that is causing the error
             self.current_statement = ''
             self.write_c('for ')
@@ -582,7 +553,6 @@
             self.visit(node.iter)
             self.write_c(':')
-            errStr = "Conversion Error in function " + self.name + ", Line #" + str(line_number)
-            errStr += "\nPython for expression not supported: '" + self.current_statement + "'"
-            raise Exception(errStr)
+            # report the error
+            self.unsupported("unsupported " + self.current_statement)
 
     def visit_While(self, node):
@@ -594,4 +564,5 @@
 
     def visit_With(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('with ')
@@ -605,7 +576,9 @@
     def visit_Pass(self, node):
         self.newline(node)
-        self.write_python('pass')
+        #self.write_python('pass')
 
     def visit_Print(self, node):
+        # TODO: print support would be nice, though hard to do
+        self.unsupported(node)
         # CRUFT: python 2.6 only
         self.newline(node)
@@ -625,4 +598,5 @@
 
     def visit_Delete(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('del ')
@@ -633,4 +607,5 @@
 
     def visit_TryExcept(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('try:')
@@ -640,4 +615,5 @@
 
     def visit_TryFinally(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('try:')
@@ -648,4 +624,5 @@
 
     def visit_Global(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('global ' + ', '.join(node.names))
@@ -676,4 +653,5 @@
 
     def visit_Raise(self, node):
+        self.unsupported(node)
         # CRUFT: Python 2.6 / 3.0 compatibility
         self.newline(node)
@@ -697,7 +675,5 @@
 
     def visit_Attribute(self, node):
-        errStr = "Conversion Error in function " + self.name + ", Line #" + str(node.value.lineno)
-        errStr += "\nPython expression not supported: '" + node.value.id + "." + node.attr + "'"
-        raise Exception(errStr)
+        self.unsupported(node, "attribute reference a.b not supported")
         self.visit(node.value)
         self.write_python('.' + node.attr)
@@ -711,6 +687,6 @@
                 want_comma.append(True)
         if hasattr(node.func, 'id'):
-            if node.func.id not in self.C_Functions:
-                self.C_Functions.append(node.func.id)
+            if node.func.id not in self.c_functions:
+                self.c_functions.append(node.func.id)
             if node.func.id == 'abs':
                 self.write_c("fabs ")
@@ -718,5 +694,5 @@
                 self.write_c('(int) ')
             elif node.func.id == "SINCOS":
-                self.WriteSincos(node)
+                self.write_sincos(node)
                 return
             else:
@@ -724,5 +700,4 @@
         else:
             self.visit(node.func)
-#self.C_Functions
         self.write_c('(')
         for arg in node.args:
@@ -748,5 +723,5 @@
     def visit_Name(self, node):
         self.write_c(node.id)
-        if node.id in self.C_Pointers and not self.SubRef:
+        if node.id in self.c_pointers and not self.in_subref:
             self.write_c("[0]")
         name = ""
@@ -756,12 +731,12 @@
         else:
             name = node.id
-        # add variable to C_Vars if it ins't there yet, not an argument and not a number
-        if (name not in self.C_Functions and name not in self.C_Vars and
-                name not in self.C_IntVars and name not in self.arguments and
-                name not in self.C_Constants and not name.isdigit()):
-            if self.InSubscript:
-                self.C_IntVars.append(node.id)
+        # add variable to c_vars if it ins't there yet, not an argument and not a number
+        if (name not in self.c_functions and name not in self.c_vars and
+                name not in self.c_int_vars and name not in self.arguments and
+                name not in self.c_constants and not name.isdigit()):
+            if self.in_subscript:
+                self.c_int_vars.append(node.id)
             else:
-                self.C_Vars.append(node.id)
+                self.c_vars.append(node.id)
 
     def visit_Str(self, node):
@@ -777,5 +752,5 @@
         for idx, item in enumerate(node.elts):
             if idx:
-                self.Tuples.append(item)
+                self.tuples.append(item)
             else:
                 self.visit(item)
@@ -793,6 +768,6 @@
                     s += str(item.n)
             if s:
-                self.C_Vectors.append(s)
-                vec_name = "vec"  + str(len(self.C_Vectors))
+                self.c_vectors.append(s)
+                vec_name = "vec"  + str(len(self.c_vectors))
                 self.write_c(vec_name)
         return visit
@@ -803,4 +778,5 @@
 
     def visit_Dict(self, node):
+        self.unsupported(node)
         self.write_python('{')
         for idx, (key, value) in enumerate(zip(node.keys, node.values)):
@@ -901,14 +877,14 @@
 
     def visit_Subscript(self, node):
-        if node.value.id not in self.C_Constants:
-            if node.value.id not in self.C_Pointers:
-                self.C_Pointers.append(node.value.id)
-        self.SubRef = True
+        if node.value.id not in self.c_constants:
+            if node.value.id not in self.c_pointers:
+                self.c_pointers.append(node.value.id)
+        self.in_subref = True
         self.visit(node.value)
-        self.SubRef = False
+        self.in_subref = False
         self.write_c('[')
-        self.InSubscript = True
+        self.in_subscript = True
         self.visit(node.slice)
-        self.InSubscript = False
+        self.in_subscript = False
         self.write_c(']')
 
@@ -931,8 +907,10 @@
 
     def visit_Yield(self, node):
+        self.unsupported(node)
         self.write_python('yield ')
         self.visit(node.value)
 
     def visit_Lambda(self, node):
+        self.unsupported(node)
         self.write_python('lambda ')
         self.visit(node.args)
@@ -941,4 +919,5 @@
 
     def visit_Ellipsis(self, node):
+        self.unsupported(node)
         self.write_python('Ellipsis')
 
@@ -960,4 +939,5 @@
 
     def visit_DictComp(self, node):
+        self.unsupported(node)
         self.write_python('{')
         self.visit(node.key)
@@ -988,4 +968,5 @@
 
     def visit_alias(self, node):
+        self.unsupported(node)
         self.write_python(node.name)
         if node.asname is not None:
@@ -1005,4 +986,24 @@
     def visit_arguments(self, node):
         self.signature(node)
+
+    def unsupported(self, node, message=None):
+        if hasattr(node, "value"):
+            lineno = node.value.lineno
+        elif hasattr(node, "iter"):
+            lineno = node.iter.lineno
+        else:
+            #print(dir(node))
+            lineno = 0
+
+        lineno += self.lineno_offset
+        if self.fname:
+            location = "%s(%d)" % (self.fname, lineno)
+        else:
+            location = "%d" % (self.fname, lineno)
+        if self.current_function:
+            location += ", function %s" % self.current_function
+        if message is None:
+            message = node.__class__.__name__ + " syntax not supported"
+        raise SyntaxError("[%s] %s" % (location, message))
 
 def print_function(f=None):
@@ -1018,14 +1019,89 @@
         print(tree_source)
 
-def translate(functions, constants=0):
+def define_constant(name, value, block_size=1):
+    # type: (str, any, int) -> str
+    """
+    Convert a python constant into a C constant of the same name.
+
+    Returns the C declaration of the constant as a string, possibly containing
+    line feeds.  The string will not be indented.
+
+    Supports int, double and sequences of double.
+    """
+    const = "constant "  # OpenCL needs globals to be constant
+    if isinstance(value, int):
+        parts = [const + "int ", name, " = ", "%d"%value, ";"]
+    elif isinstance(value, float):
+        parts = [const + "double ", name, " = ", "%.15g"%value, ";"]
+    else:
+        try:
+            len(value)
+        except TypeError:
+            raise TypeError("constant %s must be int, float or [float, ...]"%name)
+        # extend constant arrays to a multiple of 4; not sure if this
+        # is necessary, but some OpenCL targets broke if the number
+        # of parameters in the parameter table was not a multiple of 4,
+        # so do it for all constant arrays to be safe.
+        if len(value)%block_size != 0:
+            value = list(value) + [0.]*(block_size - len(value)%block_size)
+        elements = ["%.15g"%v for v in value]
+        parts = [const + "double ", name, "[]", " = ",
+                 "{\n   ", ", ".join(elements), "\n};"]
+
+    return "".join(parts)
+
+
+# Modified from the following:
+#
+#    http://code.activestate.com/recipes/578272-topological-sort/
+#    Copyright (C) 2012 Sam Denton
+#    License: MIT
+def ordered_dag(dag):
+    # type: (Dict[T, Set[T]]) -> Iterator[T]
+    """
+    Given a dag defined by a dictionary of {k1: [k2, ...]} yield keys
+    in order such that every key occurs after the keys it depends upon.
+
+    This is an iterator not a sequence.  To reverse it use::
+
+        reversed(tuple(ordered_dag(dag)))
+
+    Raise an error if there are any cycles.
+
+    Keys are arbitrary hashable values.
+    """
+    # Local import to make the function stand-alone, and easier to borrow
+    from functools import reduce
+
+    dag = dag.copy()
+
+    # make leaves depend on the empty set
+    leaves = reduce(set.union, dag.values()) - set(dag.keys())
+    dag.update({node: set() for node in leaves})
+    while True:
+        leaves = set(node for node, links in dag.items() if not links)
+        if not leaves:
+            break
+        for node in leaves:
+            yield node
+        dag = {node: (links-leaves)
+               for node, links in dag.items() if node not in leaves}
+    if dag:
+        raise ValueError("Cyclic dependes exists amongst these items:\n%s"
+                         % ", ".join(str(node) for node in dag.keys()))
+
+def translate(functions, constants=None):
+    # type: (List[(str, str, int)], Dict[str, any]) -> List[str]
+    """
+    Convert a set of functions
+    """
     snippets = []
     #snippets.append("#include <math.h>")
     #snippets.append("")
-    for source, fname, line_no in functions:
-        line_directive = '#line %d "%s"'%(line_no, fname.replace('\\', '\\\\'))
+    for source, fname, lineno in functions:
+        line_directive = '#line %d "%s"'%(lineno, fname.replace('\\', '\\\\'))
         snippets.append(line_directive)
         tree = ast.parse(source)
-        # in the future add filename, offset, constants
-        c_code = to_source(tree, functions, constants)
+        c_code = to_source(tree, constants=constants, fname=fname, lineno=lineno)
         snippets.append(c_code)
     return snippets
@@ -1051,6 +1127,11 @@
     with open(fname_in, "r") as python_file:
         code = python_file.read()
-
-    translation = translate([code, fname_in, 1])[0]
+    name = "gauss"
+    code = (code
+            .replace(name+'.n', 'GAUSS_N')
+            .replace(name+'.z', 'GAUSS_Z')
+            .replace(name+'.w', 'GAUSS_W'))
+
+    translation = translate([(code, fname_in, 1)])[0]
 
     with open(fname_out, "w") as file_out:
