Coverage for yaptide/converter/converter/fluka/helper_parsers/region_parser.py: 96%

53 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-07-01 12:55 +0000

1import copy 

2from dataclasses import dataclass, field 

3from enum import Enum 

4 

5from converter import solid_figures 

6from converter.fluka.helper_parsers.figure_parser import ( 

7 FlukaFigure, 

8 get_figure_name_by_uuid, 

9 parse_fluka_figure, 

10) 

11 

12 

13class BoolOperation(Enum): 

14 """Enum representing boolean operations used in Fluka zones.""" 

15 

16 INTERSECTION = 1 

17 SUBTRACTION = 2 

18 

19 

20@dataclass(frozen=False) 

21class FlukaRegion: 

22 """Dataclass mapping for Fluka regions.""" 

23 

24 name: str = "" 

25 figures_operators: list[list[tuple[BoolOperation, str]]] = field( 

26 default_factory=lambda: [] 

27 ) 

28 

29 

30def parse_regions( 

31 zones_json: dict, figures: list[FlukaFigure] 

32) -> (list[FlukaRegion], list[FlukaFigure]): 

33 """ 

34 Parse zones from JSON to Fluka regions. 

35 Returns list of regions and list of additional figures generated by parsing world zone. 

36 """ 

37 # Naming is different in Fluka - Fluka zones consist of figures joined by subtractions and intersections 

38 # Fluka regions consist of zones joined by unions 

39 # uuid -> FlukaRegion 

40 regions = {} 

41 zone_name = "region{}" 

42 for idx, zone in enumerate(zones_json["zones"]): 

43 regions[zone["uuid"]] = FlukaRegion( 

44 name=zone_name.format(idx), 

45 figures_operators=parse_csg_operations(zone["unionOperations"], figures), 

46 ) 

47 if "worldZone" in zones_json: 

48 world_region, boundary_region, world_figure, world_boundary = parse_world_zone( 

49 zones_json, figures 

50 ) 

51 regions[zones_json["worldZone"]["uuid"]] = world_region 

52 regions[zones_json["worldZone"]["uuid"] + "boundary"] = boundary_region 

53 

54 return regions, [world_figure, world_boundary] 

55 

56 

57def parse_world_zone( 

58 zones_json: dict, figures: list[FlukaFigure] 

59) -> (FlukaRegion, FlukaFigure, FlukaFigure): 

60 """ 

61 Parse the world zone. 

62 Returns tuple consisting of world region, boundary region and the two figures of which they consist. 

63 """ 

64 # Parse the world figure, then create boundary figure by expanding it 

65 # The boundary will have the black hole material 

66 world_zone_json = zones_json["worldZone"] 

67 world_figure = solid_figures.parse_figure(world_zone_json) 

68 world_boundary = copy.deepcopy(world_figure) 

69 world_boundary.expand(10) 

70 

71 fluka_world_figure = parse_fluka_figure(world_figure) 

72 fluka_world_figure.name = "figworld" 

73 fluka_world_boundary = parse_fluka_figure(world_boundary) 

74 fluka_world_boundary.name = "figbound" 

75 

76 # The boundary region consists of boundary figure with world figure subtracted 

77 boundary_region = FlukaRegion( 

78 name="boundary", 

79 figures_operators=[ 

80 [ 

81 (BoolOperation.INTERSECTION, fluka_world_boundary.name), 

82 (BoolOperation.SUBTRACTION, fluka_world_figure.name), 

83 ] 

84 ], 

85 ) 

86 

87 # Subtract all other figures from world region 

88 world_operations = [(BoolOperation.INTERSECTION, fluka_world_figure.name)] 

89 for figure in figures: 

90 world_operations.append((BoolOperation.SUBTRACTION, figure.name)) 

91 

92 # The world region consists of world figure with all other figures subtracted 

93 world_region = FlukaRegion( 

94 name="world", 

95 figures_operators=[world_operations], 

96 ) 

97 

98 return world_region, boundary_region, fluka_world_figure, fluka_world_boundary 

99 

100 

101def parse_csg_operations( 

102 operations: list[list[dict]], figures: list[FlukaFigure] 

103) -> list[tuple[BoolOperation, str]]: 

104 """ 

105 Parse dict of csg operations to a list of lists of tuples. 

106 Each tuple consists of a figure name and intersection or subtraction operation. 

107 Each list of tuples represents a Fluka zone. 

108 The list of lists represents a Fluka region, which consists of union of all zones. 

109 """ 

110 zones_json = list(operations) 

111 region = [] 

112 for zone in zones_json: 

113 operations_list = [] 

114 for operation in zone: 

115 figure_name = get_figure_name_by_uuid(figures, operation["objectUuid"]) 

116 if figure_name is None: 

117 raise ValueError(f"Cant find figure of uuid {operation['objectUuid']}") 

118 if operation["mode"] == "union" or operation["mode"] == "intersection": 

119 # In JSON received from frontend, first figure added to each zone is marked as a union operation. 

120 # However Fluka requires each zone to contain at least one figure marked with intersection. 

121 # This doesn't change the logic, as there is no way to add another union with a figure in the UI 

122 operations_list.append((BoolOperation.INTERSECTION, figure_name)) 

123 elif operation["mode"] == "subtraction": 

124 operations_list.append((BoolOperation.SUBTRACTION, figure_name)) 

125 else: 

126 raise ValueError(f"Unexpected CSG operation: {operation['mode']}") 

127 region.append(operations_list) 

128 

129 return region