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
« 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
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)
13class BoolOperation(Enum):
14 """Enum representing boolean operations used in Fluka zones."""
16 INTERSECTION = 1
17 SUBTRACTION = 2
20@dataclass(frozen=False)
21class FlukaRegion:
22 """Dataclass mapping for Fluka regions."""
24 name: str = ""
25 figures_operators: list[list[tuple[BoolOperation, str]]] = field(
26 default_factory=lambda: []
27 )
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
54 return regions, [world_figure, world_boundary]
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)
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"
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 )
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))
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 )
98 return world_region, boundary_region, fluka_world_figure, fluka_world_boundary
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)
129 return region