In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.stats import norm
plt.style.use('ggplot')
Eine experimentelle Verteilung in den Variablen $(x, m)$ habe eine Signalkomponente $s(x, m)$ = $s(x)s(m)$ und eine Untergrundkomponente $b(x,m)$ = $b(x)b(m)$. Der erlaubte Bereich ist $0 < x < 1$ und $0 < m < 1$. Es sei $s(m)$ eine Gaussverteilung mit Mittelwert $\mu = 0.5$ und Standardabweichung $\sigma = 0.05$. Die Verteilungen der anderen Komponenten werden aus gleichverteilten Zufallzahlen $z$ gewonnen. Für $s(x)$ verwende man $x = −0.2\ln{z}$, für $b(m)$ verwende man $m = \sqrt{z}$ und für $b(x)$ die Transformation $x = 1 − \sqrt{z}$.
Erzeugen Sie für zwei angenommene Effizienzfunktionen
Datensätze von Paaren $(x, m)$ die 20000 akzeptierte Signalereignisse und 100000 akzeptierte Untergrundereignisse umfassen. Betrachten Sie nun die gemeinsame $m$-Verteilung und parametrisieren Sie diese durch
\begin{equation} f(m) = s(m) + b(m) \end{equation}mit
\begin{equation} s(m) = p_0 \exp\left(-\frac{(m - p_1)^2}{2p_2^2}\right) \end{equation}und
\begin{equation} b(m) = p_3 + p_4m + p_5m^2 + p_6\sqrt{m} \,. \end{equation}Für den Fall $\varepsilon(x, m) = (x + m)/2$ benutzen Sie die obige Parametrisierung auch zur Beschreibung der $m_c$ und $m_{cc}$-Verteilungen, für die jeder $m$-Wert mit $1/\varepsilon(x, m)$, bzw. $1/\varepsilon^2(x, m)$ gewichtet wird, und die für die korrekte Behandlung von nicht-konstanten Effizienzen benötigt werden.
In [2]:
def generate_sx(size):
xs = -0.2 * np.log(np.random.uniform(size=2 * size))
xs = xs[xs < 1]
return xs[:size]
def generate_sm(size):
return np.random.normal(0.5, 0.05, size=size)
def generate_s(size):
return np.array([generate_sx(size), generate_sm(size)])
def generate_bx(size):
return 1 - np.sqrt(np.random.uniform(size=size))
def generate_bm(size):
return np.sqrt(np.random.uniform(size=size))
def generate_b(size):
return np.array([generate_bx(size), generate_bm(size)])
def generate_sample(sig_size=20000, bkg_size=100000):
return np.append(generate_s(sig_size), generate_b(bkg_size), axis=1)
def efficiency(x, m):
return (x + m) / 2
def generate_with_efficiency(generator, efficiency, size):
def reset():
xs, ms = generator(size)
effs = efficiency(xs, ms)
accept = np.random.uniform(size=size) > effs
return np.array([xs[accept], ms[accept]])
sample = reset()
while sample.shape[1] < size:
sample = np.append(sample, reset(), axis=1)
return sample[:size]
def generate_sample_with_efficiency(efficiency, sig_size=20000, bkg_size=100000):
return np.append(generate_with_efficiency(generate_s, efficiency, sig_size),
generate_with_efficiency(generate_b, efficiency, bkg_size),
axis=1)
n = 20000
xs, ms = generate_sample()
xs_s, xs_b = xs[:n], xs[n:]
ms_s, ms_b = ms[:n], ms[n:]
plt.hist([xs_s, xs_b], bins=40, histtype='barstacked', label=['Signal', 'Background'])
plt.xlabel(r'$x$')
plt.legend()
plt.show()
plt.hist([ms_s, ms_b], bins=40, histtype='barstacked', label=['Signal', 'Background'])
plt.xlabel(r'$m$')
plt.legend()
plt.show()
effs = efficiency(xs, ms)
effs_s, effs_b = effs[:n], effs[n:]
plt.hist([effs_s, effs_b], bins=40, histtype='barstacked', label=['Signal', 'Background'])
plt.xlabel(r'$\varepsilon$')
plt.legend()
plt.show()
exs, ems = generate_sample_with_efficiency(efficiency)
exs_s, exs_b = exs[:n], exs[n:]
ems_s, ems_b = ems[:n], ems[n:]
plt.hist([exs_s, exs_b], bins=40, histtype='barstacked', label=['Signal', 'Background'])
plt.xlabel(r'$x$')
plt.legend()
plt.show()
plt.hist([ems_s, ems_b], bins=40, histtype='barstacked', label=['Signal', 'Background'])
plt.xlabel(r'$m$')
plt.legend()
plt.show()
Zunächst fitten wir die kombinierte Massenverteilung von Signal und Untergrund an unsere beiden Datensätze. Dabei müssen wir daran denken, die Anzahl Signal- und Untergrundereignissen als Fitparamter zu behandeln. Betrachten wir zuerst den Fall $\varepsilon = 1$.
In [3]:
hist, medges, xedges = np.histogram2d(ms, xs, bins=(100, 140), range=((0, 1), (0, 1)))
mwidth = medges[1] - medges[0]
mcentres = medges[:-1] + mwidth / 2
xwidth = xedges[1] - xedges[0]
xcentres = xedges[:-1] + xwidth / 2
mhist = np.sum(hist, axis=1)
xhist = np.sum(hist, axis=0)
plt.plot(mcentres, mhist, '.', label='$m$')
plt.plot(xcentres, xhist, '.', label='$x$')
plt.ylabel('Absolute Häufigkeit')
plt.legend()
plt.show()
In [4]:
def pdf_ms(m, p0, p1, p2):
return p0 * np.exp(-(m - p1) ** 2 / 2 / p2 ** 2)
def pdf_mb(m, p3, p4, p5, p6):
return p3 + p4 * m + p5 * m ** 2 + p6 * np.sqrt(m)
def pdf_m(m, p0, p1, p2, p3, p4, p5, p6):
return pdf_ms(m, p0, p1, p2) + pdf_mb(m, p3, p4, p5, p6)
def fit_mass(centres, ns, pars=None):
if pars is None:
pars = [20000, 0.5, 0.5, 100000, 0.1, 0, 1]
return curve_fit(pdf_m, centres, ns, p0=pars)
popt, _ = fit_mass(mcentres, mhist)
plt.plot(mcentres, mhist, '.')
plt.plot(mcentres, pdf_m(mcentres, *popt))
plt.plot(mcentres, pdf_ms(mcentres, *popt[:3]), '--')
plt.plot(mcentres, pdf_mb(mcentres, *popt[3:]), '--')
plt.xlabel('$m$')
plt.show()
Als nächstes können wir mit Hilfe der bestimmten Parameter die sWeights bestimmen.
In [5]:
def sweights(centres, mhist, popt):
s = pdf_ms(centres, *popt[:3])
b = pdf_mb(centres, *popt[3:])
n = mhist
# Normierung der PDFs
s = s / np.sum(s)
b = b / np.sum(b)
Wss = np.sum((s * s) / n)
Wsb = np.sum((s * b) / n)
Wbb = np.sum((b * b) / n)
alpha = Wbb / (Wss * Wbb - Wsb ** 2)
beta = -Wsb / (Wss * Wbb - Wsb ** 2)
weights = (alpha * s + beta * b) / n
return weights
sw = sweights(mcentres, mhist, popt)
plt.plot(mcentres, sw, '.')
plt.xlabel('$m$')
plt.ylabel('sWeight')
plt.show()
Diese können wir nun verwenden, um die Signalkomponente $s(x)$ herauszuprojizieren.
In [6]:
def apply_sweights(sweights, hist):
return np.array([w * row for w, row in zip(sweights, hist)]).sum(axis=0)
xweighted = apply_sweights(sw, hist)
plt.plot(xcentres, xweighted, '.', label='sWeighted')
plt.plot(xcentres, xhist, '.', label='s+b')
plt.xlabel('$x$')
plt.ylabel('Häufigkeit')
plt.yscale('log')
plt.legend(loc='lower left')
plt.show()
Für $\varepsilon = (x + m) / 2$ verwenden wir an dieser Stelle fälschlicherweise genau das gleiche Vorgehen.
In [7]:
ehist, emedges, exedges = np.histogram2d(ems, exs, bins=(100, 140), range=((0, 1), (0, 1)))
exwidth = exedges[1] - exedges[0]
emwidth = emedges[1] - emedges[0]
excentres = exedges[:-1] + exwidth / 2
emcentres = emedges[:-1] + emwidth / 2
emhist = np.sum(ehist, axis=1)
exhist = np.sum(ehist, axis=0)
plt.plot(emcentres, emhist, '.', label='$m$')
plt.plot(excentres, exhist, '.', label='$x$')
plt.ylabel('Häufigkeit')
plt.legend()
plt.show()
epopt, _ = fit_mass(emcentres, emhist, pars=[20000, 0.5, 0.5, 1, 1, -0.1, 100])
plt.plot(emcentres, emhist, '.')
plt.plot(emcentres, pdf_m(emcentres, *epopt))
plt.plot(emcentres, pdf_ms(emcentres, *epopt[:3]), '--')
plt.plot(emcentres, pdf_mb(emcentres, *epopt[3:]), '--')
plt.xlabel('$m$')
plt.show()
esw = sweights(emcentres, emhist, epopt)
plt.plot(emcentres, esw, '.')
plt.xlabel('$m$')
plt.ylabel('sWeight')
plt.show()
exweighted = apply_sweights(esw, ehist)
plt.plot(excentres, exweighted, '.', label='sWeighted')
plt.plot(excentres, exhist, '.', label='s+b')
plt.plot(xcentres, xweighted, '.', label='sWeighted correct')
plt.xlabel('$x$')
plt.ylabel('Häufigkeit')
plt.yscale('log')
plt.legend(loc='lower left')
plt.show()
Bestimmen Sie für $\varepsilon(x, m) = (x + m)/2$ unter Berücksichtigung der Funktion $\varepsilon(x, m)$ in der Bestimmung von $w(m)$ die korrekten sWeights aus den mit $1/\varepsilon(x, m)$ gewichteten Daten. Verwenden Sie die korrekten sWeights um mit $w(m)/\varepsilon(x, m)$ um die Verteilung $N_{s}s(x)$ zu extrahieren.
In [8]:
eeffs = efficiency(exs, ems)
ehist, emedges, exedges = np.histogram2d(
ems,
exs,
bins=(100, 140),
range=((0, 1), (0, 1)),
weights=1 / eeffs
)
emwidth = emedges[1] - emedges[0]
emcentres = emedges[:-1] + emwidth / 2
exwidth = exedges[1] - exedges[0]
excentres = exedges[:-1] + exwidth / 2
emhist = np.sum(ehist, axis=1)
exhist = np.sum(ehist, axis=0)
plt.plot(emcentres, emhist, 'o', label='$m$')
plt.plot(excentres, exhist, 's', label='$x$')
plt.ylabel('Gewichtete Häufigkeit')
plt.legend()
plt.show()
epopt, _ = fit_mass(emcentres, emhist,
pars=[2000, 0.5, 0.5, 1, 1, -0.1, 10])
plt.plot(emcentres, emhist, '.')
plt.plot(emcentres, pdf_m(emcentres, *epopt))
plt.plot(emcentres, pdf_ms(emcentres, *epopt[:3]), '--')
plt.plot(emcentres, pdf_mb(emcentres, *epopt[3:]), '--')
plt.xlabel('$m$')
plt.show()
eeffhist = efficiency(*np.meshgrid(excentres, emcentres))
def sweights_q(centres, qs, popt):
s = pdf_ms(centres, *popt[:3])
s = s / np.sum(s)
b = pdf_mb(centres, *popt[3:])
b = b / np.sum(b)
Wss = np.sum((s * s) / qs)
Wsb = np.sum((s * b) / qs)
Wbb = np.sum((b * b) / qs)
alpha = Wbb / (Wss * Wbb - Wsb ** 2)
beta = -Wsb / (Wss * Wbb - Wsb ** 2)
weights = (alpha * s + beta * b) / qs
return weights
qs = np.sum(ehist / eeffhist, axis=1)
esw = sweights_q(emcentres, qs, epopt)
plt.plot(emcentres, esw, '.')
plt.xlabel('$m$')
plt.ylabel('sWeight')
plt.show()
exweighted = np.array([s * h for s, h in zip(sw, ehist)]).sum(axis=0)
plt.plot(excentres, exweighted, '.', label='sWeighted')
plt.plot(excentres, exhist, '.', label='s+b')
plt.plot(xcentres, xweighted, '.', label='sWeighted correct')
plt.xlabel('$x$')
plt.ylabel('Häufigkeit')
plt.yscale('log')
plt.legend(loc='lower left')
plt.show()