ebc118ffc54c048654027309d2991f206a23b28d
[oam.git] / code / network-generator / model / python / tower.py
1 # Copyright 2023 highstreet technologies GmbH
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 #!/usr/bin/python
16
17 """
18 A Class representing a Tower to mount O-RAN RUs
19 It can be interpreted as 'resource pool' for physical network
20 functions.
21 """
22 from model.python.o_ran_object import IORanObject
23 from model.python.o_ran_ru import IORanRu, ORanRu
24 import model.python.hexagon as Hexagon
25 from model.python.point import Point
26 from model.python.geo_location import GeoLocation
27 from model.python.o_ran_node import ORanNode
28 import xml.etree.ElementTree as ET
29
30 # Define the "IORanDu" interface
31 class ITower(IORanObject):
32     def __init__(self, o_ran_ru_count: int, **kwargs):
33         super().__init__(**kwargs)
34         self._o_ran_ru_count = o_ran_ru_count
35
36 # Implement a concrete O-RAN Node class
37 class Tower(ORanNode):
38
39     def __init__(self, tower_data: ITower = None, **kwargs):
40         super().__init__(tower_data, **kwargs)
41         self._o_ran_ru_count = tower_data["oRanRuCount"] if tower_data and "oRanRuCount" in tower_data else 3
42         self._o_ran_rus: list[ORanRu] = self._create_o_ran_rus()
43
44     def _create_o_ran_rus(self) -> list [ORanRu]:
45         result : list [ORanRu] = []
46         for index in range(self._o_ran_ru_count):
47             s: str = "00" + str(index)
48             name: str = "-".join(
49                 [self.name.replace("Tower", "RU"), s[len(s) - 2 : len(s)]]
50             )
51             cell_count: int = self.parent.parent.parent.parent.parent.configuration()['pattern']["o-ran-ru"]["nr-cell-du-count"]
52             result.append(
53                 ORanRu(
54                     {
55                         "name": name,
56                         "geoLocation": self.geoLocation,
57                         "position": self.position,
58                         "layout": self.layout,
59                         "spiralRadiusProfile": self.spiralRadiusProfile,
60                         "parent": self,
61                         "cellCount": cell_count
62                     }
63                 )
64             )
65         return result
66
67     def toKml(self) -> ET.Element:
68         placemark: ET.Element = ET.Element("Placemark")
69         name: ET.Element = ET.SubElement(placemark, "name")
70         name.text = self.name
71         style: ET.Element = ET.SubElement(placemark, "styleUrl")
72         style.text = "#" + self.__class__.__name__
73         multi_geometry: ET.Element = ET.SubElement(placemark, "MultiGeometry")
74         polygon: ET.Element = ET.SubElement(multi_geometry, "Polygon")
75         outer_boundary: ET.Element = ET.SubElement(polygon, "outerBoundaryIs")
76         linear_ring: ET.Element = ET.SubElement(outer_boundary, "LinearRing")
77         coordinates: ET.Element = ET.SubElement(linear_ring, "coordinates")
78
79         points: list[Point] = Hexagon.polygon_corners(self.layout, self.position)
80         points.append(points[0])
81         method = GeoLocation(
82             self.parent.parent.parent.parent.geoLocation
83         ).point_to_geo_location
84         geo_locations: list[GeoLocation] = list(map(method, points))
85         text: list[str] = []
86         for geo_location in geo_locations:
87             text.append(
88                 f"{geo_location.longitude},{geo_location.latitude},{geo_location.aboveMeanSeaLevel}"
89             )
90         coordinates.text = " ".join(text)
91
92         # cells
93         cell_angle = self.parent.parent.parent.parent.parent.configuration()["pattern"]["nr-cell-du"]["cell-angle"]
94         for index in range(int(360 / cell_angle)):
95             line: ET.Element = ET.SubElement(multi_geometry, "LineString")
96             tessellate: ET.Element = ET.SubElement(line, "tessellate")
97             tessellate.text = "1"
98             coordinates: ET.Element = ET.SubElement(line, "coordinates")
99
100             intersect: Point = Point(
101                 (points[2 * index+2].x + points[2 * index + 1].x) / 2,
102                 (points[2 * index+2].y + points[2 * index + 1].y) / 2,
103             )
104             intersect_geo_location: GeoLocation = GeoLocation(
105                 self.parent.parent.parent.parent.geoLocation
106             ).point_to_geo_location(intersect)
107             text: list[str] = []
108             text.append(
109                 f"{intersect_geo_location.longitude},{intersect_geo_location.latitude},{intersect_geo_location.aboveMeanSeaLevel}"
110             )
111             text.append(
112                 f"{self.geoLocation['longitude']},{self.geoLocation['latitude']},{self.geoLocation['aboveMeanSeaLevel']}"
113             )
114             coordinates.text = " ".join(text)
115
116         return placemark
117
118     def toSvg(self) -> None:
119         return None