Files
pg-rad/src/pg_rad/simulator/engine.py
2026-05-03 17:29:53 +02:00

99 lines
2.9 KiB
Python

from typing import List
from pg_rad.landscape.landscape import Landscape
from pg_rad.simulator.outputs import (
CountRateOutput,
DetectorOutput,
SimulationOutput,
SourceOutput
)
from pg_rad.physics.fluence import calculate_counts_along_path
from pg_rad.utils.projection import minimal_distance_to_path
from pg_rad.inputparser.specs import RuntimeSpec, SimulationOptionsSpec
class SimulationEngine:
"""Takes a fully built landscape and produces results."""
def __init__(
self,
landscape: Landscape,
runtime_spec: RuntimeSpec,
sim_spec: SimulationOptionsSpec,
):
self.landscape = landscape
self.detector = self.landscape.detector
self.runtime_spec = runtime_spec
self.sim_spec = sim_spec
def simulate(self) -> SimulationOutput:
"""Compute everything and return structured output."""
count_rate_results = self._calculate_count_rate_along_path()
source_results = self._calculate_point_source_distance_to_path()
detector_results = self._generate_detector_output()
return SimulationOutput(
name=self.landscape.name,
size=self.landscape.size,
count_rate=count_rate_results,
detector=detector_results,
sources=source_results
)
def _calculate_count_rate_along_path(self) -> CountRateOutput:
acq_points, sub_points, cps, int_counts, mean_bkg_counts = (
calculate_counts_along_path(
self.landscape,
self.detector,
velocity=self.runtime_spec.speed,
bkg_cps_input=self.sim_spec.bkg_cps,
seed=self.sim_spec.seed
)
)
return CountRateOutput(
self.landscape.path.x_list,
self.landscape.path.y_list,
acq_points,
sub_points,
cps,
int_counts,
mean_bkg_counts,
self.sim_spec.seed
)
def _calculate_point_source_distance_to_path(self) -> List[SourceOutput]:
path = self.landscape.path
source_output = []
for s in self.landscape.point_sources:
dist_to_path = minimal_distance_to_path(
path.x_list,
path.y_list,
path.z,
s.pos)
source_output.append(
SourceOutput(
s.name,
s.isotope.name,
s.isotope.E,
s.activity,
s.pos,
dist_to_path)
)
return source_output
def _generate_detector_output(self) -> DetectorOutput:
return DetectorOutput(
name=self.detector.name,
type=self.detector.type,
is_isotropic=self.detector.is_isotropic,
field_eff=self.detector.get_efficiency(
self.landscape.point_sources[0].isotope.E
)
)