Warning, /geant4/examples/extended/exoticphysics/channeling/ch5/analysis_ch5.ipynb is written in an unsupported language. File is not indexed.
0001 {
0002 "cells": [
0003 {
0004 "cell_type": "markdown",
0005 "id": "b1fed382-d8eb-4a41-a658-eb9e02ae77e6",
0006 "metadata": {},
0007 "source": [
0008 "# Read the output of a Geant4 **ch5** simulation"
0009 ]
0010 },
0011 {
0012 "cell_type": "markdown",
0013 "id": "29ffa6b6-2469-45d8-bce5-94e8b8d184cf",
0014 "metadata": {},
0015 "source": [
0016 "## Import the required libraries"
0017 ]
0018 },
0019 {
0020 "cell_type": "code",
0021 "execution_count": null,
0022 "id": "3764e2c2-8cb7-4b89-9d5c-1e1379a1207d",
0023 "metadata": {
0024 "tags": []
0025 },
0026 "outputs": [],
0027 "source": [
0028 "import numpy as np\n",
0029 "import pandas as pd\n",
0030 "import matplotlib.pyplot as plt\n",
0031 "#%matplotlib ipympl\n",
0032 "from matplotlib.ticker import AutoMinorLocator\n",
0033 "import os\n",
0034 "import uproot\n",
0035 "import math\n",
0036 "import re\n",
0037 "from scipy import interpolate\n",
0038 "\n",
0039 "# Set the number of digits to show in pandas dataframes\n",
0040 "pd.set_option('display.float_format', '{:.2f}'.format)\n",
0041 "\n",
0042 "import warnings\n",
0043 "warnings.simplefilter(\"ignore\", category=DeprecationWarning)\n",
0044 "pd.options.mode.chained_assignment = None"
0045 ]
0046 },
0047 {
0048 "cell_type": "markdown",
0049 "id": "cf2a5937-f6d1-4c85-ba11-9889be23b8cd",
0050 "metadata": {},
0051 "source": [
0052 "## Graphical settings for fancier plots"
0053 ]
0054 },
0055 {
0056 "cell_type": "code",
0057 "execution_count": null,
0058 "id": "9044a604-fb1b-4429-9b54-d399919a29b0",
0059 "metadata": {},
0060 "outputs": [],
0061 "source": [
0062 "import mplhep as hep\n",
0063 "\n",
0064 "style = hep.style.ROOT\n",
0065 "\n",
0066 "# figure size\n",
0067 "style['figure.figsize'] = (10.795, 7.000)\n",
0068 "\n",
0069 "# other sizes\n",
0070 "style['lines.markersize'] = 6\n",
0071 "style['lines.linewidth'] = 3\n",
0072 "\n",
0073 "# fonts\n",
0074 "style['font.family'] = \"serif\"\n",
0075 "style['axes.titlesize'] = \"x-small\"\n",
0076 "style['axes.labelsize'] = \"small\"\n",
0077 "style['xtick.labelsize'] = \"x-small\"\n",
0078 "style['ytick.labelsize'] = \"x-small\"\n",
0079 "style['legend.fontsize'] = \"x-small\"\n",
0080 "style['mathtext.fontset'] = \"dejavuserif\"\n",
0081 "\n",
0082 "# text locations\n",
0083 "style['xaxis.labellocation'] = 'center'\n",
0084 "style['yaxis.labellocation'] = 'center'\n",
0085 "\n",
0086 "# grid\n",
0087 "#style[\"axes.grid\"] = True\n",
0088 "\n",
0089 "# output plots\n",
0090 "out_format = \"pdf\"\n",
0091 "dpi = 800"
0092 ]
0093 },
0094 {
0095 "cell_type": "markdown",
0096 "id": "b12394a6-daae-4b8e-a458-28cae054a7a4",
0097 "metadata": {
0098 "tags": []
0099 },
0100 "source": [
0101 "## Set input path and base filename"
0102 ]
0103 },
0104 {
0105 "cell_type": "code",
0106 "execution_count": null,
0107 "id": "cbebf6ec-61ad-4e71-b856-d4afdb3c18d6",
0108 "metadata": {
0109 "tags": []
0110 },
0111 "outputs": [],
0112 "source": [
0113 "path = \"output/\"\n",
0114 "\n",
0115 "name = \"output_6GeV_W2.0mm_conv8.0mm_D50cm\" #name of the output root file (without extension)\n",
0116 "rad_th = 2.0 #[mm] thickness ot the radiator\n",
0117 "conv_th = 8.0 #[mm] thickness ot the converter"
0118 ]
0119 },
0120 {
0121 "cell_type": "markdown",
0122 "id": "69c5ad7f-f62b-4c95-a1ed-144dda88cec9",
0123 "metadata": {},
0124 "source": [
0125 "## Save and export settings"
0126 ]
0127 },
0128 {
0129 "cell_type": "code",
0130 "execution_count": null,
0131 "id": "9d7a6d4a-e1c4-4a57-a388-5e66a5c6242e",
0132 "metadata": {
0133 "tags": []
0134 },
0135 "outputs": [],
0136 "source": [
0137 "# Figure save option\n",
0138 "saveFigs = True\n",
0139 "\n",
0140 "# Option to convert file for RF-Track\n",
0141 "convertFileToRFTrack = True\n",
0142 "setGaussianTimeShape = True\n",
0143 "addID = False"
0144 ]
0145 },
0146 {
0147 "cell_type": "markdown",
0148 "id": "60605cbf-1850-4d71-a3f1-d3373e464913",
0149 "metadata": {},
0150 "source": [
0151 "## Set output path and desired variables"
0152 ]
0153 },
0154 {
0155 "cell_type": "code",
0156 "execution_count": null,
0157 "id": "57131664-c6b4-42d5-8c79-a12214c51ae6",
0158 "metadata": {
0159 "tags": []
0160 },
0161 "outputs": [],
0162 "source": [
0163 "# Stripped name\n",
0164 "purename = name.replace(\"output_\", \"\")\n",
0165 "\n",
0166 "# Define the output folder\n",
0167 "outpath = path + \"analysis_output/\"\n",
0168 "if not os.path.exists(outpath):\n",
0169 " os.makedirs(outpath)\n",
0170 "\n",
0171 "# Quantity to be stored as results\n",
0172 "case_list = []\n",
0173 "yield_pos_list = []\n",
0174 "yield_ele_list = []\n",
0175 "yield_ph_list = []\n",
0176 "yield_n_list = []\n",
0177 "pos_mean_E_list = []\n",
0178 "pos_spread_E_list = []\n",
0179 "pos_mean_div_fit_list = []\n",
0180 "pos_mean_size_fit_list = []\n",
0181 "Edep_rad_list = []\n",
0182 "Edep_conv_list = []\n",
0183 "PEDD_list = []"
0184 ]
0185 },
0186 {
0187 "cell_type": "markdown",
0188 "id": "8c779b26-1bc9-49c3-a7b9-7d1289460e12",
0189 "metadata": {
0190 "tags": []
0191 },
0192 "source": [
0193 "## Read the root file with the scoring ntuples for virtual detectors"
0194 ]
0195 },
0196 {
0197 "cell_type": "code",
0198 "execution_count": null,
0199 "id": "78e5a25f-0a7c-4af5-ad45-91eca1af2231",
0200 "metadata": {
0201 "tags": []
0202 },
0203 "outputs": [],
0204 "source": [
0205 "print(\"\\nopening rf:\", name ,\".root file ...\")\n",
0206 "\n",
0207 "rf = uproot.open(path + name + \".root\")\n",
0208 "rf_content = [item.split(';')[0] for item in rf.keys()]\n",
0209 "print('rf_content:', rf_content)\n",
0210 "\n",
0211 "#screenID: 2=after the Radiator (if used), 0=before the Converter, 1=after the Converter (or the single-crystal)\n",
0212 "#particle: Geant4 particle name\n",
0213 "#x,y are in [mm]\n",
0214 "#px,py,pz are in [MeV/c]\n",
0215 "#t is in [ns]\n",
0216 "#branches = [\"screenID\", \"particle\", \"x\", \"y\", \"px\", \"py\", \"pz\", \"t\", \"eventID\"]\n",
0217 "df = rf['scoring_ntuple'].arrays(library='pd')\n",
0218 "\n",
0219 "if 'eventID' in df:\n",
0220 " Nevents = len(np.array(df.eventID.unique()))\n",
0221 "else:\n",
0222 " Nevents = 1e4\n",
0223 "print(\"Nevents:\", Nevents) #number of simulated events (primary particles)\n",
0224 "\n",
0225 "df_rad_out = df[(df.screenID == 2)].copy().drop([\"screenID\"], axis=1)\n",
0226 "df_conv_in = df[(df.screenID == 0)].copy().drop([\"screenID\"], axis=1)\n",
0227 "df_conv_out = df[(df.screenID == 1)].copy().drop([\"screenID\"], axis=1)\n",
0228 "#df_wrong = df[(df.screenID == -1)].copy().drop([\"screenID\"], axis=1)\n",
0229 "del df"
0230 ]
0231 },
0232 {
0233 "cell_type": "markdown",
0234 "id": "9094f5fd-8bd2-4501-9757-561bfbe73130",
0235 "metadata": {},
0236 "source": [
0237 "### Dataframes with phase-spaces (of $\\gamma$/e-/e+/n) after the Radiator crystal\n",
0238 "note: if D = 0 -> this is empty!"
0239 ]
0240 },
0241 {
0242 "cell_type": "code",
0243 "execution_count": null,
0244 "id": "1043904e-ff55-4920-8349-099e6cff9a5c",
0245 "metadata": {
0246 "tags": []
0247 },
0248 "outputs": [],
0249 "source": [
0250 "print(np.array(df_rad_out.particle.unique()))\n",
0251 "print(df_rad_out.shape[0], '\\n')\n",
0252 "\n",
0253 "if df_rad_out.shape[0] > 0 :\n",
0254 " df_rad_out_n = df_rad_out[(df_rad_out.particle == \"neutron\")].copy()\n",
0255 " df_rad_out_ph = df_rad_out[(df_rad_out.particle == \"gamma\")].copy()\n",
0256 " df_rad_out_ele = df_rad_out[(df_rad_out.particle == \"e-\")].copy()\n",
0257 " df_rad_out_pos = df_rad_out[(df_rad_out.particle == \"e+\")].copy()\n",
0258 " \n",
0259 " print('neutrons:', df_rad_out_n.shape[0])\n",
0260 " print('photons:', df_rad_out_ph.shape[0])\n",
0261 " print('e-:', df_rad_out_ele.shape[0], ', e+:', df_rad_out_pos.shape[0], \\\n",
0262 " '-> e-e+-:', df_rad_out_ele.shape[0] + df_rad_out_pos.shape[0], '\\n')\n",
0263 "\n",
0264 " df_rad_out.head(5)"
0265 ]
0266 },
0267 {
0268 "cell_type": "markdown",
0269 "id": "f6a9b843-8841-4a80-b947-f458c97e989f",
0270 "metadata": {},
0271 "source": [
0272 "### Dataframes with phase-spaces (of $\\gamma$/e-/e+/n) before the Converter crystal"
0273 ]
0274 },
0275 {
0276 "cell_type": "code",
0277 "execution_count": null,
0278 "id": "d69706c0-e4d8-496d-850c-bd9e6de72cfc",
0279 "metadata": {
0280 "tags": []
0281 },
0282 "outputs": [],
0283 "source": [
0284 "print(np.array(df_conv_in.particle.unique()))\n",
0285 "print(df_conv_in.shape[0], '\\n')\n",
0286 "\n",
0287 "if df_conv_in.shape[0] > 0 :\n",
0288 " df_conv_in_n = df_conv_in[(df_conv_in.particle == \"neutron\")].copy()\n",
0289 " df_conv_in_ph = df_conv_in[(df_conv_in.particle == \"gamma\")].copy()\n",
0290 " df_conv_in_ele = df_conv_in[(df_conv_in.particle == \"e-\")].copy()\n",
0291 " df_conv_in_pos = df_conv_in[(df_conv_in.particle == \"e+\")].copy()\n",
0292 "\n",
0293 " print('neutrons:', df_conv_in_n.shape[0])\n",
0294 " print('photons:', df_conv_in_ph.shape[0])\n",
0295 " print('e-:', df_conv_in_ele.shape[0], ', e+:', df_conv_in_pos.shape[0], \\\n",
0296 " '-> e-/e+-:', df_conv_in_ele.shape[0] + df_conv_in_pos.shape[0], '\\n')\n",
0297 "\n",
0298 " df_conv_in.head(5)"
0299 ]
0300 },
0301 {
0302 "cell_type": "markdown",
0303 "id": "9dcc1d28-10fa-4f7d-9fa1-914ba08d96d4",
0304 "metadata": {},
0305 "source": [
0306 "### Dataframes with phase-spaces (of $\\gamma$/e-/e+/n) after the Converter crystal\n",
0307 "note: if the source is not hybrid -> this is empty!"
0308 ]
0309 },
0310 {
0311 "cell_type": "code",
0312 "execution_count": null,
0313 "id": "f5d9ce34-6ccf-4c4f-83e4-c2ef5cb4795d",
0314 "metadata": {
0315 "tags": []
0316 },
0317 "outputs": [],
0318 "source": [
0319 "print(np.array(df_conv_out.particle.unique()))\n",
0320 "print(df_conv_out.shape[0], '\\n')\n",
0321 "\n",
0322 "if df_conv_out.shape[0] > 0 :\n",
0323 " df_conv_out_n = df_conv_out[(df_conv_out.particle == \"neutron\")].copy()\n",
0324 " df_conv_out_ph = df_conv_out[(df_conv_out.particle == \"gamma\")].copy()\n",
0325 " df_conv_out_ele = df_conv_out[(df_conv_out.particle == \"e-\")].copy()\n",
0326 " df_conv_out_pos = df_conv_out[(df_conv_out.particle == \"e+\")].copy()\n",
0327 "\n",
0328 " print('neutrons:', df_conv_out_n.shape[0])\n",
0329 " print('photons:', df_conv_out_ph.shape[0])\n",
0330 " print('e-:', df_conv_out_ele.shape[0], ', e+:', df_conv_out_pos.shape[0], \\\n",
0331 " '-> e-e+-:', df_conv_out_ele.shape[0] + df_conv_out_pos.shape[0], '\\n')\n",
0332 "\n",
0333 " df_conv_out.head(5)"
0334 ]
0335 },
0336 {
0337 "cell_type": "markdown",
0338 "id": "d40fb008-776e-48d4-bcba-39b36ae7af58",
0339 "metadata": {},
0340 "source": [
0341 "## Plot the positron distribution at the Converter/Target exit [and correlate it with the photon distribution at the exit of the radiator crystal]"
0342 ]
0343 },
0344 {
0345 "cell_type": "markdown",
0346 "id": "3190fcce-76b8-48e5-92d1-93db9eec9fd1",
0347 "metadata": {},
0348 "source": [
0349 "### Import the required libraries"
0350 ]
0351 },
0352 {
0353 "cell_type": "code",
0354 "execution_count": null,
0355 "id": "7f1578f2-2913-4dc4-8c1a-7556fd84faeb",
0356 "metadata": {
0357 "tags": []
0358 },
0359 "outputs": [],
0360 "source": [
0361 "from scipy.optimize import curve_fit\n",
0362 "from matplotlib.colors import LogNorm\n",
0363 "\n",
0364 "def gaussian(x, a, b, c):\n",
0365 " import numpy as np\n",
0366 " return a*np.exp(-np.power(x - b, 2)/(2*np.power(c, 2)))\n",
0367 "\n",
0368 "### Set plot style ###\n",
0369 "style['figure.figsize'] = (style['figure.figsize'][0], 8.50) #manual tweak to figure height\n",
0370 "plt.style.use(style)"
0371 ]
0372 },
0373 {
0374 "cell_type": "markdown",
0375 "id": "ac6e8cb8-9888-4721-8639-71496b8c9208",
0376 "metadata": {},
0377 "source": [
0378 "### Options for this calculation"
0379 ]
0380 },
0381 {
0382 "cell_type": "code",
0383 "execution_count": null,
0384 "id": "6ad51514-f780-44f4-b72b-7f7f18fa1278",
0385 "metadata": {
0386 "tags": []
0387 },
0388 "outputs": [],
0389 "source": [
0390 "if 'conventional' in name:\n",
0391 " inputType = \"e-\" \n",
0392 "else:\n",
0393 " inputType = \"all\" #set a value different from \"all\" only if it is a conventional source\n",
0394 "\n",
0395 "bCutOnMomentum = False\n",
0396 "MomentumCut = 5 #MeV"
0397 ]
0398 },
0399 {
0400 "cell_type": "markdown",
0401 "id": "7ae3c2b7-cbfb-4183-953c-ecff0d9d8db0",
0402 "metadata": {},
0403 "source": [
0404 "### Define data_in and data_out dataframes and add more parameters to them"
0405 ]
0406 },
0407 {
0408 "cell_type": "code",
0409 "execution_count": null,
0410 "id": "f1b026f9-ad0c-4d2e-a0e5-df82c318f5bf",
0411 "metadata": {
0412 "tags": []
0413 },
0414 "outputs": [],
0415 "source": [
0416 "if df_rad_out.shape[0] > 0:\n",
0417 " data_in = df_rad_out.copy()\n",
0418 "else:\n",
0419 " if df_conv_out.shape[0] > 0:\n",
0420 " data_in = df_conv_in.copy()\n",
0421 " else:\n",
0422 " data_in = df_rad_out.copy() #set an empty dataframe, because this is a single-volume (crystal or conventional) source\n",
0423 " \n",
0424 "data_in[\"P\"] = (data_in.px*data_in.px + data_in.py*data_in.py + data_in.pz*data_in.pz)**0.5 #MeV \n",
0425 "data_in = data_in[data_in.pz >= 0] #selecting only events (that should be) from the input beam\n",
0426 "if bCutOnMomentum:\n",
0427 " data_in = data_in[data_in.P >= MomentumCut] #selecting only events with momentum > MomentumCut\n",
0428 "data_in.pz = data_in.pz/1000 #MeV -> GeV\n",
0429 "data_in.x = data_in.x/10 #mm -> cm\n",
0430 "data_in.y = data_in.y/10 #mm -> cm\n",
0431 "data_in[\"pt\"] = (data_in.px**2 + data_in.py**2)**0.5 #MeV\n",
0432 "data_in[\"thx\"] = np.arctan(data_in.px/1000 / data_in.pz)*1000 #mrad\n",
0433 "data_in[\"thy\"] = np.arctan(data_in.py/1000 / data_in.pz)*1000 #mrad\n",
0434 "data_in[\"tht\"] = np.arctan(data_in.pt/1000 / data_in.pz)*1000 #mrad\n",
0435 "\n",
0436 "if df_conv_out.shape[0] > 0:\n",
0437 " data_out = df_conv_out.copy() \n",
0438 "else: #this is the case of a single-volume (crystalline or conventional) source\n",
0439 " data_out = df_conv_in.copy() \n",
0440 "\n",
0441 "data_out[\"P\"] = (data_out.px*data_out.px+data_out.py*data_out.py+data_out.pz*data_out.pz)**0.5 #MeV\n",
0442 "if bCutOnMomentum:\n",
0443 " data_out = data_out[data_out.P >= MomentumCut] #selecting only events with momentum > MomentumCut\n",
0444 "data_out.pz = data_out.pz/1000 #MeV -> GeV\n",
0445 "data_out.x = data_out.x/10 #mm -> cm\n",
0446 "data_out.y = data_out.y/10 #mm -> cm\n",
0447 "data_out[\"pt\"] = (data_out.px**2 + data_out.py**2)**0.5 #MeV\n",
0448 "data_out[\"thx\"] = np.arctan(data_out.px/1000 / data_out.pz)*1000 #mrad\n",
0449 "data_out[\"thy\"] = np.arctan(data_out.py/1000 / data_out.pz)*1000 #mrad\n",
0450 "data_out[\"tht\"] = np.arctan(data_out.pt/1000 / data_out.pz)*1000 #mrad"
0451 ]
0452 },
0453 {
0454 "cell_type": "markdown",
0455 "id": "89f362e5-7855-4bdf-8edd-eea48d2c582b",
0456 "metadata": {},
0457 "source": [
0458 "### Plot the angular distribution"
0459 ]
0460 },
0461 {
0462 "cell_type": "code",
0463 "execution_count": null,
0464 "id": "af9627fe-7a0b-431b-a7a3-0fdb2bc67f08",
0465 "metadata": {
0466 "tags": []
0467 },
0468 "outputs": [],
0469 "source": [
0470 "# plot options\n",
0471 "fitrange_ang = 17.45 #mrad (for angular distribution) \n",
0472 "ang_plot_lim = (-50, 150) #mrad\n",
0473 "fitrange = 0.2 #cm (for spatial distribution)\n",
0474 "nBins = 200 #(for spatial distribution)\n",
0475 "xRange = (-0.45, 0.45) #cm\n",
0476 "xRange1 = (-10.5, 10.5) #cm\n",
0477 "yUpperLim = 14 #(for profiles)"
0478 ]
0479 },
0480 {
0481 "cell_type": "code",
0482 "execution_count": null,
0483 "id": "52dc1aa8-62b6-472d-bf28-dff2063a00df",
0484 "metadata": {
0485 "tags": []
0486 },
0487 "outputs": [],
0488 "source": [
0489 "fig, ax = plt.subplots(nrows=2, sharex=True)\n",
0490 "\n",
0491 "divergenceIn = [0, 0]\n",
0492 "angleStdIn = [0, 0]\n",
0493 "divergence = [0, 0]\n",
0494 "angleStd = [0, 0]\n",
0495 "\n",
0496 "if len(data_in) > 0:\n",
0497 " series = [data_in[(data_in.particle==\"gamma\" if inputType==\"all\" else data_in.particle==\"e-\")].thx, \n",
0498 " data_in[(data_in.particle==\"gamma\" if inputType==\"all\" else data_in.particle==\"e-\")].thy]\n",
0499 " for i in (0, 1):\n",
0500 " hist = ax[i].hist(series[i], bins=15000, range=(-200, 200), histtype=\"step\", color=\"C0\")\n",
0501 " x, y = hist[1][:-1]+0.5*abs(hist[1][1]-hist[1][0]), hist[0]\n",
0502 " x, y = x[(x>-fitrange_ang) & (x<fitrange_ang)], y[(x>-fitrange_ang) & (x<fitrange_ang)]\n",
0503 " try:\n",
0504 " par, _ = curve_fit(f=gaussian, xdata=x, ydata=y, bounds=(-np.inf, np.inf))\n",
0505 " except:\n",
0506 " par = (1, 0, np.inf)\n",
0507 " xplot = np.linspace(-fitrange_ang, fitrange_ang, 200)\n",
0508 " xplot2 = np.linspace(-200, -fitrange_ang, 2000)\n",
0509 " xplot3 = np.linspace(fitrange_ang, 200, 2000)\n",
0510 " label = (\"at crystal output\"+r\" ($\\it{\\gamma}$ only)\" if inputType==\"all\" else \\\n",
0511 " \"at amorphous target input\"+r\" ($\\it{e}^-$ only)\")+\", Gaussian\\n\"+r\"fit (in $\\pm$ %.2f mrad)\" % \\\n",
0512 " fitrange_ang+r\" $\\it{\\sigma}$ = %.2f mrad\" % abs(par[2])\n",
0513 " if abs(par[2]) < np.inf:\n",
0514 " ax[i].plot(xplot, gaussian(xplot, *par), c=\"C0\", alpha=0.5, label=label)\n",
0515 " ax[i].plot(xplot2, gaussian(xplot2, *par), c=\"C0\", ls=\":\", alpha=0.5)\n",
0516 " ax[i].plot(xplot3, gaussian(xplot3, *par), c=\"C0\", ls=\":\", alpha=0.5)\n",
0517 " \n",
0518 " divergenceIn[i] = abs(par[2])\n",
0519 " angleStdIn[i] = series[i].std()\n",
0520 "\n",
0521 " ax[i].set_yscale(\"linear\")\n",
0522 " ax[i].set_xlim(ang_plot_lim)\n",
0523 " ax[i].set_title(\" \"+(\"horizontal\" if i==0 else \"vertical\"), loc=\"left\")\n",
0524 " ax[i].legend(loc=\"upper right\", fontsize=\"xx-small\")\n",
0525 " ax[i].grid(True)\n",
0526 "\n",
0527 "series = [data_out[(data_out.particle==\"e+\")].thx, data_out[(data_out.particle==\"e+\")].thy]\n",
0528 "for i in (0, 1):\n",
0529 " hist = ax[i].hist(series[i], bins=800, range=(-1000, 1000), histtype=\"step\", color=\"C1\")\n",
0530 " x, y = hist[1][:-1]+0.5*abs(hist[1][1]-hist[1][0]), hist[0]\n",
0531 " x, y = x[(x>-fitrange_ang) & (x<fitrange_ang)], y[(x>-fitrange_ang) & (x<fitrange_ang)]\n",
0532 " try:\n",
0533 " par, _ = curve_fit(f=gaussian, xdata=x, ydata=y, bounds=(-np.inf, np.inf))\n",
0534 " except:\n",
0535 " par = (1, 0, np.inf)\n",
0536 " xplot = np.linspace(-fitrange_ang, fitrange_ang, 200)\n",
0537 " xplot2 = np.linspace(-200, -fitrange_ang, 2000)\n",
0538 " xplot3 = np.linspace(fitrange_ang, 200, 2000)\n",
0539 " label = \"at amorphous target output\"+r\" ($\\it{e}^+$ only)\"+\", Gaussian\\n\"+r\"fit (in $\\pm$ %.2f mrad)\" % \\\n",
0540 " fitrange_ang+r\" $\\it{\\sigma}$ = %.2f mrad\" % abs(par[2])\n",
0541 " if abs(par[2]) < np.inf:\n",
0542 " ax[i].plot(xplot, gaussian(xplot, *par), c=\"C1\", alpha=0.5, label=label)\n",
0543 " ax[i].plot(xplot2, gaussian(xplot2, *par), c=\"C1\", ls=\":\", alpha=0.5)\n",
0544 " ax[i].plot(xplot3, gaussian(xplot3, *par), c=\"C1\", ls=\":\", alpha=0.5)\n",
0545 " divergence[i] = abs(par[2])\n",
0546 " angleStd[i] = series[i].std()\n",
0547 "\n",
0548 " ax[i].set_yscale(\"linear\")\n",
0549 " ax[i].set_xlim(ang_plot_lim)\n",
0550 " ax[i].set_title(\" \"+(\"horizontal\" if i==0 else \"vertical\"), loc=\"left\")\n",
0551 " ax[i].legend(loc=\"upper right\", fontsize=\"xx-small\")\n",
0552 " ax[i].grid(True)\n",
0553 "\n",
0554 "fig.supylabel(\"Counts\", fontsize=\"small\")\n",
0555 "ax[1].set_xlabel(r\"$\\it{\\theta}$ [mrad]\")\n",
0556 "fig.tight_layout()\n",
0557 "\n",
0558 "if saveFigs:\n",
0559 " plt.savefig(outpath + 'eBeam_theta_distrib_' + purename + '.jpg')\n",
0560 "\n",
0561 "print(\"e+ beam divergence along X and Y from Gauss fit in (-%.2f, %.2f) mrad range: [-%.2f, %.2f] mrad\" \\\n",
0562 " % (fitrange_ang, fitrange_ang, divergence[0], divergence[1]))"
0563 ]
0564 },
0565 {
0566 "cell_type": "markdown",
0567 "id": "eeeef894-b2ab-4f60-90af-68faa33e6562",
0568 "metadata": {},
0569 "source": [
0570 "### Plot the spatial distribution"
0571 ]
0572 },
0573 {
0574 "cell_type": "code",
0575 "execution_count": null,
0576 "id": "df9d997c-d378-40f2-83e8-558c5cf504b7",
0577 "metadata": {
0578 "tags": []
0579 },
0580 "outputs": [],
0581 "source": [
0582 "fig, ax = plt.subplots(ncols=2, nrows=3, figsize=(style['figure.figsize'][0], 14.0))\n",
0583 "fig.subplots_adjust(wspace=-1)\n",
0584 "\n",
0585 "beamSizeX, beamSizeY = [0, 0, 0], [0, 0, 0]\n",
0586 "\n",
0587 "ax[0,0].set_title(r\"$\\it{e}^{+}$ only\")\n",
0588 "ax[0,1].set_title(r\"$\\it{e}^{+}$ only\")\n",
0589 "\n",
0590 "ax[0,1].hist2d(data_out[(data_out.particle==\"e+\")].x, data_out[(data_out.particle==\"e+\")].y, \\\n",
0591 " bins=nBins, range=(xRange, xRange), norm=LogNorm())\n",
0592 "ax[0,1].grid(True)\n",
0593 "ax[0,0].hist2d(data_out[(data_out.particle==\"e+\")].x, data_out[(data_out.particle==\"e+\")].y, \\\n",
0594 " bins=nBins, range=(xRange1, xRange1), norm=LogNorm())\n",
0595 "ax[0,0].grid(True)\n",
0596 "\n",
0597 "gs = ax[1,0].get_gridspec()\n",
0598 "for ax0 in ax[1,:]:\n",
0599 " ax0.remove()\n",
0600 "axdown = fig.add_subplot(gs[1,:])\n",
0601 "\n",
0602 "if len(data_in) > 0:\n",
0603 " hist = axdown.hist(data_in[(data_in.particle==\"gamma\" if inputType==\"all\" else data_in.particle==\"e-\")].x, \\\n",
0604 " bins=nBins, histtype=\"step\", range=xRange, density=True, color=\"C0\") ;\n",
0605 " x, y = hist[1][:-1]+0.5*abs(hist[1][1]-hist[1][0]), hist[0]\n",
0606 " x, y = x[(x>-fitrange) & (x<fitrange)], y[(x>-fitrange) & (x<fitrange)]\n",
0607 " try:\n",
0608 " par, _ = curve_fit(f=gaussian, xdata=x, ydata=y, bounds=(-np.inf, np.inf))\n",
0609 " except:\n",
0610 " par = (1, 0, np.inf)\n",
0611 " xplot = np.linspace(-fitrange, fitrange, 200)\n",
0612 " xplot2 = np.linspace(xRange[0], -fitrange, 2000)\n",
0613 " xplot3 = np.linspace(fitrange, xRange[1], 2000)\n",
0614 " label = (\"at crystal output\"+r\" ($\\it{\\gamma}$ only)\" if inputType==\"all\" else \\\n",
0615 " \"at amorphous target input\"+r\" ($\\it{e}^-$ only)\")+\",\\nGaussian fit \"+r\"$\\it{\\sigma}$ = %.3f mm\" % abs(par[2]*10)\n",
0616 " if abs(par[2]) < np.inf:\n",
0617 " axdown.plot(xplot, gaussian(xplot, *par), c=\"C0\", alpha=0.5, label=label)\n",
0618 " axdown.plot(xplot2, gaussian(xplot2, *par), c=\"C0\", ls=\":\", alpha=0.5)\n",
0619 " axdown.plot(xplot3, gaussian(xplot3, *par), c=\"C0\", ls=\":\", alpha=0.5)\n",
0620 " beamSizeX[0] = par[2]\n",
0621 "\n",
0622 "hist = axdown.hist(data_out[(data_out.particle==\"e+\")].x, bins=nBins, histtype=\"step\", range=xRange, density=True, color=\"C1\")\n",
0623 "x, y = hist[1][:-1]+0.5*abs(hist[1][1]-hist[1][0]), hist[0]\n",
0624 "x, y = x[(x>-fitrange) & (x<fitrange)], y[(x>-fitrange) & (x<fitrange)]\n",
0625 "try:\n",
0626 " par, _ = curve_fit(f=gaussian, xdata=x, ydata=y, bounds=(-np.inf, np.inf))\n",
0627 "except:\n",
0628 " par = (1, 0, np.inf)\n",
0629 "xplot = np.linspace(-fitrange, fitrange, 200)\n",
0630 "xplot2 = np.linspace(xRange[0], -fitrange, 2000)\n",
0631 "xplot3 = np.linspace(fitrange, xRange[1], 2000)\n",
0632 "label = \"at amorphous target output\"+r\" ($\\it{e}^{+}$ only)\"+\",\\nGaussian fit \"+r\"$\\it{\\sigma}$ = %.3f mm\" % abs(par[2]*10)\n",
0633 "if abs(par[2]) < np.inf:\n",
0634 " axdown.plot(xplot, gaussian(xplot, *par), c=\"C1\", alpha=0.5, label=label)\n",
0635 " axdown.plot(xplot2, gaussian(xplot2, *par), c=\"C1\", ls=\":\", alpha=0.5)\n",
0636 " axdown.plot(xplot3, gaussian(xplot3, *par), c=\"C1\", ls=\":\", alpha=0.5)\n",
0637 "beamSizeX[1] = par[2]\n",
0638 "\n",
0639 "gs = ax[2,0].get_gridspec()\n",
0640 "for ax0 in ax[2,:]:\n",
0641 " ax0.remove()\n",
0642 "axdown2 = fig.add_subplot(gs[2,:])\n",
0643 "\n",
0644 "if len(data_in) > 0:\n",
0645 " hist = axdown2.hist(data_in[(data_in.particle==\"gamma\" if inputType==\"all\" else data_in.particle==\"e-\")].y, \\\n",
0646 " bins=nBins, histtype=\"step\", range=xRange, density=True, color=\"C0\") ;\n",
0647 " x, y = hist[1][:-1]+0.5*abs(hist[1][1]-hist[1][0]), hist[0]\n",
0648 " x, y = x[(x>-fitrange) & (x<fitrange)], y[(x>-fitrange) & (x<fitrange)]\n",
0649 " try:\n",
0650 " par, _ = curve_fit(f=gaussian, xdata=x, ydata=y, bounds=(-np.inf, np.inf))\n",
0651 " except:\n",
0652 " par = (1, 0, np.inf)\n",
0653 " xplot = np.linspace(-fitrange, fitrange, 200)\n",
0654 " xplot2 = np.linspace(xRange[0], -fitrange, 2000)\n",
0655 " xplot3 = np.linspace(fitrange, xRange[1], 2000)\n",
0656 " label = (\"at crystal output\"+r\" ($\\it{\\gamma}$ only)\" if inputType==\"all\" else \\\n",
0657 " \"at amorphous target input\"+r\" ($\\it{e}^-$ only)\")+\",\\nGaussian fit \"+r\"$\\it{\\sigma}$ = %.3f mm\" % abs(par[2]*10)\n",
0658 " if abs(par[2]) < np.inf:\n",
0659 " axdown2.plot(xplot, gaussian(xplot, *par), c=\"C0\", alpha=0.5, label=label)\n",
0660 " axdown2.plot(xplot2, gaussian(xplot2, *par), c=\"C0\", ls=\":\", alpha=0.5)\n",
0661 " axdown2.plot(xplot3, gaussian(xplot3, *par), c=\"C0\", ls=\":\", alpha=0.5)\n",
0662 " beamSizeY[0] = par[2]\n",
0663 "\n",
0664 "hist = axdown2.hist(data_out[(data_out.particle==\"e+\")].y, bins=nBins, histtype=\"step\", range=xRange, density=True, color=\"C1\")\n",
0665 "x, y = hist[1][:-1]+0.5*abs(hist[1][1]-hist[1][0]), hist[0]\n",
0666 "x, y = x[(x>-fitrange) & (x<fitrange)], y[(x>-fitrange) & (x<fitrange)]\n",
0667 "try:\n",
0668 " par, _ = curve_fit(f=gaussian, xdata=x, ydata=y, bounds=(-np.inf, np.inf))\n",
0669 "except:\n",
0670 " par = (1, 0, np.inf)\n",
0671 "xplot = np.linspace(-fitrange, fitrange, 200)\n",
0672 "xplot2 = np.linspace(xRange[0], -fitrange, 2000)\n",
0673 "xplot3 = np.linspace(fitrange, xRange[1], 2000)\n",
0674 "label = \"at amorphous target output\"+r\" ($\\it{e}^{+}$ only)\"+\",\\nGaussian fit \"+r\"$\\it{\\sigma}$ = %.3f mm\" % abs(par[2]*10)\n",
0675 "if abs(par[2]) < np.inf:\n",
0676 " axdown2.plot(xplot, gaussian(xplot, *par), c=\"C1\", alpha=0.5, label=label)\n",
0677 " axdown2.plot(xplot2, gaussian(xplot2, *par), c=\"C1\", ls=\":\", alpha=0.5)\n",
0678 " axdown2.plot(xplot3, gaussian(xplot3, *par), c=\"C1\", ls=\":\", alpha=0.5)\n",
0679 "beamSizeY[1] = par[2]\n",
0680 "\n",
0681 "ax[0,0].set_ylabel(r\"$\\it{y}$ at amorphous\"+\"\\ntarget output [cm]\")\n",
0682 "ax[0,0].set_xlabel(r\" $\\it{x}$ at amorphous target output [cm]\", loc=\"left\")\n",
0683 "axdown.set_xlabel(r\"$\\it{x}$ [cm]\")\n",
0684 "axdown.set_ylabel(r\"$\\frac{\\mathrm{d}\\it{N}}{\\it{N}\\mathrm{d}\\it{x}}\\left[\\frac{1}{\\mathrm{cm}}\\right]$\")\n",
0685 "axdown.set_xlim((xRange[0], xRange[1]))\n",
0686 "axdown.set_ylim((0, yUpperLim))\n",
0687 "axdown.legend(loc=\"upper left\", fontsize=16)\n",
0688 "axdown.grid(True)\n",
0689 "axdown2.set_xlabel(r\"$\\it{y}$ [cm]\")\n",
0690 "axdown2.set_ylabel(r\"$\\frac{\\mathrm{d}\\it{N}}{\\it{N}\\mathrm{d}\\it{y}}\\left[\\frac{1}{\\mathrm{cm}}\\right]$\")\n",
0691 "axdown2.set_xlim((xRange[0], xRange[1]))\n",
0692 "axdown2.set_ylim((0, yUpperLim))\n",
0693 "axdown2.legend(loc=\"upper left\", fontsize=16)\n",
0694 "axdown2.grid(True)\n",
0695 "fig.tight_layout()\n",
0696 "\n",
0697 "if saveFigs:\n",
0698 " plt.savefig(outpath + 'eBeam_spatial_distrib_' + purename + '.jpg')\n",
0699 "\n",
0700 "beamSizeXStd = [data_in.x.std(), data_out[(data_out.particle==\"e+\")].x.std(), data_out[(data_out.particle==\"e+\")].x.std()]\n",
0701 "beamSizeYStd = [data_in.y.std(), data_out[(data_out.particle==\"e+\")].y.std(), data_out[(data_out.particle==\"e+\")].y.std()]\n",
0702 "\n",
0703 "print(\"e+ beam size along X and Y from Gauss fit in (-%.2f, %.2f) mm range: [-%.2f, %.2f] mm\" % \\\n",
0704 " (fitrange, fitrange, np.abs(beamSizeX[1]*10), np.abs(beamSizeY[1]*10)))"
0705 ]
0706 },
0707 {
0708 "cell_type": "markdown",
0709 "id": "f33236b5-250d-4560-83b0-c9fc7574704f",
0710 "metadata": {},
0711 "source": [
0712 "## Plot the photon spectrum emitted by the Radiator crystal "
0713 ]
0714 },
0715 {
0716 "cell_type": "code",
0717 "execution_count": null,
0718 "id": "30aabcff-7a56-41af-a3b4-1990b9f91dfa",
0719 "metadata": {
0720 "tags": []
0721 },
0722 "outputs": [],
0723 "source": [
0724 "if len(data_in) > 0:\n",
0725 " df_ph_rad = data_in[(data_in.particle==\"gamma\")]\n",
0726 " nbin_gamma = 100\n",
0727 " range_gamma = (50, 500) #(50, 2450)\n",
0728 " IWantDensityInSpectrum = False\n",
0729 " IWantFluence = False\n",
0730 " df_ph_rad_sel = df_ph_rad[(df_ph_rad.P >= range_gamma[0]) & (df_ph_rad.P <= range_gamma[1])]\n",
0731 " ph_beam_area = 4*np.pi*np.std(df_ph_rad.x)*np.std(df_ph_rad.y)*100 \n",
0732 " spectrum_Eph_rad, edges_Eph_rad = np.histogram(df_ph_rad.P, density=IWantDensityInSpectrum, \\\n",
0733 " bins=nbin_gamma, range=range_gamma)\n",
0734 " bin_Eph_rad = edges_Eph_rad[:-1] + (edges_Eph_rad[1]-edges_Eph_rad[0])*0.5\n",
0735 " if not IWantDensityInSpectrum:\n",
0736 " spectrum_Eph_rad = spectrum_Eph_rad / Nevents\n",
0737 " if IWantFluence:\n",
0738 " spectrum_Eph_rad = spectrum_Eph_rad / ph_beam_area\n",
0739 " ylbl = 'ph/mm$^2/e$'\n",
0740 " else:\n",
0741 " ylbl = 'ph/e'\n",
0742 " else:\n",
0743 " ylbl = '1/N$\\\\times$dN/dE'\n",
0744 " spectral_int_Eph_rad = spectrum_Eph_rad * bin_Eph_rad\n",
0745 " plt.figure()\n",
0746 " plt.plot(bin_Eph_rad, spectrum_Eph_rad, alpha=0.75, label='')\n",
0747 " plt.xlabel('Energy [MeV]')\n",
0748 " plt.ylabel(ylbl)\n",
0749 " plt.title('spectrum of the photons emitted by the radiator crystal')\n",
0750 " plt.grid(True)\n",
0751 " plt.yscale('log')\n",
0752 " if saveFigs:\n",
0753 " plt.savefig(outpath + 'Eph_rad_' + purename + '.jpg')\n",
0754 " plt.show()"
0755 ]
0756 },
0757 {
0758 "cell_type": "markdown",
0759 "id": "18d93d3a-8365-4810-a21f-be495f5d264e",
0760 "metadata": {
0761 "tags": []
0762 },
0763 "source": [
0764 "## Histograms of Edep per event in the Radiator and the Converter\n",
0765 "note: pay attention in case of read_PS...these plots make not much sense!"
0766 ]
0767 },
0768 {
0769 "cell_type": "code",
0770 "execution_count": null,
0771 "id": "2df91e29-f46d-4dac-85c0-11dcbbc05946",
0772 "metadata": {
0773 "tags": []
0774 },
0775 "outputs": [],
0776 "source": [
0777 "NbinsEdep = 50\n",
0778 "fs = 20"
0779 ]
0780 },
0781 {
0782 "cell_type": "markdown",
0783 "id": "464d80e7-1622-4c82-b436-e415c5fc63b8",
0784 "metadata": {},
0785 "source": [
0786 "### Radiator"
0787 ]
0788 },
0789 {
0790 "cell_type": "code",
0791 "execution_count": null,
0792 "id": "7566fd8e-98a2-497c-8bd6-a659d9321c2e",
0793 "metadata": {
0794 "tags": []
0795 },
0796 "outputs": [],
0797 "source": [
0798 "if 'edep_rad' in rf_content: \n",
0799 " df_edep_rad = rf['edep_rad'].arrays(library='pd')\n",
0800 " edep_rad = np.array(df_edep_rad[\"edep\"])\n",
0801 " \n",
0802 " print(\"total Edep in the Radiator per event:\", round(np.sum(edep_rad)/Nevents, 2), \"MeV/e-\\n\")\n",
0803 " \n",
0804 " if len(df_edep_rad) > 0:\n",
0805 "\n",
0806 " edep_rad_cut = edep_rad[edep_rad > 1]\n",
0807 "\n",
0808 " plt.figure(figsize=(8, 6))\n",
0809 " h_rad = plt.hist(edep_rad_cut, bins=NbinsEdep,\n",
0810 " histtype=\"step\", label=\"\", density=False,\n",
0811 " edgecolor=\"blue\", linewidth=1.2, alpha=1.)\n",
0812 " plt.title('Edep per event in the radiator', fontsize=fs)\n",
0813 " plt.xlabel(\"Edep [MeV]\", fontsize=fs)\n",
0814 " plt.ylabel(\"Counts\", fontsize=fs)\n",
0815 " plt.xticks(fontsize=fs, rotation=0)\n",
0816 " plt.yticks(fontsize=fs, rotation=0)\n",
0817 " plt.grid(which=\"major\", color=\"gray\", linestyle=\"--\", linewidth=1)\n",
0818 " if saveFigs:\n",
0819 " plt.savefig(outpath + 'Edep_distrib_rad_' + purename + '.jpg')\n",
0820 " plt.show() \n",
0821 "else:\n",
0822 " edep_rad = []"
0823 ]
0824 },
0825 {
0826 "cell_type": "markdown",
0827 "id": "a5c0c89a-3e5c-4856-adf1-73cd6128916b",
0828 "metadata": {},
0829 "source": [
0830 "### Converter"
0831 ]
0832 },
0833 {
0834 "cell_type": "code",
0835 "execution_count": null,
0836 "id": "0b11b063-ffe4-4284-994a-54593e9b1daf",
0837 "metadata": {
0838 "tags": []
0839 },
0840 "outputs": [],
0841 "source": [
0842 "if 'edep_conv' in rf_content:\n",
0843 " df_edep_conv = rf['edep_conv'].arrays(library='pd')\n",
0844 " edep_conv = np.array(df_edep_conv[\"edep\"])\n",
0845 " \n",
0846 " print(\"total Edep in the Converter per event:\", round(np.sum(edep_conv)*1.e-3/Nevents, 2), \"GeV/e-\\n\")\n",
0847 " \n",
0848 " if len(df_edep_conv) > 0 and not \"_GT\" in name:\n",
0849 "\n",
0850 " edep_conv_cut = edep_conv[edep_conv > 0]\n",
0851 "\n",
0852 " plt.figure(figsize=(8, 6))\n",
0853 " h_conv = plt.hist(edep_conv_cut, bins=NbinsEdep,\n",
0854 " histtype=\"step\", label=\"\", density=False,\n",
0855 " edgecolor=\"blue\", linewidth=1.2, alpha=1.)\n",
0856 " plt.title('Edep per event in the converter', fontsize=fs)\n",
0857 " plt.xlabel(\"Edep [MeV]\", fontsize=fs)\n",
0858 " plt.ylabel(\"Counts\", fontsize=fs)\n",
0859 " plt.xticks(fontsize=fs, rotation=0)\n",
0860 " plt.yticks(fontsize=fs, rotation=0)\n",
0861 " plt.grid(which=\"major\", color=\"gray\", linestyle=\"--\", linewidth=1)\n",
0862 " if saveFigs:\n",
0863 " plt.savefig(outpath + 'Edep_distrib_conv_' + purename + '.jpg')\n",
0864 " plt.show()\n",
0865 "else:\n",
0866 " edep_conv = []"
0867 ]
0868 },
0869 {
0870 "cell_type": "markdown",
0871 "id": "6f646b9a-ec72-4500-adc1-8d998c6683aa",
0872 "metadata": {
0873 "tags": []
0874 },
0875 "source": [
0876 "## Settings to read the built-in BoxMesh scorer with Edep in the Absorber (Converter or Radiator)"
0877 ]
0878 },
0879 {
0880 "cell_type": "code",
0881 "execution_count": null,
0882 "id": "dcd7ef10-3916-4ce0-badc-3f140d9aff42",
0883 "metadata": {
0884 "tags": []
0885 },
0886 "outputs": [],
0887 "source": [
0888 "tranvsizeX = 100 #volume tranversal X size (mm)\n",
0889 "tranvsizeY = 100 #volume tranversal Y size (mm)\n",
0890 "\n",
0891 "print(\"tranverse sixe (X*Y) = %.1f x %.1f mm2\" % (tranvsizeX, tranvsizeY))\n",
0892 "\n",
0893 "if 'conv_th' in locals() and conv_th != '': \n",
0894 " tranvsizeZ = conv_th\n",
0895 "elif 'rad_th' in locals() and rad_th != '':\n",
0896 " tranvsizeZ = rad_th\n",
0897 "else:\n",
0898 " try:\n",
0899 " tranvsizeZ = float(name.split('W')[1].split('mm_')[0])\n",
0900 " except:\n",
0901 " print('Enter the thickness [mm] of the target (or the Radiator if it is not an hybrid source):')\n",
0902 " tranvsizeZ = float(input())\n",
0903 " \n",
0904 "print(\"tranvsizeZ = %.1f mm\\n\" % (tranvsizeZ))\n",
0905 " \n",
0906 "IWantPlotVoxel = False\n",
0907 "IWantPlotX0fract = False\n",
0908 "X0 = 3.504 #crystal radiation length (mm)\n",
0909 "\n",
0910 "normEvents = True; #normalize w.r.t. simulated events (set always to true to compare with previous results)\n",
0911 "\n",
0912 "axis_proj = 2 #0: axial, 1:sagittal, 2:coronal\n",
0913 "proj_type = 1 #1: mean, 2: sum\n",
0914 "p2m = 1 #voxels around which to mean\n",
0915 "\n",
0916 "plot_proj = True\n",
0917 "reader_verb = True\n",
0918 "\n",
0919 "titstr = ''\n",
0920 "\n",
0921 "cmap2D = 'viridis'\n",
0922 "Wfig = 12\n",
0923 "Hfig = 8\n",
0924 "fs = 20\n",
0925 "ms = 6"
0926 ]
0927 },
0928 {
0929 "cell_type": "markdown",
0930 "id": "26ce0632-da84-4982-a944-0680009b2746",
0931 "metadata": {},
0932 "source": [
0933 "### Function to read the result provided by the built-in BoxMesh scorer"
0934 ]
0935 },
0936 {
0937 "cell_type": "code",
0938 "execution_count": null,
0939 "id": "b511c1ad-a6eb-43f6-ac0e-21c88b1ca39a",
0940 "metadata": {
0941 "tags": []
0942 },
0943 "outputs": [],
0944 "source": [
0945 "def read_Edep_BoxMesh(filename, normEvents, Nevents, \n",
0946 " tranvsizeX, tranvsizeY, tranvsizeZ):\n",
0947 " \"\"\"\n",
0948 " Function to read the total Edep accumulated through a built-in BoxMesh scorer.\n",
0949 " It is general. It returns [data, (x,y,z)], where:\n",
0950 " data is a dictionary with 10 columns defined as follows\n",
0951 " {\"ind_x\", \"ind_y\", \"ind_z\", \"eDep\", \"x\", \"y\", \"z\", \"r\" ,\"eDep_err\", \"eDepDensity\", \"eDepDensity_err\"}\n",
0952 " and (x,y,z) are the coordinates [mm] of the voxel centers.\n",
0953 " \"\"\"\n",
0954 " \n",
0955 " def find(cond, N=1e7): \n",
0956 " \"\"\"\n",
0957 " function, equivalent to Matlab's one, that returns\n",
0958 " a list with the indices of an array/matrix\n",
0959 " that satisfy a given condition.\n",
0960 " \"\"\"\n",
0961 " cond = cond.reshape(np.size(cond), 1).ravel()\n",
0962 " index = list(np.argwhere(cond).ravel())\n",
0963 " return index[:N]\n",
0964 " \n",
0965 " # Retrieve data and put them into a dataframe\n",
0966 " data = pd.read_csv(\n",
0967 " filename, skiprows=3, names=[\"ind_x\", \"ind_y\", \"ind_z\", \"eDep\", \"eDep2\", \"Nentry\"]\n",
0968 " )\n",
0969 " \n",
0970 " # Calculate eDep uncertainty \n",
0971 " data[\"eDep_err\"] = (data[\"eDep2\"] - data[\"eDep\"]**2/data[\"Nentry\"])**0.5\n",
0972 " data.fillna(0, inplace=True)\n",
0973 " data = data.drop(columns=['eDep2', 'Nentry'])\n",
0974 "\n",
0975 " # Retrieve the number of voxels in each direction\n",
0976 " Nvoxel = len(data)\n",
0977 " zzzz = find(np.array(data[\"ind_z\"]) == 0, 2)\n",
0978 " if len(zzzz) > 1:\n",
0979 " nz = zzzz[1]\n",
0980 " else:\n",
0981 " nz = len(data[\"ind_y\"]) \n",
0982 " ny = np.max([round((np.max(find(np.array(data[\"ind_y\"])==0, nz+1))-1)/nz), 1])\n",
0983 " nx = max(np.array(data[\"ind_x\"]))+1\n",
0984 " \n",
0985 " # Set geometrical size\n",
0986 " Xmin = -tranvsizeX*0.5 \n",
0987 " Xmax = tranvsizeX*0.5 \n",
0988 " Ymin = -tranvsizeY*0.5 \n",
0989 " Ymax = tranvsizeY*0.5\n",
0990 " Zmin = 0\n",
0991 " Zmax = tranvsizeZ\n",
0992 "\n",
0993 " # Generate vectors of points linearly spaced (corrected in 24/12/2023)\n",
0994 " Xedges = np.linspace(Xmin, Xmax, nx+1) #[mm]\n",
0995 " Yedges = np.linspace(Ymin, Ymax, ny+1) #[mm]\n",
0996 " Zedges = np.linspace(Zmin, Zmax, nz+1) #[mm]\n",
0997 " dx = Xedges[1] - Xedges[0]\n",
0998 " dy = Yedges[1] - Yedges[0]\n",
0999 " dz = Zedges[1] - Zedges[0]\n",
1000 " #print(\"dx:\", dx, \"mm, dy:\", dy, \"mm, dz:\", dz, \"mm\")\n",
1001 " x = Xedges[:-1] + dx*0.5\n",
1002 " y = Yedges[:-1] + dy*0.5\n",
1003 " z = Zedges[:-1] + dz*0.5\n",
1004 "\n",
1005 " # Physical position inside the mesh data\n",
1006 " data[\"x\"] = dx * (data[\"ind_x\"] + 0.5) - tranvsizeX*0.5 #central x [mm]\n",
1007 " data[\"y\"] = dy * (data[\"ind_y\"] + 0.5) - tranvsizeY*0.5 #central y [mm]\n",
1008 " data[\"z\"] = dz * (data[\"ind_z\"] + 0.5) #central z [mm]\n",
1009 " data[\"r\"] = np.sqrt(data[\"x\"]**2 + data[\"y\"]**2) #central r [mm]\n",
1010 " \n",
1011 " # eDep Map\n",
1012 " if normEvents:\n",
1013 " data[\"eDep\"] = data[\"eDep\"] / Nevents\n",
1014 " data[\"eDep_err\"] = data[\"eDep_err\"] / Nevents\n",
1015 " data[\"eDepDensity\"] = data[\"eDep\"] / (dz * dy * dx) #[MeV/mm**3] or [MeV/(mm**3 event)]\n",
1016 " data[\"eDepDensity_err\"] = data[\"eDep_err\"] / (dz * dy * dx) #[MeV/mm**3] or [MeV/(mm**3 event)]\n",
1017 "\n",
1018 " return data, (x,y,z)"
1019 ]
1020 },
1021 {
1022 "cell_type": "markdown",
1023 "id": "1edbb447-5b72-4c6c-a5d7-a92cbe25d3bd",
1024 "metadata": {},
1025 "source": [
1026 "## Read the built-in BoxMesh scorer with Edep in the Absorber"
1027 ]
1028 },
1029 {
1030 "cell_type": "code",
1031 "execution_count": null,
1032 "id": "b6f22f16-1cdc-44b2-88bb-848fac3e52b3",
1033 "metadata": {
1034 "tags": []
1035 },
1036 "outputs": [],
1037 "source": [
1038 "# read BoxMesh scorer\n",
1039 "try:\n",
1040 " filename = path + name.replace(\"output\", \"Edep\") + \".txt\"\n",
1041 "except:\n",
1042 " print('Enter the name of the file with the BoxMesh scorer results:')\n",
1043 " filename = float(input())\n",
1044 "\n",
1045 "results_BoxMesh = read_Edep_BoxMesh(filename, normEvents, Nevents, \n",
1046 " tranvsizeX, tranvsizeY, tranvsizeZ)\n",
1047 "df_BoxMesh = results_BoxMesh[0]\n",
1048 "voxel_coord = results_BoxMesh[1]\n",
1049 "del results_BoxMesh\n",
1050 "\n",
1051 "# retrieve variables form BoxMesh scorer\n",
1052 "eDep = df_BoxMesh.eDep\n",
1053 "eDepDensity = df_BoxMesh.eDepDensity\n",
1054 "x = voxel_coord[0]\n",
1055 "y = voxel_coord[1]\n",
1056 "z = voxel_coord[2]\n",
1057 "if x.shape[0] > 1:\n",
1058 " dx = x[1] - x[0]\n",
1059 "else:\n",
1060 " dx = 0\n",
1061 "if y.shape[0] > 1:\n",
1062 " dy = y[1] - y[0]\n",
1063 "else:\n",
1064 " dy = 0\n",
1065 "if z.shape[0] > 1:\n",
1066 " dz = z[1] - z[0]\n",
1067 "else:\n",
1068 " dz = 0\n",
1069 "\n",
1070 "# variables for contour plot of Edep\n",
1071 "nx, ny , nz = [voxel_coord[i].shape[0] for i in range(3)]\n",
1072 "X, Z = np.meshgrid(x, z)\n",
1073 "icx = 0 if nx == 1 else int(X.shape[1]/2+1)\n",
1074 "eDepMap = np.transpose(np.array(eDep).reshape(nx,ny,nz)[icx,:,:])\n",
1075 "eDepDensityMap = np.transpose(np.array(eDepDensity).reshape(nx,ny,nz)[icx,:,:])\n",
1076 "\n",
1077 "# Zprofile of Edep\n",
1078 "ic = int(Z.shape[1]/2+1)\n",
1079 "profileZ_eDep = np.zeros(nz)\n",
1080 "profileZ_eDepDensity = np.zeros(nz)\n",
1081 "for j in range(nz):\n",
1082 " if proj_type == 1:\n",
1083 " profileZ_eDep[j] = np.mean(eDepMap[j][ic-p2m:ic+p2m])\n",
1084 " profileZ_eDepDensity[j] = np.mean(eDepDensityMap[j][ic-p2m:ic+p2m])\n",
1085 " else:\n",
1086 " profileZ_eDep[j] = np.sum(eDepMap[j][ic-p2m:ic+p2m])\n",
1087 " profileZ_eDepDensity[j] = np.sum(eDepDensityMap[j][ic-p2m:ic+p2m])\n",
1088 "\n",
1089 "PEDD = np.max(np.array(eDepDensity))\n",
1090 "print(\"PEDD:\", round(PEDD,2), \"MeV/(mm^3 e-)\")"
1091 ]
1092 },
1093 {
1094 "cell_type": "markdown",
1095 "id": "b4339b43-c89a-4f10-8639-f29416c5845c",
1096 "metadata": {},
1097 "source": [
1098 "### Contour and plofile plot of Edep (density) distribution"
1099 ]
1100 },
1101 {
1102 "cell_type": "code",
1103 "execution_count": null,
1104 "id": "4a89f66c-cf61-4d95-b4a4-e30769fa6f66",
1105 "metadata": {
1106 "tags": []
1107 },
1108 "outputs": [],
1109 "source": [
1110 "# set options\n",
1111 "if normEvents:\n",
1112 " clbl = \"Edep density per event [MeV/(mm$^3$ e-]\"\n",
1113 "else:\n",
1114 " clbl = \"Edep density [MeV/mm$^3$]\"\n",
1115 "\n",
1116 "# contour plot of Edep\n",
1117 "if eDepDensityMap.shape[0]>1 and eDepDensityMap.shape[1]>1: \n",
1118 " plt.figure(figsize=(Wfig, Hfig))\n",
1119 " Nlev = 50\n",
1120 " if IWantPlotVoxel:\n",
1121 " plt.contourf(eDepDensityMap, Nlev, cmap='viridis')\n",
1122 " xlabel = \"X [voxel]\"\n",
1123 " ylabel = \"Z [voxel]\" \n",
1124 " else:\n",
1125 " plt.contourf(X, Z, eDepDensityMap, Nlev, cmap='viridis')\n",
1126 " xlabel = \"X [mm]\"\n",
1127 " ylabel = \"Z [mm]\"\n",
1128 " #plt.gca().set_aspect('equal')\n",
1129 " plt.gca().invert_yaxis()\n",
1130 " cbar = plt.colorbar()\n",
1131 " cbar.ax.tick_params(labelsize=fs)\n",
1132 " cbar.set_label(clbl, fontsize=fs, rotation=90)\n",
1133 " plt.title(titstr, fontsize=fs)\n",
1134 " plt.xlabel(xlabel, fontsize=fs)\n",
1135 " plt.ylabel(ylabel, fontsize=fs, wrap=True)\n",
1136 " plt.xticks(fontsize=fs, rotation=0)\n",
1137 " plt.yticks(fontsize=fs, rotation=0)\n",
1138 " plt.gca().xaxis.set_minor_locator(AutoMinorLocator(5))\n",
1139 " plt.gca().yaxis.set_minor_locator(AutoMinorLocator(5))\n",
1140 " plt.gca().tick_params(axis=\"both\", which='major', direction='in', length=8)\n",
1141 " plt.gca().tick_params(axis=\"both\", which='minor', direction='in', length=4)\n",
1142 " plt.grid(False)\n",
1143 " if saveFigs:\n",
1144 " plt.savefig(outpath + 'Edep_proj_' + purename + '.jpg')\n",
1145 " plt.show()\n",
1146 "\n",
1147 "# plot Zprofile of Edep\n",
1148 "if IWantPlotVoxel:\n",
1149 " xplot = np.linspace(0, nz-1, nz)\n",
1150 " ylabel = \"Z [voxel]\" \n",
1151 "else:\n",
1152 " xplot = z\n",
1153 " ylabel = \"Z [mm]\"\n",
1154 "plt.figure(figsize=(Wfig, Hfig))\n",
1155 "plt.plot(xplot, profileZ_eDepDensity, label=\"\",\n",
1156 " color=\"blue\", linestyle='-', linewidth=2, alpha=0.75,\n",
1157 " marker='', markersize=ms, markerfacecolor=\"Blue\")\n",
1158 "plt.title(titstr, fontsize=fs)\n",
1159 "plt.xlabel(ylabel, fontsize=fs, wrap=True)\n",
1160 "plt.ylabel(clbl, fontsize=fs, wrap=True)\n",
1161 "plt.xticks(fontsize=fs, rotation=0)\n",
1162 "plt.yticks(fontsize=fs, rotation=0)\n",
1163 "plt.gca().xaxis.set_minor_locator(AutoMinorLocator(5))\n",
1164 "plt.gca().yaxis.set_minor_locator(AutoMinorLocator(5))\n",
1165 "plt.gca().tick_params(axis=\"both\", which='major', direction='in', length=8)\n",
1166 "plt.gca().tick_params(axis=\"both\", which='minor', direction='in', length=4)\n",
1167 "plt.grid(True)\n",
1168 "if saveFigs:\n",
1169 " plt.savefig(outpath + 'Edep_profileZ_' + purename + '.jpg')\n",
1170 "plt.show()"
1171 ]
1172 },
1173 {
1174 "cell_type": "markdown",
1175 "id": "96e92388-7a39-40b7-a1a5-25adfdab1e0c",
1176 "metadata": {},
1177 "source": [
1178 "### radius-vs-depth energy density"
1179 ]
1180 },
1181 {
1182 "cell_type": "code",
1183 "execution_count": null,
1184 "id": "4f6c664d-8140-4b16-aa7d-8cdd4a6d3d1c",
1185 "metadata": {
1186 "tags": []
1187 },
1188 "outputs": [],
1189 "source": [
1190 "# plot options\n",
1191 "rLim = 1.5 #mm\n",
1192 "bScaleWidth = False\n",
1193 "bLog = False\n",
1194 "upperLim = 20 #MeV/(mm^3 e-)\n",
1195 "ind_r_lsit = [0, 7, 15, 22] #6GeV: [0, 5, 10, 15]"
1196 ]
1197 },
1198 {
1199 "cell_type": "code",
1200 "execution_count": null,
1201 "id": "414084ec-d20e-4863-b513-d0221ad43e96",
1202 "metadata": {
1203 "tags": []
1204 },
1205 "outputs": [],
1206 "source": [
1207 "# radius-vs-depth energy density\n",
1208 "bData = df_BoxMesh[\"r\"] < rLim if rLim != None else df_BoxMesh[\"r\"] < 1e5\n",
1209 "Z, R = np.meshgrid(\n",
1210 " sorted(list(set(df_BoxMesh[bData][\"z\"]))),\n",
1211 " sorted(list(set(df_BoxMesh[bData][\"r\"]))),\n",
1212 ")\n",
1213 "ED = interpolate.griddata(\n",
1214 " (df_BoxMesh[bData][\"z\"], df_BoxMesh[bData][\"r\"]),\n",
1215 " df_BoxMesh[bData][\"eDepDensity\"], (Z, R), method='nearest'\n",
1216 ")\n",
1217 "\n",
1218 "if ED.shape[0]>1 and ED.shape[1]>1: \n",
1219 " width = 5*max(df_BoxMesh[\"z\"]) if bScaleWidth else 10\n",
1220 " fig, ax = plt.subplots(num=\"mesh\", figsize=[width, 8], nrows=2, sharex=True, constrained_layout=True)\n",
1221 "\n",
1222 " # 2d plot\n",
1223 " plotmesh = ax[0].pcolormesh(Z, R, ED, shading=\"nearest\", norm=LogNorm() if bLog else None)\n",
1224 " cbar = plt.colorbar(plotmesh, ax=ax[0])\n",
1225 " ax[0].grid()\n",
1226 " ax[0].set_ylim((0, max(df_BoxMesh[bData][\"r\"])))\n",
1227 "\n",
1228 " # 1d projection - energy density vs depth\n",
1229 " dr = (dx**2 + dy**2)**0.5\n",
1230 " for ind_r in ind_r_lsit:\n",
1231 " ind_r_eff = int(ind_r * 0.1 / dr)\n",
1232 " r_eff = dr * ind_r_eff\n",
1233 " bData = (df_BoxMesh[\"r\"] >= (dr * (ind_r_eff - 0.5))) & \\\n",
1234 " (df_BoxMesh[\"r\"] <= (dr * (ind_r_eff + 0.5))) \n",
1235 " temp = df_BoxMesh[bData][[\"z\", \"eDepDensity\"]].sort_values(by=[\"z\"])\n",
1236 " zlist = np.array(temp.z.unique())\n",
1237 " ymean = [np.mean(np.array(temp[temp[\"z\"] == zi][\"eDepDensity\"])) for zi in zlist]\n",
1238 " ax[1].plot(\n",
1239 " #df_BoxMesh[bData][\"z\"], df_BoxMesh[bData][\"eDepDensity\"],\n",
1240 " zlist, ymean, #corrected by gpaterno\n",
1241 " label = \"r = %.2f mm\" % r_eff,\n",
1242 " marker='', linestyle='-'\n",
1243 " )\n",
1244 " #ax[1].set_ylim((0, upperLim))\n",
1245 " ax[1].grid()\n",
1246 " ax[1].legend(loc=\"upper left\", fontsize=14)\n",
1247 " fs_local = 18\n",
1248 "\n",
1249 " ax[1].set_xlabel(\"z [mm]\", fontsize=fs_local)\n",
1250 " ax[0].set_ylabel(\"r [mm]\", fontsize=fs_local)\n",
1251 " ax[1].set_ylabel(r\"eDep [MeV/(mm$^3$ e-)]\", fontsize=fs_local)\n",
1252 " cbar.set_label(r\"eDep [MeV/(mm$^3$ e-)]\", rotation=90, labelpad=16, fontsize=fs_local)\n",
1253 " #fig.suptitle(\"e- beam features: %.2f GeV, %.1f mm\" % (Ein, sigma_in))\n",
1254 " if saveFigs:\n",
1255 " plt.savefig(outpath + 'Edep_profileR_' + purename + '.jpg')\n",
1256 " plt.show()"
1257 ]
1258 },
1259 {
1260 "cell_type": "markdown",
1261 "id": "4f319d8c-417b-4e96-a0f3-843939ed5c6b",
1262 "metadata": {},
1263 "source": [
1264 "## Get the positrons, analyze and export them"
1265 ]
1266 },
1267 {
1268 "cell_type": "markdown",
1269 "id": "26382273-291e-4998-ab0d-1eb30127bb50",
1270 "metadata": {},
1271 "source": [
1272 "### Get the positrons"
1273 ]
1274 },
1275 {
1276 "cell_type": "code",
1277 "execution_count": null,
1278 "id": "3a654a57-cdaf-4eb5-9660-bf3ead04891e",
1279 "metadata": {
1280 "tags": []
1281 },
1282 "outputs": [],
1283 "source": [
1284 "positrons = data_out[data_out.particle==\"e+\"].copy()\n",
1285 "print(\"yield_e+:\", round(positrons.shape[0] / Nevents, 2), \"\\n\")\n",
1286 "\n",
1287 "positrons"
1288 ]
1289 },
1290 {
1291 "cell_type": "markdown",
1292 "id": "b4e1a5ad-8e59-4d14-8d84-60789cbe9ad7",
1293 "metadata": {},
1294 "source": [
1295 "### Get positrons within a given energy (momentum) threshold"
1296 ]
1297 },
1298 {
1299 "cell_type": "code",
1300 "execution_count": null,
1301 "id": "5dc3eab2-a137-420d-a1c5-9b2a9b8c1670",
1302 "metadata": {
1303 "tags": []
1304 },
1305 "outputs": [],
1306 "source": [
1307 "p_th = 100 #MeV\n",
1308 "positrons[positrons[\"P\"] < 100]"
1309 ]
1310 },
1311 {
1312 "cell_type": "markdown",
1313 "id": "f1ae45cb-78ff-4633-ba38-e863e9e64b94",
1314 "metadata": {},
1315 "source": [
1316 "### Plot and Save the positron spectrum (taking into account angular and energy cuts)"
1317 ]
1318 },
1319 {
1320 "cell_type": "code",
1321 "execution_count": null,
1322 "id": "b455dff7-b783-4f28-b64a-c5a08aa55888",
1323 "metadata": {
1324 "tags": []
1325 },
1326 "outputs": [],
1327 "source": [
1328 "save_spectrum = False\n",
1329 "\n",
1330 "# Calculate positron beam energy distribution features\n",
1331 "E_pos = (positrons.P**2 + 0.511**2)**0.5 #MeV\n",
1332 "Emean_pos = np.mean(E_pos)\n",
1333 "Estdev = np.std(E_pos)\n",
1334 "Espread_pos = Estdev / Emean_pos\n",
1335 "print(\"Emean_pos:\", round(Emean_pos, 2), \"MeV\")\n",
1336 "print(\"Espread_pos:\", round(Espread_pos, 2), \"(sigma/mu)\")\n",
1337 "#angle_cut = np.mean(divergence) #mrad\n",
1338 "angle_cut = 140 #mrad\n",
1339 "positrons_cut = positrons[positrons[\"tht\"] < angle_cut]\n",
1340 "#mask = (positrons.x**2+positrons.y**2)**0.5 < np.abs(np.mean([beamSizeX[1], beamSizeY[1]]))\n",
1341 "#positrons_cut = positrons[mask] \n",
1342 "E_pos_cut = (positrons_cut.P**2 + 0.511**2)**0.5 #MeV\n",
1343 "Emean_pos_cut = np.mean(E_pos_cut)\n",
1344 "Estdev_cut = np.std(E_pos_cut)\n",
1345 "Espread_pos_cut = Estdev_cut / Emean_pos_cut\n",
1346 "print(\"Emean_pos_cut (tht < %.2f mrad):\" % angle_cut, round(Emean_pos_cut, 2), \"MeV\")\n",
1347 "print(\"Espread_pos_cut (tht < %.2f mrad):\" % angle_cut, round(Espread_pos_cut, 2), \"(sigma/mu)\")\n",
1348 "Eth = 100 # MeV\n",
1349 "NposEth = len(E_pos.values[E_pos.values < Eth]) / len(E_pos.values)\n",
1350 "NsigmaEth = Eth / (Emean_pos + Estdev)\n",
1351 "print(\"fraction of positrons with energy < %.0f MeV (%.2f*sigma): %.2f\\n\" % (Eth, NsigmaEth, NposEth))\n",
1352 "\n",
1353 "# Plot histogram of positrons energy\n",
1354 "nbin_pos = 100\n",
1355 "range_pos = (0, 100)\n",
1356 "IWantDensity = False\n",
1357 "plt.figure(figsize=(9, 6))\n",
1358 "h = plt.hist(E_pos, density=IWantDensity, bins=nbin_pos, range=range_pos, alpha=0.5, \\\n",
1359 " label='positron spectrum')\n",
1360 "h2 = plt.hist(E_pos_cut, density=IWantDensity, bins=nbin_pos, range=range_pos, alpha=0.5, \\\n",
1361 " label='positron spectrum within %.2f mrad' % (angle_cut))\n",
1362 "plt.legend(fontsize=14)\n",
1363 "plt.xlabel('Energy [MeV]')\n",
1364 "plt.ylabel('Counts [arb. units]')\n",
1365 "plt.title('')\n",
1366 "plt.grid(True)\n",
1367 "plt.yscale('log')\n",
1368 "if saveFigs:\n",
1369 " plt.savefig(outpath + 'eplusBeam_E_distrib_' + purename + '.jpg')\n",
1370 "plt.show()\n",
1371 "\n",
1372 "if not IWantDensity:\n",
1373 " print(\"sum of positron spectrum: %d\" % sum(h[0]))\n",
1374 " print(\"sum of positron spectrum within %.2f mrad: %d\\n\" % (angle_cut, sum(h2[0])))\n",
1375 "else:\n",
1376 " print(\"\\n\")\n",
1377 " \n",
1378 "# Write the positron spectrum to a file\n",
1379 "if save_spectrum:\n",
1380 " Eedges, spectrum = h[1], h[0]\n",
1381 " output_file = outpath + 'positron_spectrum_' + purename + '.txt'\n",
1382 " write_spectrum_to_G4file(Eedges, spectrum, output_file)\n",
1383 " _, spectrum_cut = h2[1], h2[0]\n",
1384 " output_file_cut = outpath + 'positron_spectrum_cut_%.1fmrad_' % angle_cut + purename + '.txt'\n",
1385 " write_spectrum_to_G4file(Eedges, spectrum_cut, output_file_cut)"
1386 ]
1387 },
1388 {
1389 "cell_type": "markdown",
1390 "id": "92ca628d-142a-4109-b6e7-bc202f1f7cbe",
1391 "metadata": {},
1392 "source": [
1393 "### Convert the positron beam in RF-Track format (for tracking in the Capture system...)"
1394 ]
1395 },
1396 {
1397 "cell_type": "code",
1398 "execution_count": null,
1399 "id": "a554a8e9-9640-4766-ae5a-6faa7e1619ef",
1400 "metadata": {
1401 "tags": []
1402 },
1403 "outputs": [],
1404 "source": [
1405 "convertFileToRFTrack = False\n",
1406 "\n",
1407 "# Prepare the file to feed the RF-Track code to tack the positrons inside the Capture System/Positron Linac with\n",
1408 "\"\"\"\n",
1409 "NOTE: In RF-Track x'=px/pz=tan(thx) and y'=py/pz=tan(thy) (see the manual at page 22).\n",
1410 " The approximation x'=thx and y'=thy holds for small-angle only,\n",
1411 " which is the case of particle beams in accelators. However, \n",
1412 " for example in a drift, we correctly have x2=x1+x'*(z2-z1) and y2=y1+y'*(z2-z1).\n",
1413 " In our case, positrons can exit the crystal also at large angles \n",
1414 " and, for some of them, px and/or py can be (much) greater than pz. Thus,\n",
1415 " x' and y' are not angles, but tangents (which can tend to infinity) and \n",
1416 " the fact that they are expressed in mrad means that they are multiplied by 1e-3.\n",
1417 " These particles would be lost in the capture section. However, if we want to\n",
1418 " calculate the tranverse phase space of the positron beam at the exit of the crystal,\n",
1419 " we must calculate properly (with arctan) thx, thy and set a proper angular cut.\n",
1420 "\"\"\"\n",
1421 "if convertFileToRFTrack:\n",
1422 " ## Add variables to the original positron dataframe\n",
1423 " positrons[\"xp[mrad]\"] = (positrons.px/(positrons.pz*1000))*1000\n",
1424 " positrons[\"yp[mrad]\"] = (positrons.py/(positrons.pz*1000))*1000\n",
1425 " positrons[\"p[MeV/c]\"] = positrons.P\n",
1426 " positrons[\"#x[mm]\"] = positrons[\"x\"]*10 #this is because they were previously converted form [mm] to [cm]\n",
1427 " positrons[\"y[mm]\"] = positrons[\"y\"]*10\n",
1428 " \n",
1429 " ## Select only a set of variables\n",
1430 " if addID:\n",
1431 " positrons[\"ID\"] = list(range(1, len(positrons)+1))\n",
1432 " positrons_out = positrons[[\"#x[mm]\", \"xp[mrad]\", \"y[mm]\", \"yp[mrad]\", \"p[MeV/c]\", \"ID\"]]\n",
1433 " else:\n",
1434 " positrons_out = positrons[[\"#x[mm]\", \"xp[mrad]\", \"y[mm]\", \"yp[mrad]\", \"p[MeV/c]\"]]\n",
1435 "\n",
1436 " ## Guassian sampling in time, to keep the RF phases of the Hybrid similar to the conventional scheme\n",
1437 " c = 299792458 #m/s\n",
1438 " if setGaussianTimeShape:\n",
1439 " mean_value = 17.762 #mm/c\n",
1440 " std_value = 1.1950 #mm/c\n",
1441 " num_sample = len(positrons_out)\n",
1442 " gaussian_samples = np.random.normal(mean_value, std_value, num_sample)\n",
1443 " t = gaussian_samples\n",
1444 " else: \n",
1445 " t = positrons.t * 1e-6 * c #ns -> mm/c\n",
1446 " positrons_out.insert(4, 't[mm/c]', t)\n",
1447 "\n",
1448 " ## Save the positron phase-space to a txt file\n",
1449 " name_out = name.replace('output', 'positrons')\n",
1450 " positrons_out.to_csv(outpath + name_out + \".dat\", index=False, sep=' ') \n",
1451 " print(\"positron beam phase-space converted to RF-Track format!\")"
1452 ]
1453 },
1454 {
1455 "cell_type": "markdown",
1456 "id": "4d7e77d2-b658-4e68-ab20-80c980242297",
1457 "metadata": {},
1458 "source": [
1459 "## Export the results of the simulation"
1460 ]
1461 },
1462 {
1463 "cell_type": "code",
1464 "execution_count": null,
1465 "id": "d7aa1f40-3ca6-4c74-9350-9ee4542010dc",
1466 "metadata": {
1467 "tags": []
1468 },
1469 "outputs": [],
1470 "source": [
1471 "# Fill the result list with those of the current simulation\n",
1472 "case_list.append(purename)\n",
1473 "yield_pos_list.append(round(data_out[(data_out.particle==\"e+\")].shape[0] / Nevents, 2))\n",
1474 "yield_ele_list.append(round(data_out[(data_out.particle==\"e-\")].shape[0] / Nevents, 2))\n",
1475 "yield_ph_list.append(round(data_out[(data_out.particle==\"gamma\")].shape[0] / Nevents, 2))\n",
1476 "yield_n_list.append(round(data_out[(data_out.particle==\"neutron\")].shape[0] / Nevents, 2))\n",
1477 "pos_mean_E_list.append(round(Emean_pos, 2))\n",
1478 "pos_spread_E_list.append(round(Espread_pos, 2)) \n",
1479 "pos_mean_div_fit_list.append(round(np.mean(divergence), 2))\n",
1480 "pos_mean_size_fit_list.append(round(np.mean([np.abs(beamSizeX[1]*10), np.abs(beamSizeY[1]*10)]), 2))\n",
1481 "Edep_rad_list.append(round(np.sum(edep_rad)/Nevents, 2))\n",
1482 "Edep_conv_list.append(round(np.sum(edep_conv)*1e-3/Nevents, 2))\n",
1483 "PEDD_list.append(round(PEDD, 2))"
1484 ]
1485 },
1486 {
1487 "cell_type": "code",
1488 "execution_count": null,
1489 "id": "f743be58-cfec-4993-bde2-c224f5bd9094",
1490 "metadata": {
1491 "tags": []
1492 },
1493 "outputs": [],
1494 "source": [
1495 "# Fill a dictionary with the results\n",
1496 "results = { \"case\": case_list,\n",
1497 " \"yield_e+\": yield_pos_list,\n",
1498 " \"yield_e-\": yield_ele_list,\n",
1499 " \"yield_ph\": yield_ph_list,\n",
1500 " \"yield_n\": yield_n_list,\n",
1501 " \"e+_mean_E[MeV]\": pos_mean_E_list,\n",
1502 " \"e+_spread_E[sigma/mu]\": pos_spread_E_list,\n",
1503 " \"e+_mean_div_fit[mrad]\": pos_mean_div_fit_list,\n",
1504 " \"e+_mean_size_fit[mm]\": pos_mean_size_fit_list,\n",
1505 " \"Edep_rad[MeV/e-]\": Edep_rad_list,\n",
1506 " \"Edep_conv[GeV/e-]\": Edep_conv_list,\n",
1507 " \"PEDD[MeV/(mm^3*e-)]\": PEDD_list\n",
1508 " }\n",
1509 "\n",
1510 "# Get a dataframe of the results\n",
1511 "df_results = pd.DataFrame.from_dict(results)\n",
1512 "\n",
1513 "# Export the results in a json file.\n",
1514 "# pickle works pretty much the same, \n",
1515 "# but it I cannot directly have a look at it.\n",
1516 "import json \n",
1517 "print(\"\\nWriting json file with these data:\")\n",
1518 "#for s in results:\n",
1519 "# print(\"\\t\", s, \":\", results[s])\n",
1520 "outname = outpath + name.replace(\"output\", \"results\") \n",
1521 "with open(outname + \".json\", \"w\") as file: \n",
1522 " json.dump(results, file)\n",
1523 "file.close()\n",
1524 "\n",
1525 "# Print results\n",
1526 "df_results"
1527 ]
1528 },
1529 {
1530 "cell_type": "markdown",
1531 "id": "e4e92d8d-24ee-44d3-b8b6-1e6ddc382119",
1532 "metadata": {},
1533 "source": [
1534 "## Read scoring_ntuple2: features of the particles that exit (towards any direction) the radiator crystal"
1535 ]
1536 },
1537 {
1538 "cell_type": "code",
1539 "execution_count": null,
1540 "id": "95150758-427a-4b05-b566-4fa9e282520b",
1541 "metadata": {
1542 "tags": []
1543 },
1544 "outputs": [],
1545 "source": [
1546 "analyze_scoring_ntuple2 = True\n",
1547 "\n",
1548 "if analyze_scoring_ntuple2:\n",
1549 " df2 = rf['scoring_ntuple2'].arrays(library='pd')\n",
1550 " df2['p'] = np.sqrt(df2['px']**2+df2['py']**2+df2['pz']**2)\n",
1551 " #df2.describe()"
1552 ]
1553 },
1554 {
1555 "cell_type": "code",
1556 "execution_count": null,
1557 "id": "f24917dd-72b6-49e8-8f50-95c15d645f8e",
1558 "metadata": {
1559 "tags": []
1560 },
1561 "outputs": [],
1562 "source": [
1563 "part_sel = 'gamma'\n",
1564 "p_low = 0 #MeV/c\n",
1565 "p_high = 100 #MeV/c\n",
1566 "\n",
1567 "if analyze_scoring_ntuple2:\n",
1568 " if len(df2) > 0:\n",
1569 " df2_sel = df2[(df2.particle == part_sel)].copy()\n",
1570 " df2_sel = df2_sel[(df2_sel.p >= p_low) & (df2_sel.p <= p_high)].copy()\n",
1571 " #df2_sel.describe()"
1572 ]
1573 },
1574 {
1575 "cell_type": "code",
1576 "execution_count": null,
1577 "id": "94034573-57ae-479a-a332-20fcf908b900",
1578 "metadata": {},
1579 "outputs": [],
1580 "source": [
1581 "if analyze_scoring_ntuple2 and len(df2) > 0:\n",
1582 " %matplotlib ipympl\n",
1583 "\n",
1584 " plt.figure(figsize=(10, 10))\n",
1585 " Npoint = 10000\n",
1586 " fs = 18\n",
1587 "\n",
1588 " ax3D = plt.axes(projection=\"3d\")\n",
1589 " scatt = ax3D.scatter3D(df2_sel.z[:Npoint], df_sel2.x[:Npoint], df2_sel.y[:Npoint], c=df2_sel.p[:Npoint], \\\n",
1590 " alpha=0.7, marker='.', cmap=plt.get_cmap('hsv'))\n",
1591 " cbar = fig.colorbar(scatt, ax=ax3D, shrink=0.5, aspect=5)\n",
1592 " cbar.set_label(\"p (MeV/c)\", rotation=90, labelpad=16, fontsize=fs)\n",
1593 " ax3D.set_xlabel(\"z (mm)\", fontsize=fs)\n",
1594 " ax3D.set_ylabel(\"x (mm)\", fontsize=fs)\n",
1595 " ax3D.set_zlabel(\"y (mm)\", fontsize=fs)\n",
1596 " ax3D.xaxis.set_inverted(True)\n",
1597 "\n",
1598 " elev = None\n",
1599 " azim = 120\n",
1600 " roll = None\n",
1601 " #ax3D.view_init(elev, azim, roll)\n",
1602 "\n",
1603 " if saveFigs:\n",
1604 " plt.savefig(outpath + '3Ddistrib_' + purename + '.jpg')\n",
1605 " plt.show() "
1606 ]
1607 },
1608 {
1609 "cell_type": "code",
1610 "execution_count": null,
1611 "id": "3c22a840-2fb2-4a95-aafe-dea4a9dce6d7",
1612 "metadata": {},
1613 "outputs": [],
1614 "source": []
1615 }
1616 ],
1617 "metadata": {
1618 "kernelspec": {
1619 "display_name": "Python 3 (ipykernel)",
1620 "language": "python",
1621 "name": "python3"
1622 },
1623 "language_info": {
1624 "codemirror_mode": {
1625 "name": "ipython",
1626 "version": 3
1627 },
1628 "file_extension": ".py",
1629 "mimetype": "text/x-python",
1630 "name": "python",
1631 "nbconvert_exporter": "python",
1632 "pygments_lexer": "ipython3",
1633 "version": "3.12.9"
1634 }
1635 },
1636 "nbformat": 4,
1637 "nbformat_minor": 5
1638 }