Skip to content

Commit

Permalink
Add photoionization plugins (#52)
Browse files Browse the repository at this point in the history
* Add general structure

* Add photo ionization electrons plugin

* update contexts, rename things, merger plugins

* Update README.md

* Add Logger for delayed electron simulations

* Add delayed electrons tests

* Add MicrophysicsSummaryMerger

* Always save photo_ionization_electrons

* Update PI tests

* Use base plugin for delayed electrons

* Scale the PI strength

* Code speedup

* Get PI from xedocs

* update PeakTruth

* Add test for delayed_s1_photons

* Disable electron lifetime for delayed electrons.

* Get PI delay times from truncated exponential distribution

* exclude PI photons from contributing to raw_area

* Add number of PI photons in peak

* Take PI settings from config file

* Add documentation page for PhotoIonizationElectrons

* Add delayed electrons plugins to documentation

---------

Co-authored-by: Dacheng Xu <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Diego Ramírez García <[email protected]>
  • Loading branch information
4 people authored Apr 11, 2024
1 parent 10606a9 commit 8d4154d
Show file tree
Hide file tree
Showing 21 changed files with 768 additions and 42 deletions.
6 changes: 3 additions & 3 deletions docs/source/build_plugin_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,9 @@ def build_all_pages():
plugin = st._get_plugins(targets=(target,), run_id="00000")[target]

class_string = str(plugin.__class__)
file_path = os.path.join(
this_dir, class_string.split(".")[2], *class_string.split(".")[4:]
)[:-2]
path_components = class_string.split(".")
del path_components[-2] # remove the file name
file_path = os.path.join(this_dir, *path_components[2:])[:-2]

documentation = create_plugin_documentation_text(st, plugin)

Expand Down
9 changes: 7 additions & 2 deletions docs/source/detector_physics.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Detector Physics Simulation
===========================

The detectorphysics simulation is performed in 8 plugins. These are listed below.
The detectorphysics simulation is performed in multiple plugins. They are listed below.

.. toctree::
:maxdepth: 1
Expand All @@ -14,7 +14,12 @@ The detectorphysics simulation is performed in 8 plugins. These are listed below
plugins/detector_physics/ElectronTiming
plugins/detector_physics/SecondaryScintillation
plugins/detector_physics/S2PhotonPropagation
plugins/detector_physics/Delayed_Electrons
plugins/detector_physics/delayed_electrons/PhotoIonizationElectrons
plugins/detector_physics/delayed_electrons/DelayedElectronsDrift
plugins/detector_physics/delayed_electrons/DelayedElectronsExtraction
plugins/detector_physics/delayed_electrons/DelayedElectronsTiming
plugins/detector_physics/delayed_electrons/DelayedElectronsSecondaryScintillation


.. image:: figures/DetectorPhysicsStructure.pdf
:width: 600
Expand Down
Binary file modified docs/source/figures/DetectorPhysicsStructure.pdf
Binary file not shown.
Binary file modified docs/source/figures/fuse_simulation_chain.pdf
Binary file not shown.
Binary file modified docs/source/figures/fuse_simulation_chain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 34 additions & 2 deletions fuse/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,27 @@
fuse.detector_physics.S2PhotonPropagation,
]

# Plugins to simulate delayed electrons
delayed_electron_simulation_plugins = [
fuse.detector_physics.delayed_electrons.PhotoIonizationElectrons,
fuse.detector_physics.delayed_electrons.DelayedElectronsDrift,
fuse.detector_physics.delayed_electrons.DelayedElectronsExtraction,
fuse.detector_physics.delayed_electrons.DelayedElectronsTiming,
fuse.detector_physics.delayed_electrons.DelayedElectronsSecondaryScintillation,
fuse.detector_physics.delayed_electrons.S1PhotonHitsEmpty,
]

# Plugins to merge delayed and regular electrons
delayed_electron_merger_plugins = [
fuse.detector_physics.delayed_electrons.DriftedElectronsMerger,
fuse.detector_physics.delayed_electrons.ExtractedElectronsMerger,
fuse.detector_physics.delayed_electrons.ElectronTimingMerger,
fuse.detector_physics.delayed_electrons.SecondaryScintillationPhotonsMerger,
fuse.detector_physics.delayed_electrons.SecondaryScintillationPhotonSumMerger,
fuse.detector_physics.delayed_electrons.MicrophysicsSummaryMerger,
fuse.detector_physics.delayed_electrons.S1PhotonHitsMerger,
]

# Plugins to simulate PMTs and DAQ
pmt_and_daq_plugins = [
fuse.pmt_and_daq.PMTAfterPulses,
Expand Down Expand Up @@ -138,6 +159,14 @@ def full_chain_context(
for plugin in s2_simulation_plugins:
st.register(plugin)

# Register delayed Electrons plugins
for plugin in delayed_electron_simulation_plugins:
st.register(plugin)

# Register merger plugins.
for plugin in delayed_electron_merger_plugins:
st.register(plugin)

# Register PMT and DAQ plugins
for plugin in pmt_and_daq_plugins:
st.register(plugin)
Expand Down Expand Up @@ -183,10 +212,13 @@ def set_simulation_config_file(context, config_file_name):
for option_key, option in plugin.takes_config.items():
if isinstance(option.default, str) and "SIMULATION_CONFIG_FILE.json" in option.default:
context.config[option_key] = option.default.replace(
"SIMULATION_CONFIG_FILE.json",
config_file_name,
"SIMULATION_CONFIG_FILE.json", config_file_name
)

# Special case for the photoionization_modifier
if option_key == "photoionization_modifier":
context.config[option_key] = option.default


@URLConfig.register("pattern_map")
def pattern_map(map_data, pmt_mask, method="WeightedNearestNeighbors"):
Expand Down
4 changes: 2 additions & 2 deletions fuse/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class FuseBasePlugin(strax.Plugin):
# Forbid rechunking
rechunk_on_save = False

# Lets wait 10 minutes for the plugin to finish
input_timeout = 600
# Lets wait 15 minutes for the plugin to finish.. PI takes a while to run
input_timeout = 900

# Config options
debug = straxen.URLConfig(
Expand Down
3 changes: 3 additions & 0 deletions fuse/plugins/detector_physics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@

from . import csv_input
from .csv_input import *

from . import delayed_electrons
from .delayed_electrons import *
12 changes: 3 additions & 9 deletions fuse/plugins/detector_physics/csv_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,6 @@ class ChunkCsvInput(FuseBasePlugin):
(("Energy of the cluster [keV]", "ed"), np.float32),
(("NEST interaction type", "nestid"), np.int8),
(("ID of the cluster", "cluster_id"), np.int32),
(
("Time of the interaction [ns]", "t"),
np.int64,
), # Remove them later as they are not in the usual micropyhsics summary
(
("Geant4 event ID", "eventid"),
np.int32,
), # Remove them later as they are not in the usual micropyhsics summary
]
dtype = dtype + strax.time_fields

Expand Down Expand Up @@ -96,11 +88,13 @@ def compute(self):
try:
chunk_data, chunk_left, chunk_right, source_done = next(self.file_reader_iterator)
chunk_data["endtime"] = chunk_data["time"]
data = np.zeros(len(chunk_data), dtype=self.dtype)
strax.copy_to_buffer(chunk_data, data, "_bring_data_into_correct_format")

self.source_done = source_done

return self.chunk(
start=chunk_left, end=chunk_right, data=chunk_data, data_type="geant4_interactions"
start=chunk_left, end=chunk_right, data=data, data_type="geant4_interactions"
)

except StopIteration:
Expand Down
20 changes: 20 additions & 0 deletions fuse/plugins/detector_physics/delayed_electrons/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from . import delayed_electrons_drift
from .delayed_electrons_drift import *

from . import delayed_electrons_extraction
from .delayed_electrons_extraction import *

from . import delayed_electrons_timing
from .delayed_electrons_timing import *

from . import delayed_electrons_secondary_scintillation
from .delayed_electrons_secondary_scintillation import *

from . import photo_ionization_electrons
from .photo_ionization_electrons import *

from . import delayed_electrons_merger
from .delayed_electrons_merger import *

from . import delayed_electrons_s1photonhits
from .delayed_electrons_s1photonhits import *
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import strax
import straxen
import logging
from ..electron_drift import ElectronDrift

export, __all__ = strax.exporter()

logging.basicConfig(handlers=[logging.StreamHandler()])
log = logging.getLogger("fuse.detector_physics.delayed_electrons.delayed_electrons_drift")


@export
class DelayedElectronsDrift(ElectronDrift):
"""This class is used to simulate the drift of electrons from the sources
of electron afterpulses."""

__version__ = "0.0.2"

child_plugin = True

depends_on = "photo_ionization_electrons"
provides = "drifted_delayed_electrons"
data_kind = "delayed_interactions_in_roi"

electron_lifetime_liquid_delayed_electrons = straxen.URLConfig(
default=0,
track=True,
type=(int, float),
child_option=True,
parent_option_name="electron_lifetime_liquid",
help="Electron lifetime in liquid xenon [ns] for delayed electrons",
)

def compute(self, delayed_interactions_in_roi):
return super().compute(interactions_in_roi=delayed_interactions_in_roi)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import strax
import logging
from ..electron_extraction import ElectronExtraction

export, __all__ = strax.exporter()

logging.basicConfig(handlers=[logging.StreamHandler()])
log = logging.getLogger("fuse.detector_physics.delayed_electrons.delayed_electrons_extraction")


@export
class DelayedElectronsExtraction(ElectronExtraction):
"""This class is used to simulate the extraction of electrons from the
sources of electron afterpulses."""

__version__ = "0.0.1"

child_plugin = True

depends_on = ("photo_ionization_electrons", "drifted_delayed_electrons")
provides = "extracted_delayed_electrons"
data_kind = "delayed_interactions_in_roi"

def compute(self, delayed_interactions_in_roi):
return super().compute(interactions_in_roi=delayed_interactions_in_roi)
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import strax

from ....vertical_merger_plugin import VerticalMergerPlugin

export, __all__ = strax.exporter()


@export
class DriftedElectronsMerger(VerticalMergerPlugin):
"""Plugin which concatenates the output of the regular and delayed electron
drift plugins."""

depends_on = ("drifted_electrons", "drifted_delayed_electrons")

provides = "merged_drifted_electrons"
data_kind = "interactions_in_roi"
__version__ = "0.0.1"


@export
class ExtractedElectronsMerger(VerticalMergerPlugin):
"""Plugin which concatenates the output of the regular and delayed electron
extraction plugins."""

depends_on = ("extracted_electrons", "extracted_delayed_electrons")

provides = "merged_extracted_electrons"
data_kind = "interactions_in_roi"
__version__ = "0.0.1"


@export
class SecondaryScintillationPhotonsMerger(VerticalMergerPlugin):
"""Plugin which concatenates the output of the regular and delayed electron
secondary scintillation plugins."""

depends_on = ("s2_photons", "delayed_electrons_s2_photons")

provides = "merged_s2_photons"
data_kind = "individual_electrons"
__version__ = "0.0.1"


@export
class SecondaryScintillationPhotonSumMerger(VerticalMergerPlugin):
"""Plugin which concatenates the output of the regular and delayed electron
secondary scintillation plugins."""

depends_on = ("s2_photons_sum", "delayed_electrons_s2_photons_sum")

provides = "merged_s2_photons_sum"
data_kind = "interactions_in_roi"
__version__ = "0.0.1"


@export
class ElectronTimingMerger(VerticalMergerPlugin):
"""Plugin which concatenates the output of the regular and delayed electron
timing plugins."""

depends_on = ("electron_time", "delayed_electrons_time")

provides = "merged_electron_time"
data_kind = "individual_electrons"
__version__ = "0.0.1"


@export
class MicrophysicsSummaryMerger(VerticalMergerPlugin):
"""Plugin which concatenates the output of the regular and delayed electron
secondary scintillation plugins."""

depends_on = ("microphysics_summary", "photo_ionization_electrons")

provides = "merged_microphysics_summary"
data_kind = "interactions_in_roi"
__version__ = "0.0.1"


@export
class S1PhotonHitsMerger(VerticalMergerPlugin):
"""Plugin which concatenates the output of the regular and delayed s1
photon hits plugins."""

depends_on = ("s1_photons", "delayed_s1_photons")

provides = "merged_s1_photons"
data_kind = "interactions_in_roi"
__version__ = "0.0.1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import strax
import logging
import numpy as np

from ....plugin import FuseBasePlugin

export, __all__ = strax.exporter()

logging.basicConfig(handlers=[logging.StreamHandler()])
log = logging.getLogger("fuse.detector_physics.delayed_electrons.delayed_electrons_s1photonhits")


@export
class S1PhotonHitsEmpty(FuseBasePlugin):
"""Plugin to return zeros for all S1 photon hits of delayed electrons."""

__version__ = "0.0.1"

depends_on = "photo_ionization_electrons"
provides = "delayed_s1_photons"
data_kind = "delayed_interactions_in_roi"

dtype = [
(("Number detected S1 photons", "n_s1_photon_hits"), np.int32),
]
dtype = dtype + strax.time_fields

def compute(self, delayed_interactions_in_roi):
result = np.zeros(len(delayed_interactions_in_roi), dtype=self.dtype)
result["time"] = delayed_interactions_in_roi["time"]
result["endtime"] = delayed_interactions_in_roi["endtime"]
return result
Loading

0 comments on commit 8d4154d

Please sign in to comment.