Skip to content

Commit ce91d08

Browse files
committed
doc FF
1 parent 9a15833 commit ce91d08

1 file changed

Lines changed: 105 additions & 0 deletions

File tree

docs/source/user_guide/user_guide_reference_actors.rst

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,4 +1027,109 @@ Reference
10271027

10281028
.. autoclass:: opengate.actors.biasingactors.BremsstrahlungSplittingActor
10291029

1030+
Free Flight Actors
1031+
------------------
10301032

1033+
Description
1034+
~~~~~~~~~~~
1035+
1036+
Free Flight is a variance reduction technique designed to accelerate simulations, particularly in SPECT imaging, by replacing stochastic particle transport with analytical probability calculations[cite: 248]. Instead of tracking a photon step-by-step through a collimator or SPECT head, these actors analytically "project" the probability of a photon reaching a target volume (like a detector plane) without interaction. See paper [Sarrut et al, PMB, 2026, to appear].
1037+
1038+
1039+
OpenGATE provides two main actors for this purpose:
1040+
1041+
* **GammaFreeFlightActor**: Primarily used for "primary" photons (unscattered) or those originating directly from the source.
1042+
* **ScatterSplittingFreeFlightActor**: Used to handle photons that undergo Compton or Rayleigh scattering within a volume, such as a patient phantom.
1043+
1044+
GammaFreeFlightActor
1045+
~~~~~~~~~~~~~~~~~~~~
1046+
1047+
This actor is typically attached to the world or a specific phantom volume. It ensures that photons directed towards the detector are accounted for analytically[cite: 249]. It is often used in conjunction with **Forced Direction** or **Angular Acceptance** source settings to focus the simulation on the detector's field of view.
1048+
1049+
.. code-block:: python
1050+
1051+
# Add the actor to the simulation
1052+
ff = sim.add_actor("GammaFreeFlightActor", "ff")
1053+
ff.attached_to = "world"
1054+
1055+
# Optionally exclude specific volumes like the detector crystal
1056+
# to let standard Geant4 tracking take over once the particle reaches the detector.
1057+
ff.exclude_volumes = ["spect_1_crystal"]
1058+
1059+
1060+
1061+
ScatterSplittingFreeFlightActor
1062+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1063+
1064+
The ``ScatterSplittingFreeFlightActor`` handles the calculation of scattered radiation contributions. When a photon interacts, this actor "splits" the interaction into multiple analytical paths directed toward the detector, weighted by the physics of the interaction (e.g., Klein-Nishina cross-section).
1065+
1066+
* **compton_splitting_factor / rayleigh_splitting_factor**: Defines how many analytical photons are generated per interaction.
1067+
* **kill_interacting_in_volumes**: Volumes where the original interacting particle should be stopped to avoid double counting.
1068+
* **angular_acceptance**: Filters the analytical scattered photons to only those heading toward the detector.
1069+
1070+
.. code-block:: python
1071+
1072+
ff_sc = sim.add_actor("ScatterSplittingFreeFlightActor", "ff_scatter")
1073+
ff_sc.attached_to = "world"
1074+
ff_sc.exclude_volumes = ["spect_1_crystal"]
1075+
ff_sc.kill_interacting_in_volumes = ["spect_1_crystal"]
1076+
1077+
# Splitting configuration
1078+
ff_sc.compton_splitting_factor = 50
1079+
ff_sc.rayleigh_splitting_factor = 50
1080+
1081+
# Direct scattered photons only towards the SPECT head
1082+
ff_sc.angular_acceptance.policy = "Rejection"
1083+
ff_sc.angular_acceptance.target_volumes = ["spect_1"]
1084+
ff_sc.angular_acceptance.angle_tolerance_max = 10 * gate.g4_units.deg
1085+
1086+
1087+
1088+
Merging and Uncertainty Calculation
1089+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1090+
1091+
Because Free Flight separates simulations into primary and scatter components, results must be merged offline. To obtain a statistically sound result, one must sum the mean counts per event from each step and propagate the variance.
1092+
1093+
The helper function ``merge_freeflight_uncertainty`` automates this by processing the ``counts.mhd`` and ``squared_counts.mhd`` files from each subfolder (e.g., primary, scatter).
1094+
1095+
**Statistical Equations:**
1096+
1097+
* Let $C_i$ be the raw counts and $C2_i$ the squared counts for step $i$ with $N_i$ events.
1098+
* Mean per event: $E[X_i] = C_i / N_i$.
1099+
* Variance of the mean: $Var(E[X_i]) = (E[X_i^2] - (E[X_i])^2) / (N_i - 1)$.
1100+
* Total Mean: $E[X_{total}] = \sum E[X_i]$.
1101+
* Final Relative Uncertainty: $R = \frac{\sqrt{\sum Var(E[X_i])}}{E[X_{total}]}$.
1102+
1103+
**Usage of Helpers:**
1104+
1105+
.. code-block:: python
1106+
1107+
from opengate.contrib.spect.spect_freeflight_helpers import merge_freeflight_uncertainty
1108+
from pathlib import Path
1109+
1110+
# Define parameters
1111+
folder = Path("./output_simu")
1112+
ref_n = 1e8 # Target reference number of events
1113+
subfolders = ["primary", "scatter"]
1114+
num_events = [1e6, 2e5] # Number of simulated events in each subfolder
1115+
1116+
# Merge images and calculate uncertainty for head 0
1117+
merge_freeflight_uncertainty(
1118+
folder,
1119+
ref_n,
1120+
subfolders,
1121+
num_events,
1122+
counts_filename="projection_0_counts.mhd",
1123+
squared_counts_filename="projection_0_squared_counts.mhd",
1124+
output_filename="relative_uncertainty_0.mhd"
1125+
)
1126+
1127+
1128+
1129+
Reference
1130+
~~~~~~~~~
1131+
1132+
.. autoclass:: opengate.actors.freeflightactors.GammaFreeFlightActor
1133+
.. autoclass:: opengate.actors.freeflightactors.ScatterSplittingFreeFlightActor
1134+
1135+
.. autofunction:: opengate.contrib.spect.spect_freeflight_helpers.merge_freeflight_uncertainty

0 commit comments

Comments
 (0)