Coverage for yaptide/converter/converter/fluka/helper_parsers/scoring_parser.py: 87%
79 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-07-01 12:55 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-07-01 12:55 +0000
1from dataclasses import dataclass
2from typing import Optional, Union
4from converter.fluka.helper_parsers.detector_parser import MeshDetector, parse_mesh_detector, CylinderDetector, \
5 parse_cylinder_detector
6from converter.fluka.helper_parsers.beam_parser import particle_dict
8__supported_filter_keywords = ('A', 'Z')
11@dataclass
12class CustomFilter:
13 """Class representing CustomFilter"""
15 name: str
16 a: int
17 z: int
20@dataclass
21class ParticleFilter:
22 """Class representing ParticleFilter"""
24 name: str
25 particle: str
28@dataclass
29class Quantity:
30 """Class representing Quantity"""
32 name: str
33 scoring_filter: Optional[Union[CustomFilter, ParticleFilter]]
34 modifiers: list[any] # unused
35 keyword: str = 'DOSE'
38@dataclass
39class Scoring:
40 """Class representing Scorings for Fluka output"""
42 quantities: list[Quantity]
43 detector: Union[MeshDetector, CylinderDetector]
44 output_unit: int = 21
47def get_particle_filter(filter_dict: dict) -> Optional[ParticleFilter]:
48 """Creates ParticleFilter from dictionary.
50 Returns None if filter cannot be created for Fluka.
51 """
52 particle = filter_dict['particle']
53 if particle.get('id') not in particle_dict:
54 return None
56 return ParticleFilter(name=filter_dict['name'], particle=particle_dict[particle['id']]['name'])
59def get_custom_filter(filter_dict: dict) -> Optional[CustomFilter]:
60 """Creates CustomFilter from dictionary.
62 Returns empty list if filter cannot be created for Fluka.
63 """
64 if not filter_dict.get('rules'):
65 return None
67 a = 0
68 z = 0
69 for rule in filter_dict['rules']:
70 if rule['keyword'] not in __supported_filter_keywords:
71 return None
72 if rule['operator'] not in ['equal', '==']:
73 return None
74 if rule['keyword'] == 'A':
75 a = rule['value']
76 elif rule['keyword'] == 'Z':
77 z = rule['value']
78 return CustomFilter(name=filter_dict['name'], a=a, z=z)
81def get_filter(filter_dict: dict) -> Optional[Union[ParticleFilter, CustomFilter]]:
82 """Creates filter for Fluka.
84 Returns None if filter cannot be created for Fluka.
85 """
86 if filter_dict.get('particle'):
87 return get_particle_filter(filter_dict)
88 return get_custom_filter(filter_dict)
91def parse_scorings(detectors_json: dict, scorings_json: dict) -> list[Scoring]:
92 """Creates list of Scorings from dictionaries"""
93 filters: dict[str, Union[ParticleFilter, CustomFilter]] = {}
94 for filter_dict in scorings_json['filters']:
95 # Check if supported filter, ignore otherwise
96 scoring_filter = get_filter(filter_dict)
97 if scoring_filter is not None:
98 filters[filter_dict['uuid']] = scoring_filter
100 scorings: list[Scoring] = []
101 for output in scorings_json['outputs']:
102 detector = next(
103 (detector for detector in detectors_json['detectors'] if detector['uuid'] == output['detectorUuid']), None)
104 if detector is None:
105 # Skip for not existing detector
106 # This should not happen
107 continue
109 parsed_detector = parse_detector(detector)
110 if not parsed_detector:
111 # Skip not cartesian mesh detectors
112 continue
114 quantities: list[Quantity] = []
115 for quantity in output['quantities']:
116 scoring_filter = None
117 if 'filter' in quantity:
118 scoring_filter = filters.get(quantity['filter'])
119 if scoring_filter is None:
120 # Skip for not existing filter or not supported filter
121 continue
123 quantities.append(
124 Quantity(name=quantity['name'],
125 keyword=quantity['keyword'],
126 scoring_filter=scoring_filter,
127 modifiers=quantity.get('modifiers')))
129 scorings.append(Scoring(quantities=quantities, detector=parse_detector(detector)))
131 return scorings
134def parse_detector(detector_dict: dict) -> Optional[Union[MeshDetector, CylinderDetector]]:
135 """Creates Detector from dictionary"""
136 if detector_dict['geometryData']['geometryType'] == 'Mesh':
137 return parse_mesh_detector(detector_dict)
138 if detector_dict['geometryData']['geometryType'] == 'Cyl':
139 return parse_cylinder_detector(detector_dict)
141 return None