mirror of
https://github.com/pim-n/pg-rad
synced 2026-03-22 21:48:11 +01:00
update isotope lookup to tabular format. Add primary gamma energy to results plotting
This commit is contained in:
@ -1,3 +1,4 @@
|
|||||||
ATTENUATION_TABLE = 'attenuation_table.csv'
|
ATTENUATION_TABLE = 'attenuation_table.csv'
|
||||||
|
ISOTOPE_TABLE = 'isotopes.csv'
|
||||||
TEST_EXP_DATA = 'test_path_coords.csv'
|
TEST_EXP_DATA = 'test_path_coords.csv'
|
||||||
LOGGING_CONFIG = 'logging.yml'
|
LOGGING_CONFIG = 'logging.yml'
|
||||||
|
|||||||
6
src/pg_rad/data/isotopes.csv
Normal file
6
src/pg_rad/data/isotopes.csv
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
isotope,gamma_energy_keV,branching_ratio
|
||||||
|
Cs134,604.7,0.976
|
||||||
|
Cs134,795.9,0.855
|
||||||
|
Cs137,661.657,0.851
|
||||||
|
Co60,1173.228,1.0
|
||||||
|
Co60,1332.5,1.0
|
||||||
|
@ -11,6 +11,7 @@ from pg_rad.exceptions.exceptions import (
|
|||||||
InvalidYAMLError
|
InvalidYAMLError
|
||||||
)
|
)
|
||||||
from pg_rad.configs import defaults
|
from pg_rad.configs import defaults
|
||||||
|
from pg_rad.isotopes.isotope import get_isotope
|
||||||
|
|
||||||
from .specs import (
|
from .specs import (
|
||||||
MetadataSpec,
|
MetadataSpec,
|
||||||
@ -276,7 +277,9 @@ class ConfigParser:
|
|||||||
specs: List[PointSourceSpec] = []
|
specs: List[PointSourceSpec] = []
|
||||||
|
|
||||||
for name, params in source_dict.items():
|
for name, params in source_dict.items():
|
||||||
required = {"activity_MBq", "isotope", "position"}
|
required = {
|
||||||
|
"activity_MBq", "isotope", "position", "gamma_energy_keV"
|
||||||
|
}
|
||||||
if not isinstance(params, dict):
|
if not isinstance(params, dict):
|
||||||
raise InvalidConfigValueError(
|
raise InvalidConfigValueError(
|
||||||
f"sources.{name} is not defined correctly."
|
f"sources.{name} is not defined correctly."
|
||||||
@ -288,7 +291,10 @@ class ConfigParser:
|
|||||||
raise MissingConfigKeyError(name, missing)
|
raise MissingConfigKeyError(name, missing)
|
||||||
|
|
||||||
activity = params.get("activity_MBq")
|
activity = params.get("activity_MBq")
|
||||||
isotope = params.get("isotope")
|
isotope_name = params.get("isotope")
|
||||||
|
gamma_energy_keV = params.get("gamma_energy_keV")
|
||||||
|
|
||||||
|
isotope = get_isotope(isotope_name, gamma_energy_keV)
|
||||||
|
|
||||||
if not isinstance(activity, int | float) or activity <= 0:
|
if not isinstance(activity, int | float) or activity <= 0:
|
||||||
raise InvalidConfigValueError(
|
raise InvalidConfigValueError(
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
from typing import Dict, Type
|
from importlib.resources import files
|
||||||
|
|
||||||
|
from pandas import read_csv
|
||||||
|
|
||||||
|
from pg_rad.configs.filepaths import ISOTOPE_TABLE
|
||||||
from pg_rad.exceptions.exceptions import InvalidIsotopeError
|
from pg_rad.exceptions.exceptions import InvalidIsotopeError
|
||||||
from pg_rad.physics.attenuation import get_mass_attenuation_coeff
|
from pg_rad.physics.attenuation import get_mass_attenuation_coeff
|
||||||
|
|
||||||
@ -30,22 +33,35 @@ class Isotope:
|
|||||||
self.mu_mass_air = get_mass_attenuation_coeff(E / 1000)
|
self.mu_mass_air = get_mass_attenuation_coeff(E / 1000)
|
||||||
|
|
||||||
|
|
||||||
class CS137(Isotope):
|
def get_isotope(isotope: str, energy_gamma_keV: float) -> Isotope:
|
||||||
def __init__(self):
|
"""Lazy factory function to create isotope objects."""
|
||||||
super().__init__(
|
path = files('pg_rad.data').joinpath(ISOTOPE_TABLE)
|
||||||
name="Cs-137",
|
df = read_csv(path)
|
||||||
E=661.66,
|
|
||||||
b=0.851
|
isotope_df = df[df['isotope'] == isotope]
|
||||||
|
|
||||||
|
if isotope_df.empty:
|
||||||
|
raise InvalidIsotopeError(f"No data available for isotope {isotope}.")
|
||||||
|
|
||||||
|
tol = 0.01 * energy_gamma_keV
|
||||||
|
closest_energy = isotope_df[
|
||||||
|
(isotope_df['gamma_energy_keV'] >= energy_gamma_keV - tol) &
|
||||||
|
(isotope_df['gamma_energy_keV'] <= energy_gamma_keV + tol)
|
||||||
|
]
|
||||||
|
|
||||||
|
if closest_energy.empty:
|
||||||
|
available_gammas = ', '.join(
|
||||||
|
str(x)+' keV' for x in isotope_df['gamma_energy_keV'].to_list()
|
||||||
|
)
|
||||||
|
raise InvalidIsotopeError(
|
||||||
|
f"No gamma of {energy_gamma_keV}±{tol} keV "
|
||||||
|
f"found for isotope {isotope}. "
|
||||||
|
f"Available gammas are: {available_gammas}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
matched_row = closest_energy.iloc[0]
|
||||||
preset_isotopes: Dict[str, Type[Isotope]] = {
|
return Isotope(
|
||||||
"Cs137": CS137
|
name=isotope,
|
||||||
}
|
E=matched_row['gamma_energy_keV'],
|
||||||
|
b=matched_row['branching_ratio']
|
||||||
|
)
|
||||||
def get_isotope(isotope_str: str) -> Isotope:
|
|
||||||
"""Lazy factory function to create isotope objects."""
|
|
||||||
if isotope_str not in preset_isotopes:
|
|
||||||
raise InvalidIsotopeError(f"Unknown isotope: {isotope_str}")
|
|
||||||
return preset_isotopes[isotope_str]()
|
|
||||||
|
|||||||
@ -59,7 +59,7 @@ def main():
|
|||||||
length: 1000
|
length: 1000
|
||||||
segments:
|
segments:
|
||||||
- straight
|
- straight
|
||||||
- turn_left
|
- turn_left: 45
|
||||||
direction: negative
|
direction: negative
|
||||||
|
|
||||||
sources:
|
sources:
|
||||||
@ -67,6 +67,7 @@ def main():
|
|||||||
activity_MBq: 100
|
activity_MBq: 100
|
||||||
position: [250, 100, 0]
|
position: [250, 100, 0]
|
||||||
isotope: Cs137
|
isotope: Cs137
|
||||||
|
gamma_energy_keV: 661
|
||||||
|
|
||||||
detector:
|
detector:
|
||||||
name: dummy
|
name: dummy
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class PointSource(BaseObject):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
activity_MBq: int,
|
activity_MBq: int,
|
||||||
isotope: str,
|
isotope: Isotope,
|
||||||
position: tuple[float, float, float] = (0, 0, 0),
|
position: tuple[float, float, float] = (0, 0, 0),
|
||||||
name: str | None = None,
|
name: str | None = None,
|
||||||
color: str = 'red'
|
color: str = 'red'
|
||||||
@ -40,7 +40,7 @@ class PointSource(BaseObject):
|
|||||||
super().__init__(position, name, color)
|
super().__init__(position, name, color)
|
||||||
|
|
||||||
self.activity = activity_MBq
|
self.activity = activity_MBq
|
||||||
self.isotope: Isotope = get_isotope(isotope)
|
self.isotope = isotope
|
||||||
|
|
||||||
logger.debug(f"Source created: {self.name}")
|
logger.debug(f"Source created: {self.name}")
|
||||||
|
|
||||||
|
|||||||
@ -105,7 +105,7 @@ class ResultPlotter:
|
|||||||
data = [
|
data = [
|
||||||
[
|
[
|
||||||
s.name,
|
s.name,
|
||||||
s.isotope,
|
s.isotope+f" ({s.primary_gamma} keV)",
|
||||||
s.activity,
|
s.activity,
|
||||||
"("+", ".join(f"{val:.2f}" for val in s.position)+")",
|
"("+", ".join(f"{val:.2f}" for val in s.position)+")",
|
||||||
round(s.dist_from_path, 2)
|
round(s.dist_from_path, 2)
|
||||||
|
|||||||
@ -62,6 +62,7 @@ class SimulationEngine:
|
|||||||
SourceOutput(
|
SourceOutput(
|
||||||
s.name,
|
s.name,
|
||||||
s.isotope.name,
|
s.isotope.name,
|
||||||
|
s.isotope.E,
|
||||||
s.activity,
|
s.activity,
|
||||||
s.pos,
|
s.pos,
|
||||||
dist_to_path)
|
dist_to_path)
|
||||||
|
|||||||
@ -13,6 +13,7 @@ class CountRateOutput:
|
|||||||
class SourceOutput:
|
class SourceOutput:
|
||||||
name: str
|
name: str
|
||||||
isotope: str
|
isotope: str
|
||||||
|
primary_gamma: float
|
||||||
activity: float
|
activity: float
|
||||||
position: Tuple[float, float, float]
|
position: Tuple[float, float, float]
|
||||||
dist_from_path: float
|
dist_from_path: float
|
||||||
|
|||||||
Reference in New Issue
Block a user