\n",
"\n",
"Answer:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ce97b6c-2171-4f72-868d-469f6f864410",
"metadata": {},
"outputs": [],
"source": [
"def bkg_reconstructed():\n",
" df = pd.read_csv(\"hist_p_SMbkg.csv\")\n",
" \n",
" plt.hist(df['momentum'], weights=df['entries'],bins=300, density=True)\n",
" plt.ylabel('Entries [a.u.]')\n",
" plt.xlabel('p(e) [MeV]')\n",
" plt.title('SM background')\n",
" # plt.show()\n",
" \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1d345ef6-3fb1-4884-9b92-f5d424f34aa4",
"metadata": {},
"outputs": [],
"source": [
"# plotting\n",
"bkg_rec = bkg_reconstructed()\n",
"plt.plot(p, np.array(list(map(bkg_theory, p))))"
]
},
{
"cell_type": "markdown",
"id": "143abedb-0dc7-48b9-a141-50e03b79e1fd",
"metadata": {
"tags": []
},
"source": [
"
\n",
"\n",
"**Exercise 2** \n",
"We will now set up the signal template ($f_s\\mathrm{d}p$). We will use a Gaussian distribution centered around the expected positron momentum for a given mass $m_X$ of the new particle. The relationship between $m_X$ and the positron momentum $p_e$ has been calculated in question 1. The relative momentum resolution $\\frac{\\Delta p}{p}$ can be derived from Figure 2 (right). $\\Delta p$ is taken as the width of the Gaussian distribution. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e6fb87f0-0e46-40fe-a53d-8c02a58ae02f",
"metadata": {},
"outputs": [],
"source": [
"def sig_template(p, m_X=60.):\n",
" # Calculate the electron momentum for a given familon mass (as in question 1)\n",
" pe = ## YOUR CODE HERE\n",
" \n",
" # Derive the relative momentum resolution from the plot\n",
" dp_over_p = ## YOUR CODE HERE\n",
" sigma = dp_over_p * pe\n",
" \n",
" # Define the gaussian distribution\n",
" fs = 1./(np.sqrt(2.*np.pi)*sigma)*np.exp(-np.power((p - pe)/sigma, 2.)/2)\n",
" \n",
" return fs"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "494656d5-b7d9-4770-b985-98aaac2be754",
"metadata": {},
"outputs": [],
"source": [
"#plotting\n",
"plt.plot(p, np.array(list(map(sig_template, p, np.full(300,40.) ))), color='red', label='mX=40MeV')\n",
"plt.plot(p, np.array(list(map(sig_template, p, np.full(300,55.) ))), color='green', label='mX=55MeV')\n",
"plt.plot(p, np.array(list(map(sig_template, p, np.full(300,70.) ))), color='blue', label='mX=70MeV')\n",
"plt.plot(p, np.array(list(map(sig_template, p, np.full(300,85.) ))), color='magenta', label='mX=85MeV')\n",
"plt.ylabel('Entries [a.u.]')\n",
"plt.xlabel('p(e) [MeV]')\n",
"plt.title('Signal')\n",
"plt.legend()\n",
"plt.show() "
]
},
{
"cell_type": "markdown",
"id": "4da4afab-406a-4895-b374-2b38e56f403b",
"metadata": {},
"source": [
"
\n",
"\n",
"**Exercise 3** \n",
"We will use the background template to generate $N_{gen}$ background-like events and fit a signal-plus-background template to this background-only data to figure out how much \"signal\" can be found in the statistical fluctuations of the background.\n",
" \n",
"Let $f_b \\mathrm{d}p$ and $f_s \\mathrm{d}p$ denote the background and signal pdfs, then the signal-plus-background pdf becomes\n",
" $$ f_{s+b} = (1-f_{sig})f_b + f_{sig}f_s $$\n",
"with the signal contribution $-1\\leq f_{sig}\\leq 1$ as a free floating parameter in the fit.\n",
" \n",
"The code for a single toyMC run is given below. It generates $N_{gen}$ background events using the [accept-and-reject method](https://en.wikipedia.org/wiki/Rejection_sampling) and performs a signal-plus-background fit. Please fill in the gaps.\n",
" \n",
"Tip: For testing the code, lower the $N_{gen}$. For example, generating 1000000 events takes about 30s. We will certainly not try to generate $10^{16}$ muon decays."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b0ce6b63-8d42-49a1-996c-0b2caede4957",
"metadata": {},
"outputs": [],
"source": [
"# Initializing the random number generator. Choose your own seed if you like.\n",
"rnd_gen = np.random.RandomState(seed=65)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8e7ef5d5-0e0b-4739-a9f0-b030b3148ba5",
"metadata": {},
"outputs": [],
"source": [
"## pdfs\n",
"\n",
"# redefine background pdf\n",
"def fb(p):\n",
" fb = 16/(pow(m_mu,3)) * (3-4/m_mu*p)*p*p\n",
" return fb\n",
"\n",
"# signal pdf is signal_template() as defined earlier\n",
"def fs(p, m_X):\n",
" fs = sig_template(p, m_X)\n",
" return fs\n",
"\n",
"# signal+background pdf\n",
"def fsb(p, m_X, N, fsig):\n",
" # fit parameters are normalisation and signal fraction\n",
" fsb = N*( ## YOUR CODE HERE )\n",
" return fsb\n",
" \n",
"def fit_wrapper(m_X = 60.):\n",
" return lambda p, N, fsig: fsb(p, m_X, N, fsig)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c85c6d0b-581d-4c5b-87db-9fa03c94e7ff",
"metadata": {},
"outputs": [],
"source": [
"def singleBkgToyMC(Ngen=100000, m_X=60, plot=False):\n",
" # number of bins for histogram\n",
" n_bins = 53\n",
" \n",
" # Accept and reject method\n",
" i = 0\n",
" toyBkg = np.zeros(Ngen)\n",
" maxGamma = 1.05*bkg_theory(m_mu/2)\n",
" batch_size = Ngen\n",
" while i
\n",
"\n",
"**Exercise 4** \n",
"The procedure above is repeated several times. From the histogram of the resulting $f_{sig}$, an expected limit on the branching ratio $B(\\mu\\to eX)$ can be derived as follows:\n",
"* Histogram the resulting $f_{sig}$ from $N_{rep}$ repetitions.\n",
"* Get the standard deviation $\\sigma$ of the distribution. For the moment, we will assume that the mean is equal to 0. It might need a larger number of repetitions to actually get there. \n",
"* In the muon-LFV community, it is common to quote 90% CL limits. The one-sided 90% confidence interval streches up to $1.282\\sigma$. (For more details, have a look at p.125 of [Cowan, G.: Statistical data analysis](https://primo.bibliothek.kit.edu/primo-explore/fulldisplay?docid=KITSRC455289476&context=L&vid=KIT&lang=de_DE&search_scope=KIT&adaptor=Local%20Search%20Engine&tab=kit&query=any,contains,glen%20cowan&sortby=date&mode=simple)).\n",
"* With this input, the expected upper limit on $BR(\\mu\\to eX)$ at 90% CL can be computed: \n",
" * Branching ratio $B(\\mu\\to eX)=\\frac{N_{\\mu\\to eX}}{N_{\\mu}}$\n",
" * We do not reconstruct every muon decay due to the detector acceptance and reconstruction and selection efficiencies. Assuming this is covered by a constant efficiency factor $\\epsilon$, we can use $N_{\\mu\\to eX}^{rec}=\\epsilon N_{\\mu\\to eX}$. The toyMC study generates background events after reconstruction and selection, thus we have $N_{gen}=\\epsilon N_{\\mu}$ assuming that the fraction of $\\mu\\to eX$ is vanishingly small. The measured branching ratio becomes $B(\\mu\\to eX)=\\frac{N_{\\mu\\to eX}^{rec}}{N_{gen}}$.\n",
" * In the 90% confidence interval, up to $1.282\\sigma$ of signal fraction can be caused by background fluctuations, i.e. $1.282\\sigma N_{gen}$ events. The expected upper limit on $B(\\mu\\to eX)$ in the toyMC study becomes $B(\\mu\\to eX)\\geq 1.282 \\sigma$ at 90% CL.\n",
"\n",
"**Tasks**\n",
"* Fill in the gaps in the code.\n",
"* Perform toyMC studies with different $N_{gen}$ and $m_X$.\n",
"* How does the sensitivity change with the number of generated toyMC background event ($N_{gen}$)? (Keep $N_{rep}$ at a reasonable level.)\n",
"* Do you see a change in sensitivity for different $m_X$? What would you expect?"
]
},
{
"cell_type": "markdown",
"id": "c2904653-0430-475d-a8d1-6f4ca0eb118f",
"metadata": {
"tags": []
},
"source": [
"\n",
"\n",
"Answer:\n",
" \n",
"| mX [MeV] | Nrep | Ngen | UL on BR at 90%CL |\n",
"| ---: | ---: | ---: | :--- |\n",
"| ?? | ?? | ?? | ?? |\n",
"| | | | |\n",
" \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c24d0f9f-737c-4edb-8cc8-a7d47e0b3c9d",
"metadata": {},
"outputs": [],
"source": [
"def toyMCstudy(Nrep=100, Ngen=100000, m_X=60.):\n",
" \n",
" fsig = np.zeros(Nrep)\n",
" \n",
" for i in range(Nrep):\n",
" fsig[i] = singleBkgToyMC(Ngen, m_X)\n",
" \n",
" plt.hist(fsig, label='signal fraction')\n",
" plt.ylabel('Entries')\n",
" plt.xlabel('fsig')\n",
" plt.title('toyMC study')\n",
" # plt.legend()\n",
" plt.show()\n",
" \n",
" # Calculate the 90%CL limit on the BR(mu to eX) from sigma\n",
" sigma = fsig.std()\n",
" BRlimit = ## YOUR CODE HERE\n",
" \n",
" print(f\"toyMC results for mX={m_X}MeV (Nrep={Nrep}, Ngen={Ngen}):\\t standard deviation (fsig) {sigma} \\t BRlimit {BRlimit}\")\n",
" \n",
" return sigma, BRlimit"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1206d47-925d-4230-8519-fa2663f8ae34",
"metadata": {},
"outputs": [],
"source": [
"toyMCstudy( Nrep=??, Ngen=??, m_X=??)"
]
},
{
"cell_type": "markdown",
"id": "41c50e3f-3da1-4cd8-a90d-5fd789cdb610",
"metadata": {},
"source": [
"
\n",
"\n",
"**Question 5** \n",
"How can the sensitivity be improved?"
]
},
{
"cell_type": "markdown",
"id": "34ef2cc5-f777-4e64-9837-61926e5c9328",
"metadata": {
"tags": []
},
"source": [
"
\n",
"\n",
"Answer:\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}