{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Detectorphysics Simulation\n", "\n", "This notebook will demonstrate the detector physics simulation as well as the simulation of PMT response and DAQ effects. This part of the XENONnT simulation chain was formerly done using the `WFSim` software.\n", "\n", "## Imports & Simulation Context\n", "\n", "Just like in the previous examples, the `Getting_Started` and `Microphysics_Simulation` notebooks, we start by importing the necessary modules and setting up the simulation context." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "import fuse" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:fuse.context:Using corrections run id: 026000\n", "INFO:fuse.context:Using clustering method: dbscan\n", "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/strax/context.py:380: UserWarning: Provides of multi-output plugins overlap, deregister old plugins .\n", " warnings.warn(\n", "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/strax/context.py:380: UserWarning: Provides of multi-output plugins overlap, deregister old plugins .\n", " warnings.warn(\n", "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/strax/context.py:380: UserWarning: Provides of multi-output plugins overlap, deregister old plugins .\n", " warnings.warn(\n", "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/strax/context.py:380: UserWarning: Provides of multi-output plugins overlap, deregister old plugins .\n", " warnings.warn(\n", "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/strax/context.py:380: UserWarning: Provides of multi-output plugins overlap, deregister old plugins .\n", " warnings.warn(\n", "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/strax/context.py:380: UserWarning: Provides of multi-output plugins overlap, deregister old plugins .\n", " warnings.warn(\n", "WARNING:fuse.context:Running without proper corrections! Please provide a corrections_version to ensure proper corrections. Example: 'global_v16'\n", "WARNING:fuse.context:elife not in context config, skipping...\n", "WARNING:fuse.context:electron_drift_velocity not in context config, skipping...\n", "WARNING:fuse.context:electron_drift_time_gate not in context config, skipping...\n", "INFO:fuse.context:Found 'mc_overrides' in config, using override-based config system.\n", "WARNING:strax:Option gain_model_nv purged from context config as it is not used.\n", "WARNING:strax:Option gain_model_mv purged from context config as it is not used.\n" ] } ], "source": [ "st = fuse.context.xenonnt_fuse_full_chain_simulation(\n", " output_folder=\"./fuse_data\",\n", " simulation_config=\"sr0_dev\",\n", ")\n", "\n", "st.set_config(\n", " {\n", " \"path\": \"/project2/lgrandi/xenonnt/simulations/testing\",\n", " \"file_name\": \"pmt_neutrons_100.root\",\n", " \"entry_stop\": 10,\n", " }\n", ")\n", "\n", "run_number = \"00000\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running the Simulation\n", "\n", "First let us start by running the microphysics simulation up to `microphysics_summary`. If you have run the `Microphysics_Simulation` notebook, the data should already be prepared and ready for use. " ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "st.make(run_number, \"microphysics_summary\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### S1 Simulation\n", "\n", "The Detectorphysics simulation of fuse splits into two branches, the simulation of S1 signals and the simulation of S2 signals. Lets start first to take a look at the S1 simulation. Two plugins are needed for this: `S1PhotonHits` and `S1PhotonPropagation`. \n", "\n", "The `S1PhotonHits` plugin simulates the number of detected photons for each interaction site in the TPC. It takes as input the number of photons at the interaction site that we simulated in the microphysics simulation.\n", "\n", "After we have the number of detected photons simulated, we can distribute these photons to the PMTs using the `S1PhotonPropagation` plugin. Additionally the timing of the photons is simulated here. As output we will get a long list of photons that we can load with the target `propagated_s1_photons`. " ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/straxen/storage/mongo_storage.py:321: DownloadWarning: Downloading XENONnT_s1_xyz_patterns_LCE_MCvf051911_wires.pkl to ./resource_cache/02ed2634596793f6e7aa13783745089a\n", " warn(f\"Downloading {config_name} to {destination_path}\", DownloadWarning)\n", "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/straxen/storage/mongo_storage.py:321: DownloadWarning: Downloading XENONnT_SR0_spe_distributions_20210713_no_noise_scaled.csv to ./resource_cache/99c2cbc580cfa8eeebe831456076e136\n", " warn(f\"Downloading {config_name} to {destination_path}\", DownloadWarning)\n", "*** Detector definition message ***\n", "You are currently using the default XENON10 template detector.\n", "\n", "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/straxen/storage/mongo_storage.py:321: DownloadWarning: Downloading XENONnT_s1_proponly_pc_reflection_optPhot_perPMT_S1_local_20220510.json.gz to ./resource_cache/91f4a6162d5e335c4416165349222061\n", " warn(f\"Downloading {config_name} to {destination_path}\", DownloadWarning)\n" ] } ], "source": [ "st.make(run_number, \"s1_photon_hits\")\n", "st.make(run_number, \"propagated_s1_photons\")" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "45a726afc62f488796327b10e2382f5b", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Loading propagated_s1_photons: | | 0.00 % [00:00\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
channeldpephoton_gaincluster_idphoton_typetimeendtime
032False15502307113152793691315279369
19False13568007113152793701315279370
2129False175602035113228634141322863414
367False203198533113228634151322863415
4104False131126830113228634161322863416
\n", "" ], "text/plain": [ " channel dpe photon_gain cluster_id photon_type time \\\n", "0 32 False 1550230 7 1 1315279369 \n", "1 9 False 1356800 7 1 1315279370 \n", "2 129 False 1756020 35 1 1322863414 \n", "3 67 False 2031985 33 1 1322863415 \n", "4 104 False 1311268 30 1 1322863416 \n", "\n", " endtime \n", "0 1315279369 \n", "1 1315279370 \n", "2 1322863414 \n", "3 1322863415 \n", "4 1322863416 " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "propagated_s1_photons.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### S2 Simulation\n", "\n", "Before we can distribute the photons of the S2 signals to the PMTs like we just did for the S1 signal, we need to simulate what is happening to the electrons at the interaction site. The processes are split into 5 plugins.\n", "\n", "#### Electron Drift and Extraction\n", "\n", "First we will simulate the drift of the electrons to the liquid-gas interface. The `ElectronDrift` plugin calculates how many electrons reach the interface taking into account the electron lifetime and the charge insensitive volume of the detector. Next, we simulate each individual electron's time and position in the `ElectronPropagation` plugin. The plugin takes into account diffusion and the drift field in the TPC. \n", "\n", "Next the electrons extracted into the gas phase are simulated using the `ElectronExtraction` plugin. You can load the data of these plugins now if you like, but we will first move to the next step and then combine the results afterwards. " ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "st.make(run_number, \"drifted_electrons\") # data_kind: \"interactions_in_roi\"\n", "st.make(run_number, \"electrons_at_interface\") # data_kind: \"individual_electrons\"\n", "st.make(run_number, \"extracted_electrons\") # data_kind: \"individual_electrons\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Secondary Scintillation\n", "\n", "Now that we know how many electrons are extracted into the gas phase, we can simulate the secondary scintillation. This is done using the `SecondaryScintillation` plugin. The plugin provides two outputs, the number of photons produced by each electron and the number of photons per interaction site (summing over the electrons originating from the interaction). " ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "st.make(run_number, \"s2_photons\")\n", "st.make(run_number, \"s2_photons_sum\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### S2 Photon Propagation\n", "\n", "Just like for the S1 simulation we can now distribute the S2 photons to the PMTs and calculate theirs arrival times. This is done using the `S2PhotonPropagation` plugin. The plugin provides similar output as the `S1PhotonPropagation` plugin, a long list of photons that we can access with the target `propagated_s2_photons`. As we are dealing with a lot of photons, expecially for interactions with higher energies, the S2 photon propagtion takes a little longer to run than the previous plugins. " ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "st.make(run_number, \"propagated_s2_photons\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Combining the Results\n", "\n", "Now that we have everything prepared for our S1 and S2 signals we can take a look at how we can combine these simulation results. First we can load `s2_photons_sum` along with `s1_photon_hits`, `drifted_electrons`, `extracted_electrons` and `microphysics_summary`. " ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "combined_simulation_results = st.get_df(\n", " run_number,\n", " [\n", " \"microphysics_summary\",\n", " \"s2_photons_sum\",\n", " \"s1_photon_hits\",\n", " ],\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lets take a look at some of the results we just simulated. Here you can see the evolution of the numbers through the simulation chain. Additionaly as all of these plugins have matching data types, this will be the base for the implementation of fastsim into fuse. " ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
n_s1_photon_hitssum_s2_photonsphotonselectronsed
0229334315.101432
144911676440992874.346542
23677634348165255.221275
33388089315666152.827538
44238585379174261.517601
\n", "
" ], "text/plain": [ " n_s1_photon_hits sum_s2_photons photons electrons ed\n", "0 2 293 34 31 5.101432\n", "1 449 11676 4409 928 74.346542\n", "2 367 7634 3481 652 55.221275\n", "3 338 8089 3156 661 52.827538\n", "4 423 8585 3791 742 61.517601" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "combined_simulation_results[\n", " [\n", " \"n_s1_photon_hits\",\n", " \"sum_s2_photons\",\n", " \"photons\",\n", " \"electrons\",\n", " \"ed\",\n", " ]\n", "].head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### PMT Afterpulses\n", "\n", "Now that we know at which PMTs photons the photons are arriving at we can simulate the PMT afterpulses. The `PMTAfterPulses` plugin provides a list of 'pseudo' photons that represent the afterpulse. This way the output of `PMTAfterPulses`, `S1PhotonPropagation` and `S2PhotonPropagation` can be combined and passed to the next simulation steps. The combined output can be loaded using the `PhotonSummary` plugin. " ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/straxen/storage/mongo_storage.py:321: DownloadWarning: Downloading XENONnT_pmt_afterpulse_config_018435.json.gz to ./resource_cache/a38b18cd61ca67a065a3a32d9b57c2b2\n", " warn(f\"Downloading {config_name} to {destination_path}\", DownloadWarning)\n" ] } ], "source": [ "st.make(run_number, \"pmt_afterpulses\")" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f27c4d7e18244c2b9182ba091a4a99c3", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Loading photon_summary: | | 0.00 % [00:00\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
channeldpephoton_gaincluster_idphoton_typetimeendtime
032False15502307113152793691315279369
19False13568007113152793701315279370
29False19329767213152980521315298052
319False18889707213152980661315298066
4399False-5778757213152982881315298288
\n", "" ], "text/plain": [ " channel dpe photon_gain cluster_id photon_type time \\\n", "0 32 False 1550230 7 1 1315279369 \n", "1 9 False 1356800 7 1 1315279370 \n", "2 9 False 1932976 7 2 1315298052 \n", "3 19 False 1888970 7 2 1315298066 \n", "4 399 False -577875 7 2 1315298288 \n", "\n", " endtime \n", "0 1315279369 \n", "1 1315279370 \n", "2 1315298052 \n", "3 1315298066 \n", "4 1315298288 " ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "photon_summary.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### PMT Response and DAQ Simulation\n", "\n", "Now that we have simulated the propagation of the photons to the PMTs, we can simulate the PMT response and DAQ effects. First we use the `PulseWindow` plugin to calculate the time intervals (calles `pulse_windows`) in which the PMT signals can potentially overlap since the photons arrive with time differences shorter than the length of a single photons waveform. Additionaly each photon gets an id that corresponds to the pulse window it belongs to." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "st.make(run_number, \"pulse_windows\")\n", "st.make(run_number, \"pulse_ids\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally we can make `raw_records` using the `PMTResponseAndDAQ` plugin. The plugins iterates over all `pulse_windows` and adds the PMT response of all photons in the pulse. Then the pulse is is split into fragments. These fragments are the final output of fuse: `raw_records`." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/opt/XENONnT/anaconda/envs/XENONnT_el7.sr1_wimp_unblind/lib/python3.9/site-packages/straxen/storage/mongo_storage.py:321: DownloadWarning: Downloading XENONnT_noise_tpc_only_2ms_25118.npz to ./resource_cache/e560759e28f74d5c049425c25e5ae0d5\n", " warn(f\"Downloading {config_name} to {destination_path}\", DownloadWarning)\n" ] } ], "source": [ "st.make(run_number, \"raw_records\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.20" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }