Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Per electron simulation #264

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions fuse/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
# Plugins to simulate S2 signals
s2_simulation_plugins = [
fuse.detector_physics.ElectronDrift,
fuse.detector_physics.ElectronPropagation,
fuse.detector_physics.ElectronExtraction,
fuse.detector_physics.ElectronTiming,
fuse.detector_physics.SecondaryScintillation,
fuse.detector_physics.S2PhotonPropagation,
]
Expand All @@ -53,17 +53,17 @@
delayed_electron_simulation_plugins = [
fuse.detector_physics.delayed_electrons.PhotoIonizationElectrons,
fuse.detector_physics.delayed_electrons.DelayedElectronsDrift,
fuse.detector_physics.delayed_electrons.DelayedElectronPropagation,
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.PropagatedElectronsMerger,
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,
Expand Down
6 changes: 3 additions & 3 deletions fuse/plugins/detector_physics/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from . import electron_drift
from .electron_drift import *

from . import electron_propagation
from .electron_propagation import *

from . import electron_extraction
from .electron_extraction import *

from . import electron_timing
from .electron_timing import *

from . import s1_photon_hits
from .s1_photon_hits import *

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

from . import delayed_electrons_propagation
from .delayed_electrons_propagation 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 *

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ class DelayedElectronsExtraction(ElectronExtraction):
"""This class is used to simulate the extraction of electrons from the
sources of electron afterpulses."""

__version__ = "0.0.1"
__version__ = "0.0.2"

child_plugin = True

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

def compute(self, delayed_interactions_in_roi):
return super().compute(interactions_in_roi=delayed_interactions_in_roi)
def compute(self, delayed_individual_electrons):
return super().compute(individual_electrons=delayed_individual_electrons)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ class DriftedElectronsMerger(VerticalMergerPlugin):
__version__ = "0.0.1"


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

depends_on = ("electrons_at_interface", "delayed_electrons_at_interface")

provides = "merged_electrons_at_interface"
data_kind = "individual_electrons"
__version__ = "0.0.1"


@export
class ExtractedElectronsMerger(VerticalMergerPlugin):
"""Plugin which concatenates the output of the regular and delayed electron
Expand All @@ -25,8 +37,8 @@ class ExtractedElectronsMerger(VerticalMergerPlugin):
depends_on = ("extracted_electrons", "extracted_delayed_electrons")

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


@export
Expand All @@ -53,18 +65,6 @@ class SecondaryScintillationPhotonSumMerger(VerticalMergerPlugin):
__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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import strax
from ..electron_propagation import ElectronPropagation

export, __all__ = strax.exporter()


@export
class DelayedElectronPropagation(ElectronPropagation):
"""This class is used to simulate the propagation of electrons from the
sources of electron afterpulses."""

__version__ = "0.0.0"

child_plugin = True

depends_on = ("photo_ionization_electrons", "drifted_delayed_electrons")
provides = "delayed_electrons_at_interface"
data_kind = "delayed_individual_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
Expand Up @@ -11,7 +11,7 @@ class DelayedElectronsSecondaryScintillation(SecondaryScintillation):
"""This class is used to simulate the extraction of electrons from the
sources of electron afterpulses."""

__version__ = "0.0.1"
__version__ = "0.0.3"

child_plugin = True

Expand All @@ -21,7 +21,6 @@ class DelayedElectronsSecondaryScintillation(SecondaryScintillation):
depends_on = (
"drifted_delayed_electrons",
"extracted_delayed_electrons",
"delayed_electrons_time",
"photo_ionization_electrons",
)

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ class PhotoIonizationElectrons(FuseBasePlugin):
scaled using the config option photoionization_modifier.
"""

__version__ = "0.0.2"
__version__ = "0.0.3"

depends_on = (
"s2_photons_sum",
"extracted_electrons",
"s2_photons",
"electron_time",
"extracted_electrons",
"microphysics_summary",
)
provides = "photo_ionization_electrons"
Expand Down
60 changes: 36 additions & 24 deletions fuse/plugins/detector_physics/electron_extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@ class ElectronExtraction(FuseBasePlugin):
"""Plugin to simulate the loss of electrons during the extraction of
drifted electrons from the liquid into the gas phase."""

__version__ = "0.2.0"
__version__ = "0.3.0"

depends_on = ("microphysics_summary", "drifted_electrons")
depends_on = "electrons_at_interface"
provides = "extracted_electrons"
data_kind = "interactions_in_roi"
data_kind = "individual_electrons"

save_when = strax.SaveWhen.ALWAYS
save_when = strax.SaveWhen.TARGET

dtype = [
(("Number of electrons extracted into the gas phase", "n_electron_extracted"), np.int32),
(("x position of the electron at the interface [cm]", "x_interface"), np.float32),
(("y position of the electron at the interface [cm]", "y_interface"), np.float32),
(("ID of the cluster creating the electron", "cluster_id"), np.int32),
] + strax.time_fields

# Config options
Expand Down Expand Up @@ -86,30 +88,30 @@ class ElectronExtraction(FuseBasePlugin):
help="Map of the single electron gain",
)

def compute(self, interactions_in_roi):
# Just apply this to clusters with photons
mask = interactions_in_roi["electrons"] > 0

if len(interactions_in_roi[mask]) == 0:
empty_result = np.zeros(len(interactions_in_roi), self.dtype)
empty_result["time"] = interactions_in_roi["time"]
empty_result["endtime"] = interactions_in_roi["endtime"]
return empty_result
electron_trapping_time = straxen.URLConfig(
default="take://resource://"
"SIMULATION_CONFIG_FILE.json?&fmt=json"
"&take=electron_trapping_time",
type=(int, float),
cache=True,
help="Time scale electrons are trapped at the liquid gas interface",
)

x = interactions_in_roi[mask]["x_obs"]
y = interactions_in_roi[mask]["y_obs"]
def compute(self, individual_electrons):

xy_int = np.array([x, y]).T # maps are in R_true, so orginal position should be here
position = np.array(
[individual_electrons["x_interface"], individual_electrons["y_interface"]]
).T

if self.ext_eff_from_map:
# Extraction efficiency is g2(x,y)/SE_gain(x,y)
rel_s2_cor = self.s2_correction_map(xy_int)
rel_s2_cor = self.s2_correction_map(position)
# Doesn't always need to be flattened, but if s2_correction_map = False,
# then map is made from MC
rel_s2_cor = rel_s2_cor.flatten()

if self.se_gain_from_map:
se_gains = self.se_gain_map(xy_int)
se_gains = self.se_gain_map(position)
else:
# Is in get_s2_light_yield map is scaled according to relative s2 correction
# We also need to do it here to have consistent g2
Expand All @@ -118,11 +120,21 @@ def compute(self, interactions_in_roi):
else:
cy = self.electron_extraction_yield

n_electron = self.rng.binomial(n=interactions_in_roi[mask]["n_electron_interface"], p=cy)
extraction_mask = self.rng.binomial(1, p=cy, size=position.shape[0]).astype(bool)

result = np.zeros(len(interactions_in_roi), dtype=self.dtype)
result["n_electron_extracted"][mask] = n_electron
result["time"] = interactions_in_roi["time"]
result["endtime"] = interactions_in_roi["endtime"]
result = np.zeros(np.sum(extraction_mask), dtype=self.dtype)
result["time"] = self.extraction_delay(individual_electrons[extraction_mask]["time"])
result["endtime"] = result["time"]
result["x_interface"] = individual_electrons[extraction_mask]["x_interface"]
result["y_interface"] = individual_electrons[extraction_mask]["y_interface"]
result["cluster_id"] = individual_electrons[extraction_mask]["cluster_id"]

return result

def extraction_delay(
self,
electron_times,
):
timing = self.rng.exponential(self.electron_trapping_time, size=electron_times.shape[0])

return electron_times + timing.astype(np.int64)
Loading
Loading