FiberFusing 1.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of FiberFusing might be problematic. Click here for more details.

Files changed (110) hide show
  1. fiberfusing-1.3.4/FiberFusing/VERSION +1 -0
  2. fiberfusing-1.3.4/FiberFusing/__init__.py +79 -0
  3. fiberfusing-1.3.4/FiberFusing/__pycache__/__init__.cpython-311.pyc +0 -0
  4. fiberfusing-1.3.4/FiberFusing/__pycache__/background.cpython-311.pyc +0 -0
  5. fiberfusing-1.3.4/FiberFusing/__pycache__/base_fused.cpython-311.pyc +0 -0
  6. fiberfusing-1.3.4/FiberFusing/__pycache__/buffer.cpython-311.pyc +0 -0
  7. fiberfusing-1.3.4/FiberFusing/__pycache__/connection.cpython-311.pyc +0 -0
  8. fiberfusing-1.3.4/FiberFusing/__pycache__/coordinate_system.cpython-311.pyc +0 -0
  9. fiberfusing-1.3.4/FiberFusing/__pycache__/geometry.cpython-311.pyc +0 -0
  10. fiberfusing-1.3.4/FiberFusing/__pycache__/utils.cpython-311.pyc +0 -0
  11. fiberfusing-1.3.4/FiberFusing/background.py +88 -0
  12. fiberfusing-1.3.4/FiberFusing/base_fused.py +510 -0
  13. fiberfusing-1.3.4/FiberFusing/buffer.py +95 -0
  14. fiberfusing-1.3.4/FiberFusing/components/__init__.py +0 -0
  15. fiberfusing-1.3.4/FiberFusing/components/__pycache__/__init__.cpython-311.pyc +0 -0
  16. fiberfusing-1.3.4/FiberFusing/components/__pycache__/base_class.cpython-311.pyc +0 -0
  17. fiberfusing-1.3.4/FiberFusing/components/__pycache__/linestring.cpython-311.pyc +0 -0
  18. fiberfusing-1.3.4/FiberFusing/components/__pycache__/point.cpython-311.pyc +0 -0
  19. fiberfusing-1.3.4/FiberFusing/components/__pycache__/polygon.cpython-311.pyc +0 -0
  20. fiberfusing-1.3.4/FiberFusing/components/__pycache__/utils.cpython-311.pyc +0 -0
  21. fiberfusing-1.3.4/FiberFusing/components/base_class.py +161 -0
  22. fiberfusing-1.3.4/FiberFusing/components/linestring.py +117 -0
  23. fiberfusing-1.3.4/FiberFusing/components/point.py +105 -0
  24. fiberfusing-1.3.4/FiberFusing/components/polygon.py +443 -0
  25. fiberfusing-1.3.4/FiberFusing/components/utils.py +59 -0
  26. fiberfusing-1.3.4/FiberFusing/configuration/__init__.py +7 -0
  27. fiberfusing-1.3.4/FiberFusing/configuration/__pycache__/__init__.cpython-311.pyc +0 -0
  28. fiberfusing-1.3.4/FiberFusing/configuration/line/__init__.py +10 -0
  29. fiberfusing-1.3.4/FiberFusing/configuration/line/__pycache__/__init__.cpython-311.pyc +0 -0
  30. fiberfusing-1.3.4/FiberFusing/configuration/line/__pycache__/configuration_01x01.cpython-311.pyc +0 -0
  31. fiberfusing-1.3.4/FiberFusing/configuration/line/__pycache__/configuration_02x02.cpython-311.pyc +0 -0
  32. fiberfusing-1.3.4/FiberFusing/configuration/line/__pycache__/configuration_03x03.cpython-311.pyc +0 -0
  33. fiberfusing-1.3.4/FiberFusing/configuration/line/__pycache__/configuration_04x04.cpython-311.pyc +0 -0
  34. fiberfusing-1.3.4/FiberFusing/configuration/line/__pycache__/configuration_05x05.cpython-311.pyc +0 -0
  35. fiberfusing-1.3.4/FiberFusing/configuration/line/configuration_01x01.py +30 -0
  36. fiberfusing-1.3.4/FiberFusing/configuration/line/configuration_02x02.py +37 -0
  37. fiberfusing-1.3.4/FiberFusing/configuration/line/configuration_03x03.py +36 -0
  38. fiberfusing-1.3.4/FiberFusing/configuration/line/configuration_04x04.py +36 -0
  39. fiberfusing-1.3.4/FiberFusing/configuration/line/configuration_05x05.py +36 -0
  40. fiberfusing-1.3.4/FiberFusing/configuration/ring/__init__.py +15 -0
  41. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/__init__.cpython-311.pyc +0 -0
  42. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_01x01.cpython-311.pyc +0 -0
  43. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_02x02.cpython-311.pyc +0 -0
  44. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_03x03.cpython-311.pyc +0 -0
  45. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_04x04.cpython-311.pyc +0 -0
  46. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_05x05.cpython-311.pyc +0 -0
  47. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_06x06.cpython-311.pyc +0 -0
  48. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_07x07.cpython-311.pyc +0 -0
  49. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_10x10.cpython-311.pyc +0 -0
  50. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_12x12.cpython-311.pyc +0 -0
  51. fiberfusing-1.3.4/FiberFusing/configuration/ring/__pycache__/configuration_19x19.cpython-311.pyc +0 -0
  52. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_01x01.py +30 -0
  53. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_02x02.py +35 -0
  54. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_03x03.py +43 -0
  55. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_04x04.py +43 -0
  56. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_05x05.py +43 -0
  57. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_06x06.py +43 -0
  58. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_07x07.py +44 -0
  59. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_10x10.py +50 -0
  60. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_12x12.py +55 -0
  61. fiberfusing-1.3.4/FiberFusing/configuration/ring/configuration_19x19.py +57 -0
  62. fiberfusing-1.3.4/FiberFusing/configuration/ring/mode_groupe_pl_6.py +48 -0
  63. fiberfusing-1.3.4/FiberFusing/configuration/ring/scaling_photonic_lantern_10.py +56 -0
  64. fiberfusing-1.3.4/FiberFusing/connection.py +340 -0
  65. fiberfusing-1.3.4/FiberFusing/coordinate_system.py +165 -0
  66. fiberfusing-1.3.4/FiberFusing/directories.py +42 -0
  67. fiberfusing-1.3.4/FiberFusing/fiber/__init__.py +0 -0
  68. fiberfusing-1.3.4/FiberFusing/fiber/__pycache__/__init__.cpython-311.pyc +0 -0
  69. fiberfusing-1.3.4/FiberFusing/fiber/__pycache__/catalogue.cpython-311.pyc +0 -0
  70. fiberfusing-1.3.4/FiberFusing/fiber/__pycache__/generic_fiber.cpython-311.pyc +0 -0
  71. fiberfusing-1.3.4/FiberFusing/fiber/__pycache__/structure_collection.cpython-311.pyc +0 -0
  72. fiberfusing-1.3.4/FiberFusing/fiber/catalogue.py +131 -0
  73. fiberfusing-1.3.4/FiberFusing/fiber/generic_fiber.py +406 -0
  74. fiberfusing-1.3.4/FiberFusing/fiber/structure_collection.py +173 -0
  75. fiberfusing-1.3.4/FiberFusing/geometry.py +342 -0
  76. fiberfusing-1.3.4/FiberFusing/sub_structures/__init__.py +0 -0
  77. fiberfusing-1.3.4/FiberFusing/sub_structures/__pycache__/__init__.cpython-311.pyc +0 -0
  78. fiberfusing-1.3.4/FiberFusing/sub_structures/__pycache__/base_class.cpython-311.pyc +0 -0
  79. fiberfusing-1.3.4/FiberFusing/sub_structures/__pycache__/line.cpython-311.pyc +0 -0
  80. fiberfusing-1.3.4/FiberFusing/sub_structures/__pycache__/ring.cpython-311.pyc +0 -0
  81. fiberfusing-1.3.4/FiberFusing/sub_structures/base_class.py +139 -0
  82. fiberfusing-1.3.4/FiberFusing/sub_structures/line.py +78 -0
  83. fiberfusing-1.3.4/FiberFusing/sub_structures/ring.py +75 -0
  84. fiberfusing-1.3.4/FiberFusing/utility/__init__.py +0 -0
  85. fiberfusing-1.3.4/FiberFusing/utility/__pycache__/__init__.cpython-311.pyc +0 -0
  86. fiberfusing-1.3.4/FiberFusing/utility/__pycache__/connection_optimization.cpython-311.pyc +0 -0
  87. fiberfusing-1.3.4/FiberFusing/utility/__pycache__/overlay_structure_on_mesh.cpython-311.pyc +0 -0
  88. fiberfusing-1.3.4/FiberFusing/utility/connection_optimization.py +232 -0
  89. fiberfusing-1.3.4/FiberFusing/utility/overlay_structure_on_mesh.py +38 -0
  90. fiberfusing-1.3.4/FiberFusing/utils.py +174 -0
  91. fiberfusing-1.3.4/FiberFusing.egg-info/PKG-INFO +140 -0
  92. fiberfusing-1.3.4/FiberFusing.egg-info/SOURCES.txt +109 -0
  93. fiberfusing-1.3.4/FiberFusing.egg-info/dependency_links.txt +1 -0
  94. fiberfusing-1.3.4/FiberFusing.egg-info/requires.txt +22 -0
  95. fiberfusing-1.3.4/FiberFusing.egg-info/top_level.txt +1 -0
  96. fiberfusing-1.3.4/LICENSE +21 -0
  97. fiberfusing-1.3.4/MANIFEST.in +19 -0
  98. fiberfusing-1.3.4/PKG-INFO +140 -0
  99. fiberfusing-1.3.4/README.rst +96 -0
  100. fiberfusing-1.3.4/pyproject.toml +11 -0
  101. fiberfusing-1.3.4/setup.cfg +79 -0
  102. fiberfusing-1.3.4/setup.py +6 -0
  103. fiberfusing-1.3.4/tests/__pycache__/test_boundaries.cpython-311-pytest-8.3.1.pyc +0 -0
  104. fiberfusing-1.3.4/tests/__pycache__/test_fiber.cpython-311-pytest-8.3.1.pyc +0 -0
  105. fiberfusing-1.3.4/tests/__pycache__/test_fused_structure.cpython-311-pytest-8.3.1.pyc +0 -0
  106. fiberfusing-1.3.4/tests/__pycache__/test_geometries.cpython-311-pytest-8.3.1.pyc +0 -0
  107. fiberfusing-1.3.4/tests/test_boundaries.py +42 -0
  108. fiberfusing-1.3.4/tests/test_fiber.py +52 -0
  109. fiberfusing-1.3.4/tests/test_fused_structure.py +36 -0
  110. fiberfusing-1.3.4/tests/test_geometries.py +77 -0
@@ -0,0 +1 @@
1
+ 1.3.4
@@ -0,0 +1,79 @@
1
+ from .geometry import Geometry # noqa: F401
2
+ from .components.point import Point # noqa: F401
3
+ from .components.linestring import LineString # noqa: F401
4
+ from .components.polygon import Polygon, EmptyPolygon # noqa: F401
5
+ from .buffer import Circle, Square # noqa: F401
6
+ from .background import BackGround # noqa: F401
7
+ from pydantic.dataclasses import dataclass
8
+ from pydantic import ConfigDict
9
+
10
+ from typing import Optional, Tuple
11
+ import numpy
12
+
13
+ micro = 1e-6
14
+
15
+
16
+ @dataclass(config=ConfigDict(extra='forbid'), kw_only=True)
17
+ class CircleOpticalStructure():
18
+ """
19
+ Initialize a CircleOpticalStructure instance.
20
+
21
+ Args:
22
+ name (str): Name of the structure.
23
+ index (float): Refractive index of the structure.
24
+ radius (float): Radius of the circle representing the slice of the structure.
25
+ position (Tuple[float, float]): Center position of the circle.
26
+ is_graded (Optional[bool], optional): True if the structure has a graded refractive index. Defaults to False.
27
+ delta_n (Optional[float], optional): Delta refractive index of the grading. Defaults to None.
28
+ """
29
+ name: str
30
+ index: float
31
+ radius: float
32
+ position: Tuple[float, float]
33
+ is_graded: Optional[bool] = False
34
+ delta_n: Optional[float] = None
35
+
36
+ def __post_init__(self) -> None:
37
+ self.polygon = Circle(position=self.position, radius=self.radius)
38
+
39
+ def compute_index_from_NA(self, NA: float, exterior_index: float) -> float:
40
+ """
41
+ Compute the refractive index from the numerical aperture (NA).
42
+
43
+ Args:
44
+ NA (float): Numerical aperture.
45
+ exterior_index (float): Refractive index of the exterior structure.
46
+
47
+ Returns:
48
+ float: Computed refractive index.
49
+ """
50
+ return numpy.sqrt(NA**2 + exterior_index**2)
51
+
52
+ def get_V_number(self, wavelength: float) -> float:
53
+ """
54
+ Compute the V-number for the optical structure.
55
+
56
+ Args:
57
+ wavelength (float): Wavelength of the light.
58
+
59
+ Returns:
60
+ float: Computed V-number.
61
+ """
62
+ delta_index = numpy.sqrt(self.index**2 - self.exterior_structure.index**2)
63
+
64
+ V = 2 * numpy.pi / wavelength * delta_index * self.radius
65
+
66
+ return V
67
+
68
+ def scale(self, factor: float) -> None:
69
+ """
70
+ Scale the radius of the optical structure by a given factor.
71
+
72
+ Args:
73
+ factor (float): Scaling factor.
74
+ """
75
+ self.radius *= factor
76
+ self.__post_init__()
77
+
78
+
79
+ # -
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from typing import Tuple, Optional
5
+ from pydantic.dataclasses import dataclass
6
+ from pydantic import ConfigDict
7
+
8
+ import numpy
9
+
10
+ from FiberFusing.coordinate_system import CoordinateSystem
11
+ from FiberFusing.utility.overlay_structure_on_mesh import OverlayStructureBaseClass
12
+ from FiberFusing import Circle
13
+
14
+
15
+ class NameSpace:
16
+ """
17
+ A flexible class that allows the dynamic addition of attributes via keyword arguments.
18
+ """
19
+
20
+ def __init__(self, **kwargs):
21
+ """
22
+ Initializes an instance with attributes specified by the keyword arguments.
23
+
24
+ :param kwargs: Arbitrary keyword arguments to set as attributes.
25
+ """
26
+ for key, value in kwargs.items():
27
+ setattr(self, key, value)
28
+
29
+
30
+ @dataclass(config=ConfigDict(extra='forbid'), kw_only=True)
31
+ class BackGround(OverlayStructureBaseClass):
32
+ """
33
+ Represents a background structure to be overlayed on a mesh, characterized by a circular shape.
34
+
35
+ Attributes:
36
+ index (float): Refractive index of the background.
37
+ radius (float): Radius of the circular structure. Defaults to 1000.
38
+ position (Optional[Tuple[float, float]]): A tuple (x, y) specifying the position of the circle's center. Defaults to (0, 0).
39
+ structure_list (list): List of namespaces containing structure data.
40
+ """
41
+
42
+ index: float
43
+ radius: float = 1000
44
+ position: Optional[Tuple[float, float]] = (0, 0)
45
+
46
+ def __post_init__(self):
47
+ """
48
+ Initializes the background structure by creating a circular polygon.
49
+ """
50
+ # Create the circular structure
51
+ polygon = Circle(
52
+ position=self.position,
53
+ radius=self.radius,
54
+ index=self.index
55
+ )
56
+
57
+ background = NameSpace(index=self.index, polygon=polygon, name='background')
58
+ self.structure_list = [background]
59
+
60
+ @property
61
+ def refractive_index_list(self) -> list:
62
+ """
63
+ Returns the list of refractive indices for the structures.
64
+
65
+ Returns:
66
+ list: A list containing the refractive index of the background.
67
+ """
68
+ return [self.index]
69
+
70
+ def overlay_structures_on_mesh(self, mesh: numpy.ndarray, coordinate_system: CoordinateSystem) -> numpy.ndarray:
71
+ """
72
+ Overlays all the structures onto the given mesh using the specified coordinate system.
73
+
74
+ Args:
75
+ mesh (numpy.ndarray): A numpy ndarray representing the mesh to overlay on.
76
+ coordinate_system (CoordinateSystem): The coordinate system to use for overlaying.
77
+
78
+ Returns:
79
+ numpy.ndarray: A numpy ndarray with the structures overlayed onto the original mesh.
80
+ """
81
+ return self._overlay_structure_on_mesh_(
82
+ structure_list=self.structure_list,
83
+ mesh=mesh,
84
+ coordinate_system=coordinate_system
85
+ )
86
+
87
+
88
+ # -
@@ -0,0 +1,510 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from __future__ import annotations
5
+ from typing import Union, Optional
6
+ import logging
7
+ from dataclasses import dataclass
8
+
9
+ # Third-party imports
10
+ import numpy
11
+ import shapely.geometry as geo
12
+
13
+ # Local imports
14
+ from MPSPlots.render2D import Axis, SceneList
15
+ from FiberFusing import utils
16
+ from FiberFusing.utility.overlay_structure_on_mesh import OverlayStructureBaseClass
17
+ from FiberFusing.coordinate_system import CoordinateSystem
18
+ from FiberFusing.buffer import Circle
19
+ from FiberFusing.sub_structures.ring import FiberRing
20
+ from FiberFusing.sub_structures.line import FiberLine
21
+
22
+ logging.basicConfig(level=logging.INFO)
23
+
24
+
25
+ class NameSpace:
26
+ """
27
+ A flexible class that allows the dynamic addition of attributes via keyword arguments.
28
+ """
29
+
30
+ def __init__(self, **kwargs):
31
+ """
32
+ Initializes an instance with attributes specified by the keyword arguments.
33
+
34
+ :param kwargs: Arbitrary keyword arguments to set as attributes.
35
+ """
36
+ for key, value in kwargs.items():
37
+ setattr(self, key, value)
38
+
39
+
40
+ @dataclass
41
+ class BaseFused(OverlayStructureBaseClass):
42
+ """
43
+ Represents a base class for managing the fusion of optical fiber structures, allowing customization of fiber properties and spatial configuration. This class facilitates the dynamic assembly of fiber optics structures and automates the overlay of these structures on a given mesh.
44
+
45
+ Attributes:
46
+ fiber_radius (float): Radius of individual fibers in the structure.
47
+ index (float): Refractive index of the fibers' cladding.
48
+ tolerance_factor (float): A tolerance value used in optimization algorithms to balance the area difference between added and removed sections during the fusion process.
49
+ fusion_degree (float | str): Specifies the degree of fusion, ranging from 0 (no fusion) to 1 (full fusion), or 'auto' to automatically determine based on geometry.
50
+ core_position_scrambling (float): Introduces randomness to core positions to simulate practical imperfections.
51
+ scale_down_position (float): Scaling factor to adjust the overall size of the assembly.
52
+ """
53
+
54
+ fiber_radius: float
55
+ index: float
56
+ tolerance_factor: Optional[float] = 1e-2
57
+ fusion_degree: Optional[Union[float | str]] = 'auto'
58
+ core_position_scrambling: Optional[float] = 0
59
+ scale_down_position: Optional[float] = 1
60
+
61
+ def __post_init__(self):
62
+ """
63
+ Initializes the fiber and core lists and any required structures immediately after the dataclass fields have been populated.
64
+ """
65
+ self.fiber_list = []
66
+ self.core_list = []
67
+ self._clad_structure = None
68
+ self.structure_list = []
69
+ self.removed_section_list = []
70
+ self.added_section_list = []
71
+
72
+ self.compute_parametrized_fusion_degree()
73
+
74
+ def compute_parametrized_fusion_degree(self) -> float:
75
+ """
76
+ Calculates a fusion degree adjusted to the specific requirements of the structure's geometry.
77
+
78
+ Returns:
79
+ float: The adjusted fusion degree, mapping an abstract range [0, 1] to the actual usable range defined by the structure's physical constraints.
80
+ """
81
+ if str(self.fusion_degree).lower() == 'auto':
82
+ self.fusion_degree = 0.8 if self.fusion_range is not None else None
83
+
84
+ self.asserts_fusion_degree()
85
+
86
+ if self.fusion_degree is not None:
87
+ self.parametrized_fusion_degree = self.fusion_range[0] * (1 - self.fusion_degree) + self.fusion_degree * self.fusion_range[-1]
88
+ else:
89
+ self.parametrized_fusion_degree = None
90
+
91
+ def asserts_fusion_degree(self) -> None:
92
+ """
93
+ Validates the fusion degree to ensure it lies within acceptable bounds.
94
+
95
+ Raises:
96
+ ValueError: If the fusion degree is not a scalar when required, or is out of the acceptable bounds [0, 1].
97
+ TypeError: If the fusion degree is required but None is provided.
98
+ """
99
+ if self.fusion_range is None:
100
+ if self.fusion_degree is not None:
101
+ raise ValueError(f"This instance of {self.__class__.__name__} does not take 'fusion_degree' as an argument.")
102
+ else:
103
+ if not numpy.isscalar(self.fusion_degree):
104
+ raise TypeError(f"Fusion degree: [{self.fusion_degree}] must be a scalar value.")
105
+
106
+ if not 0 <= self.fusion_degree <= 1:
107
+ raise ValueError(f"User provided fusion degree: {self.fusion_degree} must be in the range [0, 1].")
108
+
109
+ @property
110
+ def refractive_index_list(self) -> list[float]:
111
+ return [self.index]
112
+
113
+ @property
114
+ def is_multi(self) -> bool:
115
+ return isinstance(self.clad_structure._shapely_object, geo.MultiPolygon)
116
+
117
+ @property
118
+ def clad_structure(self):
119
+ if self._clad_structure is None:
120
+ return utils.Union(*self.structure_list)
121
+ else:
122
+ return self._clad_structure
123
+
124
+ @property
125
+ def structure_dictionary(self) -> dict:
126
+ return {'name': {'index': self.index, 'polygon': self.clad_structure}}
127
+
128
+ def overlay_structures_on_mesh(self, mesh: numpy.ndarray, coordinate_system: CoordinateSystem) -> numpy.ndarray:
129
+ """
130
+ Applies the current fiber structure configuration onto a provided mesh, considering the specified coordinate system.
131
+
132
+ Parameters:
133
+ mesh (numpy.ndarray): The mesh on which to overlay the structure.
134
+ coordinate_system (CoordinateSystem): The coordinate system to use for the overlay.
135
+
136
+ Returns:
137
+ numpy.ndarray: A mesh with the fiber structures applied.
138
+ """
139
+ structure_list = [
140
+ NameSpace(index=self.index, polygon=self.clad_structure)
141
+ ]
142
+
143
+ return self._overlay_structure_on_mesh_(
144
+ structure_list=structure_list,
145
+ mesh=mesh,
146
+ coordinate_system=coordinate_system
147
+ )
148
+
149
+ def get_shapely_object(self):
150
+ return self.clad_structure._shapely_object
151
+
152
+ @property
153
+ def bounds(self) -> tuple:
154
+ """
155
+ Return the boundaries of the structure.
156
+ """
157
+ return self.clad_structure.bounds
158
+
159
+ @property
160
+ def boundaries(self) -> tuple:
161
+ """
162
+ Return the boundaries of the structure.
163
+ """
164
+ return self.clad_structure.bounds
165
+
166
+ def get_structure_max_min_boundaries(self) -> tuple:
167
+ return self.clad_structure.bounds
168
+
169
+ @property
170
+ def center(self):
171
+ return self.clad_structure.center
172
+
173
+ @property
174
+ def fiber(self) -> list:
175
+ """
176
+ Return list of all the fiber in the structure
177
+
178
+ :returns: List of the structure fiber components
179
+ :rtype: list
180
+ """
181
+ return self.fiber_list
182
+
183
+ @property
184
+ def cores(self) -> list:
185
+ """
186
+ Return a list of the cores
187
+
188
+ :returns: List of the cores
189
+ :rtype: list
190
+ """
191
+ return [fiber.core for fiber in self.fiber_list]
192
+
193
+ def add_single_fiber(self, fiber_radius: float, position: tuple = (0, 0)) -> BaseFused:
194
+ """
195
+ Adds a single fiber to the structure at the specified position.
196
+
197
+ Parameters:
198
+ fiber_radius (float): The radius of the fiber to add.
199
+ position (tuple, optional): The x, y coordinates for the fiber. Defaults to (0, 0).
200
+
201
+ Returns:
202
+ BaseFused: Returns the instance to allow for method chaining.
203
+ """
204
+ fiber = Circle(
205
+ radius=fiber_radius,
206
+ position=position
207
+ )
208
+
209
+ fiber.shifted_core = fiber.center
210
+
211
+ self.structure_list.append(fiber)
212
+
213
+ self.fiber_list.append(fiber)
214
+
215
+ return self
216
+
217
+ def add_single_circle_structure(self, fiber_radius: float, position: tuple = (0, 0)) -> BaseFused:
218
+ """
219
+ Adds a single structure.
220
+
221
+ :param fiber_radius: The fiber radius
222
+ :type fiber_radius: float
223
+ :param position: The position
224
+ :type position: tuple
225
+
226
+ :returns: The self instance
227
+ :rtype: BaseFused
228
+ """
229
+ fiber = Circle(
230
+ radius=fiber_radius,
231
+ position=position
232
+ )
233
+
234
+ self.structure_list.append(fiber)
235
+
236
+ return self
237
+
238
+ def add_center_fiber(self, fiber_radius: float) -> BaseFused:
239
+ """
240
+ Add a single fiber of given radius at the center of the structure.
241
+
242
+ :param fiber_radius: The fiber radius
243
+ :type fiber_radius: float
244
+
245
+ :returns: The self instance
246
+ :rtype: BaseFused
247
+ """
248
+ return self.add_single_fiber(fiber_radius=fiber_radius, position=(0, 0))
249
+
250
+ def add_center_structure(self, fiber_radius: float) -> BaseFused:
251
+ """
252
+ Add a single structure of given radius at the center of the structure.
253
+
254
+ :param fiber_radius: The fiber radius
255
+ :type fiber_radius: float
256
+
257
+ :returns: The self instance
258
+ :rtype: BaseFused
259
+ """
260
+ return self.add_single_circle_structure(fiber_radius=fiber_radius, position=(0, 0))
261
+
262
+ def _add_structure_to_instance_(
263
+ self,
264
+ structure: FiberRing | FiberLine,
265
+ fusion_degree: float = 0.0,
266
+ scale_position: float = 1.0,
267
+ position_shift: list = [0, 0],
268
+ compute_fusing: bool = False) -> BaseFused:
269
+
270
+ if compute_fusing:
271
+ structure.set_fusion_degree(fusion_degree=fusion_degree)
272
+
273
+ structure.scale_position(factor=scale_position)
274
+ structure.shift_position(shift=position_shift)
275
+ structure.initialize_cores()
276
+
277
+ self.fiber_list += structure.fiber_list
278
+
279
+ if compute_fusing:
280
+ structure.init_connected_fibers()
281
+ structure.compute_optimal_structure()
282
+ self.removed_section_list.append(structure.removed_section)
283
+ self.added_section_list.append(structure.added_section)
284
+ self.structure_list.append(structure.fused_structure)
285
+
286
+ else:
287
+ self.structure_list.append(structure.unfused_structure)
288
+
289
+ return self
290
+
291
+ def add_structure(
292
+ self,
293
+ structure_type: str,
294
+ number_of_fibers: int,
295
+ fiber_radius: float,
296
+ fusion_degree: float = 0.0,
297
+ scale_position: float = 1.0,
298
+ position_shift: list = [0, 0],
299
+ compute_fusing: bool = False,
300
+ angle_shift: float = 0.0) -> BaseFused:
301
+ """
302
+ Adds a predefined structure of fibers, such as a ring or line, with customizable properties and spatial configuration.
303
+
304
+ Parameters:
305
+ structure_type (str): The type of structure to add ('ring' or 'line').
306
+ number_of_fibers (int): Number of fibers in the structure.
307
+ fiber_radius (float): Radius of each fiber in the structure.
308
+ fusion_degree (float): The degree of fusion for this structure.
309
+ scale_position (float): Factor to scale the position of each fiber.
310
+ position_shift (list): A 2D vector [x, y] to shift the entire structure.
311
+ compute_fusing (bool): Whether to compute the fusing operation for the structure.
312
+ angle_shift (float): The angle by which to rotate the structure.
313
+
314
+ Returns:
315
+ BaseFused: Returns the instance to allow for method chaining.
316
+ """
317
+ match structure_type.lower():
318
+ case 'ring':
319
+ StructureClass = FiberRing
320
+ case 'line':
321
+ StructureClass = FiberRing
322
+
323
+ structure = StructureClass(
324
+ number_of_fibers=number_of_fibers,
325
+ fiber_radius=fiber_radius,
326
+ angle_shift=angle_shift
327
+ )
328
+
329
+ return self._add_structure_to_instance_(
330
+ structure=structure,
331
+ fusion_degree=fusion_degree,
332
+ scale_position=scale_position,
333
+ position_shift=position_shift,
334
+ compute_fusing=compute_fusing
335
+ )
336
+
337
+ def add_custom_fiber(self, *fibers) -> None:
338
+ """
339
+ Add any custom defined fiber
340
+
341
+ :param fibers: The custom fibers
342
+ :type fibers: list
343
+ """
344
+ for fiber in fibers:
345
+ self.fiber_list.append(fiber)
346
+
347
+ def get_core_positions(self) -> list:
348
+ """
349
+ Return a list of the core positions
350
+
351
+ :returns: The core positions.
352
+ :rtype: list
353
+ """
354
+ return [fiber.core for fiber in self.fiber_list]
355
+
356
+ def randomize_core_position(self, random_factor: float = 0) -> BaseFused:
357
+ """
358
+ Shuffle the position of the fiber cores.
359
+ It can be used to add realism to the fusion process.
360
+
361
+ :param random_factor: The randomize position
362
+ :type random_factor: float
363
+
364
+ :returns: The self instance
365
+ :rtype: BaseFused
366
+ """
367
+ if random_factor == 0:
368
+ return
369
+
370
+ logging.info("Randomizing the core positions")
371
+
372
+ if random_factor != 0:
373
+ for fiber in self.fiber_list:
374
+ random_xy = numpy.random.rand(2) * random_factor
375
+ fiber.core.translate(random_xy, in_place=True)
376
+
377
+ return self
378
+
379
+ def get_rasterized_mesh(self, coordinate_system: CoordinateSystem) -> numpy.ndarray:
380
+ return self.clad_structure.get_rasterized_mesh(coordinate_system=coordinate_system)
381
+
382
+ def rotate(self, *args, **kwargs) -> BaseFused:
383
+ """
384
+ Rotates the full structure, including the fiber cores.
385
+
386
+ :returns: The self instance
387
+ :rtype: BaseFused
388
+ """
389
+ for fiber in self.fiber_list:
390
+ fiber.core.rotate(*args, **kwargs, in_place=True)
391
+
392
+ self._clad_structure = self.clad_structure.rotate(*args, **kwargs)
393
+
394
+ return self
395
+
396
+ def shift(self, *args, **kwargs) -> BaseFused:
397
+ """
398
+ Rotates the full structure, including the fiber cores.
399
+
400
+ :returns: The self instance
401
+ :rtype: BaseFused
402
+ """
403
+ for fiber in self.fiber_list:
404
+ fiber.core.shift(*args, **kwargs, in_place=True)
405
+
406
+ self._clad_structure = self.clad_structure.shift(*args, **kwargs)
407
+
408
+ return self
409
+
410
+ def scale_position(self, factor: float) -> BaseFused:
411
+ """
412
+ Scale down the distance between each cores.
413
+
414
+ :param factor: The scaling factor
415
+ :type factor: float
416
+
417
+ :returns: The self instance
418
+ :rtype: BaseFused
419
+ """
420
+ for fiber in self.fiber_list:
421
+ fiber.scale_position(factor=factor)
422
+
423
+ return self
424
+
425
+ def plot(self, **kwargs) -> SceneList:
426
+
427
+ figure = SceneList(unit_size=(6, 6))
428
+
429
+ ax = figure.append_ax(
430
+ x_label=r'x',
431
+ y_label=r'y',
432
+ show_grid=True,
433
+ equal_limits=True,
434
+ show_legend=True,
435
+ )
436
+
437
+ self.render_patch_on_ax(ax=ax, **kwargs)
438
+
439
+ return figure
440
+
441
+ def render_patch_on_ax(
442
+ self,
443
+ ax: Axis,
444
+ show_structure: bool = True,
445
+ show_fibers: bool = False,
446
+ show_shifted_cores: bool = True,
447
+ show_added: bool = True,
448
+ show_removed: bool = True) -> None:
449
+ """
450
+ Add the geometry patches to the axis.
451
+ Base patch is the clad representation.
452
+ The boolean paraemters defines which other patch is added
453
+ to the ax.
454
+
455
+ :param ax: The axis to which add the patches
456
+ :type ax: Axis
457
+ :param show_structure: Added the fused structure to ax
458
+ :type show_structure: bool
459
+ :param show_fibers: Added the unfused fibers to ax
460
+ :type show_fibers: bool
461
+ :param show_shifted_cores: Added the shifted cores to ax
462
+ :type show_shifted_cores: bool
463
+ :param show_added: Added the added section to ax
464
+ :type show_added: bool
465
+ :param show_removed: Added the removed section to ax
466
+ :type show_removed: bool
467
+
468
+ :returns: The scene list.
469
+ :rtype: SceneList
470
+ """
471
+ if show_structure:
472
+ self.clad_structure._render_on_ax_(ax)
473
+
474
+ ax.set_style(
475
+ x_label=r'x-distance [$\mu$m]',
476
+ y_label=r'y-distance [$\mu$m]',
477
+ x_scale_factor=1e6,
478
+ y_scale_factor=1e6,
479
+ equal_limits=True,
480
+ )
481
+
482
+ if show_added:
483
+ added_section = utils.Union(*self.added_section_list)
484
+ added_section._render_on_ax_(ax=ax, facecolor='green', label='added section')
485
+
486
+ # if show_removed:
487
+ # removed_section = utils.Union(*self.removed_section_list)
488
+ # removed_section._render_on_ax_(ax=ax, facecolor='red', label='removed section')
489
+
490
+ # if show_fibers:
491
+ # for n, fiber in enumerate(self.fiber_list):
492
+ # fiber._render_on_ax_(ax)
493
+ # fiber.center._render_on_ax_(
494
+ # ax,
495
+ # marker='o',
496
+ # marker_size=40,
497
+ # label='core',
498
+ # )
499
+
500
+ # if show_shifted_cores:
501
+ # for n, fiber in enumerate(self.fiber_list):
502
+ # fiber.shifted_core.render_on_axis(
503
+ # ax,
504
+ # marker='x',
505
+ # marker_size=40,
506
+ # edge_color=None,
507
+ # label='shifted core',
508
+ # )
509
+
510
+ # -