def _expression_mathfunction(expr, parameters): name_map = { 'abs': 'fabs', 'ln': 'log', # Bessel functions 'cyl_bessel_j': 'jn', 'cyl_bessel_y': 'yn', # Modified Bessel functions (C++ only) # # These mappings work for FEniCS only, and fail with Firedrake # since no Boost available. 'cyl_bessel_i': 'boost::math::cyl_bessel_i', 'cyl_bessel_k': 'boost::math::cyl_bessel_k', } name = name_map.get(expr.name, expr.name) if name == 'jn': nu, arg = expr.children if nu == gem.Zero(): return coffee.FunCall('j0', expression(arg, parameters)) elif nu == gem.one: return coffee.FunCall('j1', expression(arg, parameters)) if name == 'yn': nu, arg = expr.children if nu == gem.Zero(): return coffee.FunCall('y0', expression(arg, parameters)) elif nu == gem.one: return coffee.FunCall('y1', expression(arg, parameters)) return coffee.FunCall(name, *[expression(c, parameters) for c in expr.children])
def _expression_mathfunction(expr, ctx): from tsfc.coffee import math_table math_table = math_table.copy() math_table['abs'] = ('abs', 'cabs') complex_mode = int(is_complex(ctx.scalar_type)) # Bessel functions if expr.name.startswith('cyl_bessel_'): if complex_mode: msg = "Bessel functions for complex numbers: missing implementation" raise NotImplementedError(msg) nu, arg = expr.children nu_thunk = lambda: expression(nu, ctx) arg_loopy = expression(arg, ctx) if expr.name == 'cyl_bessel_j': if nu == gem.Zero(): return p.Variable("j0")(arg_loopy) elif nu == gem.one: return p.Variable("j1")(arg_loopy) else: return p.Variable("jn")(nu_thunk(), arg_loopy) if expr.name == 'cyl_bessel_y': if nu == gem.Zero(): return p.Variable("y0")(arg_loopy) elif nu == gem.one: return p.Variable("y1")(arg_loopy) else: return p.Variable("yn")(nu_thunk(), arg_loopy) # Modified Bessel functions (C++ only) # # These mappings work for FEniCS only, and fail with Firedrake # since no Boost available. if expr.name in ['cyl_bessel_i', 'cyl_bessel_k']: name = 'boost::math::' + expr.name return p.Variable(name)(nu_thunk(), arg_loopy) assert False, "Unknown Bessel function: {}".format(expr.name) # Other math functions name = math_table[expr.name][complex_mode] if name is None: raise RuntimeError("{} not supported in complex mode".format(expr.name)) return p.Variable(name)(*[expression(c, ctx) for c in expr.children])
def _expression_mathfunction(expr, ctx): if expr.name.startswith('cyl_bessel_'): # Bessel functions if is_complex(ctx.scalar_type): raise NotImplementedError("Bessel functions for complex numbers: " "missing implementation") nu, arg = expr.children nu_ = expression(nu, ctx) arg_ = expression(arg, ctx) # Modified Bessel functions (C++ only) # # These mappings work for FEniCS only, and fail with Firedrake # since no Boost available. if expr.name in {'cyl_bessel_i', 'cyl_bessel_k'}: name = 'boost::math::' + expr.name return p.Variable(name)(nu_, arg_) else: # cyl_bessel_{jy} -> {jy} name = expr.name[-1:] if nu == gem.Zero(): return p.Variable(f"{name}0")(arg_) elif nu == gem.one: return p.Variable(f"{name}1")(arg_) else: return p.Variable(f"{name}n")(nu_, arg_) else: if expr.name == "ln": name = "log" else: name = expr.name # Not all mathfunctions apply to complex numbers, but this # will be picked up in loopy. This way we allow erf(real(...)) # in complex mode (say). return p.Variable(name)(*(expression(c, ctx) for c in expr.children))
def _expression_mathfunction(expr, parameters): name_map = { 'abs': 'fabs', 'ln': 'log', # Bessel functions 'cyl_bessel_j': 'jn', 'cyl_bessel_y': 'yn', # Modified Bessel functions (C++ only) # # These mappings work for FEniCS only, and fail with Firedrake # since no Boost available. 'cyl_bessel_i': 'boost::math::cyl_bessel_i', 'cyl_bessel_k': 'boost::math::cyl_bessel_k', } complex_name_map = { 'ln': 'clog', 'conj': 'conj' # TODO: Are there different complex Bessel Functions? } if parameters.scalar_type == 'double complex': name = complex_name_map.get(expr.name, expr.name) if name in { 'sin', 'cos', 'tan', 'sqrt', 'exp', 'abs', 'sinh', 'cosh', 'tanh', 'sinh', 'acos', 'asin', 'atan', 'real', 'imag' }: name = 'c' + expr.name else: name = name_map.get(expr.name, expr.name) if name == 'jn': nu, arg = expr.children if nu == gem.Zero(): return coffee.FunCall('j0', expression(arg, parameters)) elif nu == gem.one: return coffee.FunCall('j1', expression(arg, parameters)) if name == 'yn': nu, arg = expr.children if nu == gem.Zero(): return coffee.FunCall('y0', expression(arg, parameters)) elif nu == gem.one: return coffee.FunCall('y1', expression(arg, parameters)) return coffee.FunCall(name, *[expression(c, parameters) for c in expr.children])
def _expression_mathfunction(expr, parameters): complex_mode = int(is_complex(parameters.scalar_type)) # Bessel functions if expr.name.startswith('cyl_bessel_'): if complex_mode: msg = "Bessel functions for complex numbers: missing implementation" raise NotImplementedError(msg) nu, arg = expr.children nu_thunk = lambda: expression(nu, parameters) arg_coffee = expression(arg, parameters) if expr.name == 'cyl_bessel_j': if nu == gem.Zero(): return coffee.FunCall('j0', arg_coffee) elif nu == gem.one: return coffee.FunCall('j1', arg_coffee) else: return coffee.FunCall('jn', nu_thunk(), arg_coffee) if expr.name == 'cyl_bessel_y': if nu == gem.Zero(): return coffee.FunCall('y0', arg_coffee) elif nu == gem.one: return coffee.FunCall('y1', arg_coffee) else: return coffee.FunCall('yn', nu_thunk(), arg_coffee) # Modified Bessel functions (C++ only) # # These mappings work for FEniCS only, and fail with Firedrake # since no Boost available. if expr.name in ['cyl_bessel_i', 'cyl_bessel_k']: name = 'boost::math::' + expr.name return coffee.FunCall(name, nu_thunk(), arg_coffee) assert False, "Unknown Bessel function: {}".format(expr.name) # Other math functions name = math_table[expr.name][complex_mode] if name is None: raise RuntimeError("{} not supported in complex mode".format( expr.name)) return coffee.FunCall(name, *[expression(c, parameters) for c in expr.children])