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

1from dataclasses import dataclass 

2from typing import Optional, Union 

3 

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 

7 

8__supported_filter_keywords = ('A', 'Z') 

9 

10 

11@dataclass 

12class CustomFilter: 

13 """Class representing CustomFilter""" 

14 

15 name: str 

16 a: int 

17 z: int 

18 

19 

20@dataclass 

21class ParticleFilter: 

22 """Class representing ParticleFilter""" 

23 

24 name: str 

25 particle: str 

26 

27 

28@dataclass 

29class Quantity: 

30 """Class representing Quantity""" 

31 

32 name: str 

33 scoring_filter: Optional[Union[CustomFilter, ParticleFilter]] 

34 modifiers: list[any] # unused 

35 keyword: str = 'DOSE' 

36 

37 

38@dataclass 

39class Scoring: 

40 """Class representing Scorings for Fluka output""" 

41 

42 quantities: list[Quantity] 

43 detector: Union[MeshDetector, CylinderDetector] 

44 output_unit: int = 21 

45 

46 

47def get_particle_filter(filter_dict: dict) -> Optional[ParticleFilter]: 

48 """Creates ParticleFilter from dictionary. 

49 

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 

55 

56 return ParticleFilter(name=filter_dict['name'], particle=particle_dict[particle['id']]['name']) 

57 

58 

59def get_custom_filter(filter_dict: dict) -> Optional[CustomFilter]: 

60 """Creates CustomFilter from dictionary. 

61 

62 Returns empty list if filter cannot be created for Fluka. 

63 """ 

64 if not filter_dict.get('rules'): 

65 return None 

66 

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) 

79 

80 

81def get_filter(filter_dict: dict) -> Optional[Union[ParticleFilter, CustomFilter]]: 

82 """Creates filter for Fluka. 

83 

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) 

89 

90 

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 

99 

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 

108 

109 parsed_detector = parse_detector(detector) 

110 if not parsed_detector: 

111 # Skip not cartesian mesh detectors 

112 continue 

113 

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 

122 

123 quantities.append( 

124 Quantity(name=quantity['name'], 

125 keyword=quantity['keyword'], 

126 scoring_filter=scoring_filter, 

127 modifiers=quantity.get('modifiers'))) 

128 

129 scorings.append(Scoring(quantities=quantities, detector=parse_detector(detector))) 

130 

131 return scorings 

132 

133 

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) 

140 

141 return None