def phasespace3(M, m1, m2, m3): """Calculate the full three body phase space: >>> M, m1 , m2 , m3 = ... >>> ps3 = phasespace3 ( M , m1 , m2 , m3 ) - The algorithm includes two embedded numerical integration -> could be slow """ assert 0 <= M and 0 <= m1 and 0 <= m2 and 0 <= m3, 'Invalid setting of masses!' ## if m1 + m2 + m3 >= M: return 0 ## RETURN! s = M * M m1_2 = m1 * m1 m2_2 = m2 * m2 m3_2 = m3 * m3 high = (M - m1)**2 low = (m2 + m3)**2 import math func = lambda x: math.sqrt(kallen(x, s, m1_2) * kallen(x, m2_2, m3_2)) / x from ostap.math.integral import integral r = integral(func, low, high, err=False) return (math.pi**2) * r / (4.0 * s)
def __call__(self, func, *args): ## additional arguments args = args if args else self.args # ## define integration rules # if hasattr(func, 'integral'): _integral_ = lambda f, low, high: f.integral(low, high, *args) else: from ostap.math.integral import integral _integral_ = lambda f, low, high: integral(f, low, high, *args) # ## xmin/max # xmin, xmax = self.xmin, self.xmax # ## calculate x0 as "mean"-value # x0 = self.x0 if x0 is None: if hasattr(func, 'mean'): x0 = func.mean() else: m = Mean(xmin, xmax, False) x0 = m(func, *args) # ## check validity of x0 # if not xmin <= x0 <= xmax: raise AttributeError("Invalid x0 value %s<=%s<=%s" % (xmin, x0, xmax)) # ## get the normalization # norm = _integral_(func, xmin, xmax) if 0 >= norm: raise AttributeError("Normalization integral is not positive %s" % norm) # ## Equation: ifun(x) \equiv \int_{x0-x}^{x0+x}f(t)dt - N*prob = 0 # yval = self.prob * norm def ifun(x): if 0 >= x: return -yval return _integral_(func, max(xmin, x0 - x), min(xmax, x0 + x)) - yval from ostap.math.rootfinder import findroot s = findroot(ifun, 0, max(xmax - x0, x0 - xmin)) from ostap.math.ve import VE return VE(x0, s * s)
def distance(fun1, fun2, low, high): """calculate ``distance'' between two functions""" df = lambda x: abs(fun1(x) - fun2(x)) from ostap.math.integral import integral di = integral(df, low, high) return di / (high - low)
def phasespace4(M, m1, m2, m3, m4): """Calculate the full four body phase space >>> M, m1 , m2 , m3 , m4 = ... >>> ps4 = phasespace4 ( M , m1 , m2 , m3 , m4 ) - The algorithm includes two embedded numerical integration -> could be relatively slow """ assert 0 <= M and 0 <= m1 and 0 <= m2 and 0 <= m3 and 0 <= m4, 'Invalid setting of masses!' ## if m1 + m2 + m3 + m4 >= M: return 0 ## RETURN! low = m1 + m2 high = M - m3 - m4 func = lambda x: 2.0 * x * phasespace3(M, x, m3, m4) * phasespace2( x, m1, m2) from ostap.math.integral import integral return integral(func, low, high, err=False)
def _tf2_integrate_X_(tf2, y, xlow=None, xhigh=None): r"""Integrate TF2 over range in X f = \int_{x_{low}}^{x_{high}} f(x,y) dx >>> func = ROOT.TF2( ... ) >>> a = func.integrate_X ( y , xlow , xhigh ) """ ## check Y ymin, ymax = tf2.yminmax() if not ymin <= y <= ymax: return 0 ## check X xmin, xmax = tf2.yminmax() if None is xlow: xlow = xmin if None is xhigh: xhigh = xmax xmin = max(xmin, xlow) xmax = min(xmax, xhigh) ## func_x = lambda x: tf2(x, y) from ostap.math.integral import integral return integral(func_x, xmin, xmax)
def _tf2_integrate_Y_(tf2, x, ylow=None, yhigh=None): r"""Integrate TF2 over range in Y f = \int_{y_{low}}^{y_{high}} f(x,y) dy >>> func = ROOT.TF2( ... ) >>> a = func.integrate_Y ( x , ylow , yhigh ) """ ## check X xmin, xmax = tf2.xminmax() if not xmin <= x <= xmax: return 0 ## check Y ymin, ymax = tf2.yminmax() if None is ylow: ylow = ymin if None is yhigh: yhigh = ymax ymin = max(ymin, ylow) ymax = min(ymax, yhigh) ## func_y = lambda y: tf2(x, y) from ostap.math.integral import integral return integral(func_y, ymin, ymax)
def test_integral(): from math import sin, cos, exp, log, pi, e from ostap.math.integral import integral, romberg funcs = [(sin, 0, pi, 2), (cos, 0, pi, 0), (exp, 0, 1, e - 1), (log, 1.e-50, 1, -1)] for entry in funcs: args = entry[:3] vi = integral(*entry[:3], err=True) vr = romberg(*entry[:3], err=True, maxdepth=100) value = entry[3] func = 'int(%s,%g,%g)' % (entry[0].__name__, entry[1], entry[2]) logger.info('%20s: I %-20s %-20s' % (func, vi, vr)) logger.info('%20s: Delta %-20s %-20s' % (func, vi - value, vr - value)) logger.info('%20s: Delta/I %-20s %-20s' % (func, (vi - value) / vi.error(), (vr - value) / vr.error()))
def phasespace(M, *args): """Calculate full N-body phase space >>> M, m1 , m2 , ... , mn = ... >>> ps = phasespace ( M , m1 , m2 , ... , mn ) - The algorithm includes embedded numerical integrations -> could be relatively slow """ assert 0 <= M and 2 <= len(args), 'Invalid setting of masses!' summ = 0.0 for m in args: assert 0 <= m, 'Invalid setting of masses' summ += m if summ >= M: return 0 N = len(args) if 2 == N: return phasespace2(M, *args) elif 3 == N: return phasespace3(M, *args) elif 4 == N: return phasespace4(M, *args) ## split particles into two groups & (recursively) apply the splitting formula k = N / 2 args1 = args[k:] args2 = args[:k] low = sum(args1) high = M - sum(args2) func = lambda x: 2.0 * x * phasespace(M, x, *args2) * phasespace(x, *args1) from ostap.math.integral import integral return integral(func, low, high, err=False)
def __call__(self, func, *args): ## additional arguments args = args if args else self.args # ## define integration rules # if hasattr(func, 'integral'): _integral_ = lambda f, low, high: f.integral(low, high, *args) else: from ostap.math.integral import integral _integral_ = lambda f, low, high: integral(f, low, high, *args) # ## xmin/max # xmin, xmax = self.xmin, self.xmax # # calculate mode if hasattr(func, 'mode'): xmode = func.mode() else: md = Mode(xmin, xmax) xmode = md(func, *args) if not xmin <= xmode <= xmax: raise AttributeError("Invalid mode value %s<=%s<=%s" % (xmin, xmode, xmax)) # ## get the normalization # norm = _integral_(func, xmin, xmax) if 0 >= norm: raise AttributeError("Normalization integral is not positive %s" % norm) normL = _integral_(func, xmin, xmode) normR = _integral_(func, xmode, xmax) from ostap.math.base import isequal, iszero ## solve equation f(x)=a def _solve_(func, fval, xmn, xmx, *args): ## if isequal(xmn, xmx): return xmn ## ifun = lambda x, *a: func(x, *a) - fval ## fmn = ifun(xmn) if iszero(ifun(xmn)): return xmn fmx = ifun(xmx) if iszero(ifun(xmx)): return xmx ## if 0 < fmx * fmn: ## more or less arbitrary choice return xmx if abs(fmx) <= abs(fmn) else xmn # from ostap.math.rootfinder import findroot return findroot(ifun, xmn, xmx, args=args) yval = self.prob * norm fm = func(xmode) def iifun(f): if iszero(f): x1, x2 = xmin, xmax elif isequal(f, fm): return -yval else: x1 = _solve_(func, f, xmin, xmode) x2 = _solve_(func, f, xmode, xmax) return _integral_(func, x1, x2) - yval from ostap.math.rootfinder import findroot l = findroot(iifun, 0, func(xmode)) x1 = _solve_(func, l, xmin, xmode) x2 = _solve_(func, l, xmode, xmax) return x1, x2