Source code for pyRadPlan.stf.generators._factory
import warnings
import logging
from typing import Union, Type
from pyRadPlan.plan import validate_pln, Plan
from ._base import StfGeneratorBase
STF_GENERATORS = {}
logger = logging.getLogger(__name__)
[docs]
def register_generator(generator_cls: Type[StfGeneratorBase]) -> None:
"""
Register a new stf generator for irradiation geometry.
Parameters
----------
generator_cls : type
A Generator class.
"""
if not issubclass(generator_cls, StfGeneratorBase):
raise ValueError("Generator must be a subclass of StfGeneratorBase.")
if generator_cls.short_name is None:
raise ValueError("Generator must have a 'short_name' attribute.")
if generator_cls.name is None:
raise ValueError("Generator must have a 'name' attribute.")
if generator_cls.possible_radiation_modes is None:
raise ValueError("Generator must have a 'possible_radiation_modes' attribute.")
generator_name = generator_cls.short_name
if generator_name in STF_GENERATORS:
warnings.warn(f"Generator '{generator_name}' is already registered.")
else:
STF_GENERATORS[generator_name] = generator_cls
[docs]
def get_available_generators(pln: Union[Plan, dict[str]]) -> dict[str, Type[StfGeneratorBase]]:
"""
Get a list of available stf generators based on the plan.
Parameters
----------
pln : Union[Plan,dict]
A Plan object.
Returns
-------
list
A list of available generators.
"""
pln = validate_pln(pln)
return {
name: cls
for name, cls in STF_GENERATORS.items()
if pln.radiation_mode in cls.possible_radiation_modes
}
[docs]
def get_generator(pln: Union[Plan, dict]) -> StfGeneratorBase:
"""
Get the appropriate generator based on the plan.
Parameters
----------
pln : Plan
A Plan object.
Returns
-------
Generator
A Dose Generator object.
"""
pln = validate_pln(pln)
# Available generators
generators = get_available_generators(pln)
if len(generators) <= 0:
raise ValueError(f"No generator available for radiation mode '{pln.radiation_mode}'.")
generator_names = list(generators.keys())
# Did the user provide an generator in the pln?
if isinstance(pln.prop_stf, StfGeneratorBase):
# The user provided an generator object, so lets use it
# but warn the user if it is not in the available generators
generator_name = pln.prop_stf.short_name
if generator_name not in generators:
warnings.warn(f"Generator '{generator_name}' seems not to be valid for Plan setup.")
return pln.prop_stf
if isinstance(pln.prop_stf, dict):
# The user provided a dictionary with generator parameters, so we need to find the generator name
if "generator" in pln.prop_stf:
if pln.prop_stf["generator"] in generators:
return generators[pln.prop_stf["generator"]](pln)
warnings.warn(f"Generator '{pln.prop_stf['generator']}' not available for Plan.")
# If no generator name was found, we choose the first as default
# TODO: Check for if field shape was provided and choose appropriate generator
logger.warning(
"No generator specified in Plan. Using first available generator %s.",
generator_names[0],
)
return generators[generator_names[0]](pln)
raise ValueError(f"No generator available for radiation mode '{pln.radiation_mode}'.")