FiberFusing 1.7.0__tar.gz → 1.9.0__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.
Files changed (169) hide show
  1. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/.github/workflows/deploy_anaconda.yml +3 -3
  2. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/.github/workflows/deploy_coverage.yml +2 -2
  3. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/.github/workflows/deploy_documentation.yml +3 -3
  4. fiberfusing-1.9.0/FiberFusing/__init__.py +15 -0
  5. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/_version.py +16 -3
  6. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/background.py +8 -23
  7. fiberfusing-1.9.0/FiberFusing/connection/connection.py +459 -0
  8. {fiberfusing-1.7.0/FiberFusing → fiberfusing-1.9.0/FiberFusing/connection}/connection_optimization.py +7 -7
  9. fiberfusing-1.9.0/FiberFusing/connection/utils.py +16 -0
  10. fiberfusing-1.9.0/FiberFusing/coordinate_system.py +944 -0
  11. fiberfusing-1.9.0/FiberFusing/fiber/__init__.py +2 -0
  12. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/generic_fiber.py +237 -45
  13. fiberfusing-1.9.0/FiberFusing/fiber/loader.py +318 -0
  14. fiberfusing-1.9.0/FiberFusing/geometries/__init__.py +3 -0
  15. {fiberfusing-1.7.0/FiberFusing/components → fiberfusing-1.9.0/FiberFusing/geometries}/base_class.py +3 -3
  16. {fiberfusing-1.7.0/FiberFusing/components → fiberfusing-1.9.0/FiberFusing/geometries}/linestring.py +3 -3
  17. {fiberfusing-1.7.0/FiberFusing/components → fiberfusing-1.9.0/FiberFusing/geometries}/point.py +9 -9
  18. {fiberfusing-1.7.0/FiberFusing/components → fiberfusing-1.9.0/FiberFusing/geometries}/polygon.py +3 -3
  19. {fiberfusing-1.7.0/FiberFusing/components → fiberfusing-1.9.0/FiberFusing/geometries}/utils.py +2 -2
  20. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/geometry.py +159 -186
  21. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/helper.py +3 -3
  22. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/optical_structure.py +8 -9
  23. fiberfusing-1.7.0/FiberFusing/base_fused.py → fiberfusing-1.9.0/FiberFusing/profile.py +54 -80
  24. fiberfusing-1.9.0/FiberFusing/shapes/__init__.py +3 -0
  25. fiberfusing-1.9.0/FiberFusing/shapes/base.py +6 -0
  26. fiberfusing-1.9.0/FiberFusing/shapes/circle.py +54 -0
  27. fiberfusing-1.9.0/FiberFusing/shapes/ellipse.py +68 -0
  28. fiberfusing-1.9.0/FiberFusing/shapes/square.py +55 -0
  29. fiberfusing-1.7.0/FiberFusing/fiber_structure.py → fiberfusing-1.9.0/FiberFusing/structures.py +52 -18
  30. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/utils.py +15 -3
  31. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing.egg-info/PKG-INFO +61 -12
  32. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing.egg-info/SOURCES.txt +26 -48
  33. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing.egg-info/requires.txt +7 -8
  34. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/PKG-INFO +61 -12
  35. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/README.rst +53 -3
  36. fiberfusing-1.9.0/docs/examples/extra/README.rst +4 -0
  37. fiberfusing-1.9.0/docs/examples/extra/custom_graded_index_fiber.py +42 -0
  38. fiberfusing-1.9.0/docs/examples/extra/custom_step_index_fiber.py +40 -0
  39. fiberfusing-1.9.0/docs/examples/extra/loading_fiber.py +18 -0
  40. fiberfusing-1.9.0/docs/examples/extra/randomize_core.py +32 -0
  41. fiberfusing-1.9.0/docs/examples/extra/structure_shift.py +29 -0
  42. fiberfusing-1.9.0/docs/examples/geometry/plot_line_3.py +55 -0
  43. fiberfusing-1.9.0/docs/examples/geometry/plot_line_4.py +48 -0
  44. fiberfusing-1.9.0/docs/examples/geometry/plot_line_5.py +48 -0
  45. fiberfusing-1.9.0/docs/examples/geometry/plot_ring_10.py +48 -0
  46. fiberfusing-1.9.0/docs/examples/geometry/plot_ring_2.py +49 -0
  47. fiberfusing-1.9.0/docs/examples/geometry/plot_ring_3.py +48 -0
  48. fiberfusing-1.9.0/docs/examples/geometry/plot_ring_4.py +52 -0
  49. fiberfusing-1.9.0/docs/examples/geometry/plot_ring_5.py +49 -0
  50. fiberfusing-1.9.0/docs/examples/geometry/plot_ring_7.py +49 -0
  51. fiberfusing-1.9.0/docs/examples/geometry/plot_single.py +45 -0
  52. fiberfusing-1.9.0/docs/source/code/components.rst +10 -0
  53. fiberfusing-1.9.0/docs/source/code/shapes.rst +9 -0
  54. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/code.rst +1 -1
  55. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/conf.py +0 -5
  56. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/gallery/index.rst +28 -138
  57. fiberfusing-1.9.0/docs/source/sg_execution_times.rst +79 -0
  58. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/meta.yaml +6 -5
  59. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/pyproject.toml +7 -8
  60. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/tests/fiber_loader.py +39 -13
  61. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/tests/test_boundaries.py +21 -12
  62. fiberfusing-1.9.0/tests/test_cooordinate_system.py +536 -0
  63. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/tests/test_fiber.py +28 -22
  64. fiberfusing-1.9.0/tests/test_fused_structure.py +105 -0
  65. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/tests/test_generic_fiber.py +4 -19
  66. fiberfusing-1.9.0/tests/test_geometries.py +191 -0
  67. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/tests/test_polygon.py +2 -2
  68. fiberfusing-1.7.0/.readthedocs.yml +0 -35
  69. fiberfusing-1.7.0/FiberFusing/__init__.py +0 -15
  70. fiberfusing-1.7.0/FiberFusing/buffer.py +0 -163
  71. fiberfusing-1.7.0/FiberFusing/configuration/__init__.py +0 -7
  72. fiberfusing-1.7.0/FiberFusing/configuration/line/__init__.py +0 -10
  73. fiberfusing-1.7.0/FiberFusing/configuration/line/configuration_01x01.py +0 -14
  74. fiberfusing-1.7.0/FiberFusing/configuration/line/configuration_02x02.py +0 -18
  75. fiberfusing-1.7.0/FiberFusing/configuration/line/configuration_03x03.py +0 -18
  76. fiberfusing-1.7.0/FiberFusing/configuration/line/configuration_04x04.py +0 -18
  77. fiberfusing-1.7.0/FiberFusing/configuration/line/configuration_05x05.py +0 -18
  78. fiberfusing-1.7.0/FiberFusing/configuration/ring/__init__.py +0 -15
  79. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_01x01.py +0 -14
  80. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_02x02.py +0 -18
  81. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_03x03.py +0 -18
  82. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_04x04.py +0 -18
  83. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_05x05.py +0 -18
  84. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_06x06.py +0 -18
  85. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_07x07.py +0 -20
  86. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_10x10.py +0 -31
  87. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_12x12.py +0 -30
  88. fiberfusing-1.7.0/FiberFusing/configuration/ring/configuration_19x19.py +0 -34
  89. fiberfusing-1.7.0/FiberFusing/connection.py +0 -366
  90. fiberfusing-1.7.0/FiberFusing/coordinate_system.py +0 -256
  91. fiberfusing-1.7.0/FiberFusing/fiber/catalogue.py +0 -165
  92. fiberfusing-1.7.0/FiberFusing/fiber/loader.py +0 -120
  93. fiberfusing-1.7.0/FiberFusing/fiber/structure_collection.py +0 -173
  94. fiberfusing-1.7.0/docs/examples/clad/README.rst +0 -4
  95. fiberfusing-1.7.0/docs/examples/clad/fusion_degree.py +0 -26
  96. fiberfusing-1.7.0/docs/examples/clad/plot_line_3.py +0 -22
  97. fiberfusing-1.7.0/docs/examples/clad/plot_line_4.py +0 -22
  98. fiberfusing-1.7.0/docs/examples/clad/plot_line_5.py +0 -22
  99. fiberfusing-1.7.0/docs/examples/clad/plot_ring_12.py +0 -21
  100. fiberfusing-1.7.0/docs/examples/clad/plot_ring_19.py +0 -21
  101. fiberfusing-1.7.0/docs/examples/clad/plot_ring_2.py +0 -22
  102. fiberfusing-1.7.0/docs/examples/clad/plot_ring_3py +0 -22
  103. fiberfusing-1.7.0/docs/examples/clad/plot_ring_4.py +0 -22
  104. fiberfusing-1.7.0/docs/examples/clad/plot_ring_7.py +0 -22
  105. fiberfusing-1.7.0/docs/examples/clad/plot_single.py +0 -16
  106. fiberfusing-1.7.0/docs/examples/clad/radomize_core.py +0 -33
  107. fiberfusing-1.7.0/docs/examples/clad/structure_shift.py +0 -28
  108. fiberfusing-1.7.0/docs/examples/geometry/plot_line_3.py +0 -51
  109. fiberfusing-1.7.0/docs/examples/geometry/plot_line_4.py +0 -45
  110. fiberfusing-1.7.0/docs/examples/geometry/plot_line_5.py +0 -45
  111. fiberfusing-1.7.0/docs/examples/geometry/plot_ring_10.py +0 -44
  112. fiberfusing-1.7.0/docs/examples/geometry/plot_ring_2.py +0 -45
  113. fiberfusing-1.7.0/docs/examples/geometry/plot_ring_3.py +0 -45
  114. fiberfusing-1.7.0/docs/examples/geometry/plot_ring_4.py +0 -45
  115. fiberfusing-1.7.0/docs/examples/geometry/plot_ring_5.py +0 -45
  116. fiberfusing-1.7.0/docs/examples/geometry/plot_ring_7.py +0 -45
  117. fiberfusing-1.7.0/docs/examples/geometry/plot_single.py +0 -44
  118. fiberfusing-1.7.0/docs/source/code/buffer.rst +0 -19
  119. fiberfusing-1.7.0/docs/source/code/components.rst +0 -33
  120. fiberfusing-1.7.0/tests/__init__.py +0 -0
  121. fiberfusing-1.7.0/tests/test_cooordinate_system.py +0 -155
  122. fiberfusing-1.7.0/tests/test_fused_structure.py +0 -57
  123. fiberfusing-1.7.0/tests/test_geometries.py +0 -154
  124. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/.flake8 +0 -0
  125. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/.github/dependabot.yml +0 -0
  126. /fiberfusing-1.7.0/.github/workflows/deploy_PyPI.yml → /fiberfusing-1.9.0/.github/workflows/deploy_PyPi.yml +0 -0
  127. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/.gitignore +0 -0
  128. {fiberfusing-1.7.0/FiberFusing/components → fiberfusing-1.9.0/FiberFusing/connection}/__init__.py +0 -0
  129. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/directories.py +0 -0
  130. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/1550BHP.yaml +0 -0
  131. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/DCF13.yaml +0 -0
  132. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/DCF1300S_20.yaml +0 -0
  133. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/DCF1300S_26.yaml +0 -0
  134. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/DCF1300S_33.yaml +0 -0
  135. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/DCF1300S_42.yaml +0 -0
  136. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/F2028M12.yaml +0 -0
  137. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/F2028M21.yaml +0 -0
  138. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/F2028M24.yaml +0 -0
  139. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/F2058G1.yaml +0 -0
  140. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/F2058L1.yaml +0 -0
  141. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/HI1060.yaml +0 -0
  142. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/HP630.yaml +0 -0
  143. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/SM1950.yaml +0 -0
  144. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/SMF28.yaml +0 -0
  145. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/fluorine_doped_1%_capillary.yaml +0 -0
  146. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/fluorine_doped_2%_capillary.yaml +0 -0
  147. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/test_fiber.yaml +0 -0
  148. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/fiber/fiber_files/test_multimode_fiber.yaml +0 -0
  149. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing/plottings.py +0 -0
  150. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing.egg-info/dependency_links.txt +0 -0
  151. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/FiberFusing.egg-info/top_level.txt +0 -0
  152. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/LICENSE +0 -0
  153. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/Makefile +0 -0
  154. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/examples/README.rst +0 -0
  155. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/examples/geometry/README.rst +0 -0
  156. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/images/example_3x3.png +0 -0
  157. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/images/logo.png +0 -0
  158. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/make.bat +0 -0
  159. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/_static/default.css +0 -0
  160. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/_static/thumbnail.png +0 -0
  161. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/code/coordinate_system.rst +0 -0
  162. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/code/geometry.rst +0 -0
  163. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/code/utils.rst +0 -0
  164. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/index.rst +0 -0
  165. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/references.rst +0 -0
  166. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/docs/source/theory.rst +0 -0
  167. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/notebook.ipynb +0 -0
  168. {fiberfusing-1.7.0 → fiberfusing-1.9.0}/setup.cfg +0 -0
  169. {fiberfusing-1.7.0/FiberFusing/fiber → fiberfusing-1.9.0/tests}/__init__.py +0 -0
@@ -3,8 +3,7 @@ name: Deploy Conda Packages
3
3
  on:
4
4
  push:
5
5
  branches: [ "master" ]
6
- tags:
7
- - '*'
6
+ tags: '*'
8
7
  pull_request:
9
8
  branches: [ "master" ]
10
9
 
@@ -15,7 +14,8 @@ jobs:
15
14
  ManyLinux_x86_64:
16
15
  uses: MartinPdeS/MPSActions/.github/workflows/publish_compiled_package_to_anaconda.yml@master
17
16
  with:
18
- python-versions: '["3.11", "3.12"]'
17
+ python-versions: '["3.11", "3.12", "3.13"]'
18
+ apt-package: ""
19
19
  secrets:
20
20
  ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_API_TOKEN }}
21
21
 
@@ -4,8 +4,7 @@ name: Deploy coverage
4
4
  on:
5
5
  push:
6
6
  branches: [ "master" ]
7
- tags:
8
- - '*'
7
+ tags: '*'
9
8
  pull_request:
10
9
  branches: [ "master" ]
11
10
 
@@ -21,5 +20,6 @@ jobs:
21
20
  uses: MartinPdeS/MPSActions/.github/workflows/publish_coverage.yml@master
22
21
  with:
23
22
  python-version: "3.11"
23
+ apt-package: xvfb
24
24
  secrets:
25
25
  _GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -1,11 +1,10 @@
1
1
  # Simple workflow for deploying static content to GitHub Pages
2
- name: Deploy documentation to github page
2
+ name: Documentation
3
3
 
4
4
  on:
5
5
  push:
6
6
  branches: [ "master" ]
7
- tags:
8
- - '*'
7
+ tags: '*'
9
8
  pull_request:
10
9
  branches: [ "master" ]
11
10
 
@@ -22,3 +21,4 @@ jobs:
22
21
  with:
23
22
  python-version: "3.11"
24
23
  package-name: "FiberFusing"
24
+ apt-package: xvfb jq
@@ -0,0 +1,15 @@
1
+ from .geometry import Geometry, DomainAlignment # noqa: F401
2
+ from .geometries.point import Point # noqa: F401
3
+ from .geometries.linestring import LineString # noqa: F401
4
+ from .geometries.polygon import Polygon, EmptyPolygon # noqa: F401
5
+ from .shapes import Circle, Square # noqa: F401
6
+ from .background import BackGround # noqa: F401
7
+ from .optical_structure import CircleOpticalStructure # noqa: F401
8
+ micro = 1e-6
9
+
10
+
11
+ try:
12
+ from ._version import version as __version__ # noqa: F401
13
+
14
+ except ImportError:
15
+ __version__ = "0.0.0"
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '1.7.0'
21
- __version_tuple__ = version_tuple = (1, 7, 0)
31
+ __version__ = version = '1.9.0'
32
+ __version_tuple__ = version_tuple = (1, 9, 0)
33
+
34
+ __commit_id__ = commit_id = 'gf07a7ef48'
@@ -8,22 +8,7 @@ import numpy as np
8
8
 
9
9
  from FiberFusing.coordinate_system import CoordinateSystem
10
10
  from FiberFusing.helper import OverlayStructureBaseClass
11
-
12
-
13
- class NameSpace:
14
- """
15
- A flexible class that allows dynamic addition of attributes via keyword arguments.
16
- """
17
- def __init__(self, **kwargs):
18
- """
19
- Initializes an instance with attributes specified by keyword arguments.
20
-
21
- Parameters
22
- ----------
23
- **kwargs : dict
24
- Arbitrary keyword arguments to set as attributes.
25
- """
26
- self.__dict__.update(kwargs)
11
+ from FiberFusing.utils import NameSpace
27
12
 
28
13
 
29
14
  @dataclass(config=ConfigDict(extra='forbid', kw_only=True))
@@ -33,15 +18,15 @@ class BackGround(OverlayStructureBaseClass):
33
18
 
34
19
  Attributes
35
20
  ----------
36
- index : float
37
- Refractive index of the background.
21
+ refractive_index : float
22
+ Refractive refractive_index of the background.
38
23
  radius : float, optional
39
24
  Radius of the circular structure, by default 1000.
40
25
  position : Optional[Tuple[float, float]], optional
41
26
  A tuple (x, y) specifying the position of the circle's center, by default (0, 0).
42
27
  """
43
28
 
44
- index: float
29
+ refractive_index: float
45
30
  radius: float = 1000
46
31
  position: Optional[Tuple[float, float]] = (0, 0)
47
32
 
@@ -51,8 +36,8 @@ class BackGround(OverlayStructureBaseClass):
51
36
  """
52
37
  from FiberFusing import Circle
53
38
 
54
- polygon = Circle(position=self.position, radius=self.radius, index=self.index)
55
- self.structure_list = [NameSpace(index=self.index, polygon=polygon, name='background')]
39
+ polygon = Circle(position=self.position, radius=self.radius, refractive_index=self.refractive_index)
40
+ self.structure_list = [NameSpace(refractive_index=self.refractive_index, polygon=polygon, name='background')]
56
41
 
57
42
  @property
58
43
  def refractive_index_list(self) -> list:
@@ -64,7 +49,7 @@ class BackGround(OverlayStructureBaseClass):
64
49
  list
65
50
  A list containing the refractive index of the background.
66
51
  """
67
- return [self.index]
52
+ return [self.refractive_index]
68
53
 
69
54
  def overlay_structures_on_mesh(self, mesh: np.ndarray, coordinate_system: CoordinateSystem) -> np.ndarray:
70
55
  """
@@ -89,4 +74,4 @@ class BackGround(OverlayStructureBaseClass):
89
74
  )
90
75
 
91
76
  def rotate(self, *args, **kwargs) -> None:
92
- pass
77
+ pass
@@ -0,0 +1,459 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from __future__ import annotations
5
+ from typing import List, Tuple, Optional
6
+ import numpy as np
7
+ import logging
8
+ from scipy.optimize import minimize_scalar
9
+ from pydantic.dataclasses import dataclass
10
+ from pydantic import ConfigDict
11
+
12
+ import FiberFusing as ff
13
+ from FiberFusing import utils
14
+ from FiberFusing.shapes.circle import Circle
15
+ from FiberFusing.connection.utils import TopologyType, ConscriptedCircleType
16
+
17
+
18
+
19
+ @dataclass(config=ConfigDict(extra='forbid', arbitrary_types_allowed=True, strict=True, frozen=False))
20
+ class Connection:
21
+ """
22
+ Represents a connection between two optical fiber circles.
23
+
24
+ This class manages the geometric relationship between two fibers, including
25
+ their fusion topology, area calculations, and core positioning optimization.
26
+
27
+ Parameters
28
+ ----------
29
+ fiber0 : Circle
30
+ The first fiber in the connection.
31
+ fiber1 : Circle
32
+ The second fiber in the connection.
33
+
34
+ Attributes
35
+ ----------
36
+ topology : TopologyType
37
+ The connection topology (convex, concave, or undefined).
38
+ shift : float
39
+ The shift value for the connection geometry.
40
+ added_section : ff.Polygon
41
+ The area added during fiber fusion.
42
+ removed_section : ff.Polygon
43
+ The area removed during fiber fusion.
44
+ virtual_circles : tuple[Circle, Circle] | None
45
+ Pair of virtual circles used for geometry calculations.
46
+ mask : ff.Polygon | None
47
+ Geometric mask for connection calculations.
48
+ core_shift : tuple[ff.Point, ff.Point] | None
49
+ Optimized core position shifts for both fibers.
50
+ """
51
+
52
+ fiber0: Circle
53
+ fiber1: Circle
54
+
55
+ def __post_init__(self) -> None:
56
+ """Initialize connection properties with default values."""
57
+ self._topology = TopologyType.UNDEFINED
58
+ self._shift: float = 0.0
59
+ self.added_section = ff.EmptyPolygon()
60
+ self.removed_section = ff.EmptyPolygon()
61
+ self.virtual_circles: Optional[Tuple[Circle, Circle]] = None
62
+ self.mask: Optional[ff.Polygon] = None
63
+ self.core_shift: Optional[Tuple[ff.Point, ff.Point]] = None
64
+
65
+ logging.info(f"Created connection between fibers at {self.fiber0.center} and {self.fiber1.center}")
66
+
67
+ @property
68
+ def topology(self) -> TopologyType:
69
+ """Get the connection topology."""
70
+ return self._topology
71
+
72
+ @topology.setter
73
+ def topology(self, value: TopologyType) -> None:
74
+ """Set the connection topology with validation."""
75
+ if not isinstance(value, TopologyType):
76
+ raise TypeError(f"Topology must be a TopologyType enum, got {type(value).__name__}")
77
+ self._topology = value
78
+
79
+ @property
80
+ def shift(self) -> float:
81
+ """Get the connection shift value."""
82
+ return self._shift
83
+
84
+ @shift.setter
85
+ def shift(self, value: float) -> None:
86
+ """Set the connection shift value."""
87
+ self._shift = float(value)
88
+
89
+ @property
90
+ def fibers(self) -> List[Circle]:
91
+ """Get list of connected fibers."""
92
+ return [self.fiber0, self.fiber1]
93
+
94
+ def __getitem__(self, idx: int) -> Circle:
95
+ """Get fiber by index."""
96
+ if idx not in (0, 1):
97
+ raise IndexError(f"Fiber index must be 0 or 1, got {idx}")
98
+ return self.fibers[idx]
99
+
100
+ def __setitem__(self, idx: int, fiber: Circle) -> None:
101
+ """Set fiber by index."""
102
+ if idx not in (0, 1):
103
+ raise IndexError(f"Fiber index must be 0 or 1, got {idx}")
104
+ if idx == 0:
105
+ self.fiber0 = fiber
106
+ else:
107
+ self.fiber1 = fiber
108
+
109
+ # =============================================================================
110
+ # GEOMETRIC PROPERTIES
111
+ # =============================================================================
112
+
113
+ @property
114
+ def distance_between_cores(self) -> float:
115
+ """Calculate distance between fiber centers."""
116
+ return self.fiber0.center.distance(self.fiber1.center)
117
+
118
+ @property
119
+ def center_line(self) -> ff.LineString:
120
+ """Get line connecting fiber centers."""
121
+ return ff.LineString(coordinates=[self.fiber0.center, self.fiber1.center])
122
+
123
+ @property
124
+ def extended_center_line(self) -> ff.LineString:
125
+ """Get extended line connecting fiber centers."""
126
+ line = self.center_line
127
+ extension = self.fiber0.radius + self.fiber1.radius
128
+ return line.make_length(line.length + extension)
129
+
130
+ @property
131
+ def limit_added_area(self) -> ff.Polygon:
132
+ """Calculate the theoretical maximum added area."""
133
+ union_hull = self.fiber0.union(self.fiber1).convex_hull
134
+ return union_hull - self.fiber0 - self.fiber1
135
+
136
+ @property
137
+ def total_area(self) -> ff.Polygon:
138
+ """Get total area including both fibers and added section."""
139
+ output = utils.union_geometries(self.fiber0, self.fiber1, self.added_section)
140
+ output.remove_non_polygon_elements()
141
+ return output
142
+
143
+ # =============================================================================
144
+ # CONNECTION CONFIGURATION
145
+ # =============================================================================
146
+
147
+ def configure_connection(self, shift: float, topology: TopologyType) -> None:
148
+ """
149
+ Configure connection with shift and topology parameters.
150
+
151
+ Parameters
152
+ ----------
153
+ shift : float
154
+ The shift value for connection geometry.
155
+ topology : TopologyType
156
+ The connection topology type.
157
+ """
158
+ self.shift = shift
159
+ self.topology = topology
160
+
161
+ self._compute_all_geometry()
162
+
163
+ logging.info(f"Configured connection: shift={shift:.3f}, topology={self.topology.value}")
164
+
165
+
166
+ def _compute_all_geometry(self) -> None:
167
+ """Compute all geometric components in correct order."""
168
+ if self.topology == TopologyType.UNDEFINED:
169
+ raise ValueError("Cannot compute geometry with undefined topology")
170
+
171
+ self._compute_virtual_circles()
172
+ self._compute_mask()
173
+ self._compute_added_section()
174
+ self._compute_removed_section()
175
+
176
+ # =============================================================================
177
+ # GEOMETRIC CALCULATIONS
178
+ # =============================================================================
179
+
180
+ def _compute_virtual_circles(self) -> None:
181
+ """Compute conscripted virtual circles based on topology."""
182
+ circle_type = (
183
+ ConscriptedCircleType.EXTERIOR if self.topology == TopologyType.CONCAVE
184
+ else ConscriptedCircleType.INTERIOR
185
+ )
186
+
187
+ primary_circle = self._get_conscripted_circle(circle_type)
188
+ secondary_circle = primary_circle.rotate(
189
+ angle=180,
190
+ origin=self.center_line.mid_point,
191
+ in_place=False
192
+ )
193
+
194
+ self.virtual_circles = (primary_circle, secondary_circle)
195
+
196
+ def _get_conscripted_circle(self, circle_type: ConscriptedCircleType) -> Circle:
197
+ """
198
+ Create conscripted circle based on type.
199
+
200
+ Parameters
201
+ ----------
202
+ circle_type : ConscriptedCircleType
203
+ Type of conscripted circle to create.
204
+
205
+ Returns
206
+ -------
207
+ Circle
208
+ The conscripted circle.
209
+ """
210
+ line = self.center_line
211
+ perpendicular = self.extended_center_line.get_perpendicular().get_vector()
212
+ center_point = line.mid_point.translate(perpendicular * self.shift)
213
+
214
+ base_radius = np.sqrt(self.shift**2 + (line.length / 2)**2)
215
+
216
+ if circle_type == ConscriptedCircleType.EXTERIOR:
217
+ radius = base_radius - self.fiber0.radius
218
+ else: # INTERIOR
219
+ radius = base_radius + self.fiber0.radius
220
+
221
+ return Circle(position=(center_point.x, center_point.y), radius=radius)
222
+
223
+ def _compute_mask(self) -> None:
224
+ """Compute geometric mask for connection."""
225
+ if not self.virtual_circles:
226
+ raise ValueError("Virtual circles must be computed before mask")
227
+
228
+ contact_points = self._get_contact_points()
229
+
230
+ if self.topology == TopologyType.CONCAVE:
231
+ self.mask = self._compute_concave_mask(contact_points)
232
+ else: # CONVEX
233
+ self.mask = self._compute_convex_mask(contact_points)
234
+
235
+ def _get_contact_points(self) -> List[ff.Point]:
236
+ """Get contact points between fibers and virtual circles."""
237
+ if not self.virtual_circles:
238
+ raise ValueError("Virtual circles not computed")
239
+
240
+ v0, v1 = self.virtual_circles
241
+
242
+ contacts = [
243
+ utils.nearest_points_exterior(v0, self.fiber0),
244
+ utils.nearest_points_exterior(v1, self.fiber0),
245
+ utils.nearest_points_exterior(v0, self.fiber1),
246
+ utils.nearest_points_exterior(v1, self.fiber1)
247
+ ]
248
+
249
+ return [ff.Point(position=(p.x, p.y)) for p in contacts]
250
+
251
+ def _compute_concave_mask(self, contact_points: List[ff.Point]) -> ff.Polygon:
252
+ """Compute mask for concave topology."""
253
+ p0, p1, p2, p3 = contact_points
254
+ coordinates = [(p._shapely_object.x, p._shapely_object.y) for p in [p0, p1, p3, p2]]
255
+
256
+ mask = ff.Polygon(coordinates=coordinates)
257
+ v0, v1 = self.virtual_circles
258
+ return mask - v0 - v1
259
+
260
+ def _compute_convex_mask(self, contact_points: List[ff.Point]) -> ff.Polygon:
261
+ """Compute mask for convex topology."""
262
+ p0, p1, p2, p3 = contact_points
263
+ mid_point = self.center_line.mid_point
264
+
265
+ # Create two mask triangles
266
+ coords0 = [(p._shapely_object.x, p._shapely_object.y) for p in [mid_point, p0, p2]]
267
+ coords1 = [(p._shapely_object.x, p._shapely_object.y) for p in [mid_point, p1, p3]]
268
+
269
+ mask0 = ff.Polygon(coordinates=coords0)
270
+ mask1 = ff.Polygon(coordinates=coords1)
271
+
272
+ # Scale masks
273
+ scale_factor = 1000
274
+ mask0.scale(factor=scale_factor, origin=mid_point._shapely_object, in_place=True)
275
+ mask1.scale(factor=scale_factor, origin=mid_point._shapely_object, in_place=True)
276
+
277
+ # Combine masks with virtual circles
278
+ v0, v1 = self.virtual_circles
279
+ combined_mask = utils.union_geometries(mask0, mask1)
280
+ combined_virtual = utils.union_geometries(v0, v1)
281
+
282
+ return combined_mask & combined_virtual
283
+
284
+ def _compute_added_section(self) -> None:
285
+ """Compute the area added during fiber fusion."""
286
+ if not self.virtual_circles or not self.mask:
287
+ raise ValueError("Virtual circles and mask must be computed first")
288
+
289
+ v0, v1 = self.virtual_circles
290
+ base_section = self.mask - self.fiber0 - self.fiber1
291
+
292
+ if self.topology == TopologyType.CONVEX:
293
+ intersection = v0.intersection(v1, in_place=False)
294
+ self.added_section = base_section & intersection
295
+ else: # CONCAVE
296
+ union = v0.union(v1, in_place=False)
297
+ self.added_section = base_section - union
298
+
299
+ self.added_section.remove_non_polygon_elements()
300
+
301
+ def _compute_removed_section(self) -> None:
302
+ """Compute the area removed during fiber fusion."""
303
+ self.removed_section = utils.intersection_geometries(self.fiber0, self.fiber1)
304
+
305
+ # Calculate actual removed area
306
+ total_individual_area = self.fiber0.area + self.fiber1.area
307
+ union_area = utils.union_geometries(self.fiber0, self.fiber1).area
308
+ self.removed_section.Area = total_individual_area - union_area
309
+
310
+ def determine_topology(self) -> TopologyType:
311
+ """
312
+ Automatically determine connection topology based on geometry.
313
+
314
+ Returns
315
+ -------
316
+ TopologyType
317
+ The determined topology type.
318
+ """
319
+ if self.removed_section.Area > self.limit_added_area.area:
320
+ return TopologyType.CONVEX
321
+ else:
322
+ return TopologyType.CONCAVE
323
+
324
+ # =============================================================================
325
+ # GEOMETRY OPERATIONS
326
+ # =============================================================================
327
+
328
+ def split_geometry(self,
329
+ geometry: ff.Polygon,
330
+ position: ff.Point,
331
+ return_largest: bool = True) -> ff.Polygon:
332
+ """
333
+ Split geometry at specified position.
334
+
335
+ Parameters
336
+ ----------
337
+ geometry : ff.Polygon
338
+ Geometry to split.
339
+ position : ff.Point
340
+ Position for splitting.
341
+ return_largest : bool, default True
342
+ Whether to return the largest split section.
343
+
344
+ Returns
345
+ -------
346
+ ff.Polygon
347
+ The split geometry section.
348
+ """
349
+ # Create perpendicular split line
350
+ split_line = self.center_line.centering(center=position)
351
+ split_line = split_line.rotate(angle=90, origin=split_line.mid_point)
352
+ split_line = split_line.extend(factor=2)
353
+
354
+ # Prepare geometry and split
355
+ clean_geometry = (utils.union_geometries(geometry.copy())
356
+ .remove_non_polygon_elements()
357
+ .keep_largest_polygon())
358
+
359
+ return clean_geometry.split_with_line(line=split_line, return_largest=return_largest)
360
+
361
+ # =============================================================================
362
+ # CORE POSITION OPTIMIZATION
363
+ # =============================================================================
364
+
365
+ def optimize_core_positions(self, tolerance: float = 1e-10) -> None:
366
+ """
367
+ Optimize core positions to minimize area mismatch.
368
+
369
+ Parameters
370
+ ----------
371
+ tolerance : float, default 1e-10
372
+ Optimization tolerance.
373
+ """
374
+ logging.info("Starting core position optimization...")
375
+
376
+ result = minimize_scalar(
377
+ self._compute_area_mismatch_cost,
378
+ bounds=(0.50001, 0.99),
379
+ method='bounded',
380
+ options={'xatol': tolerance}
381
+ )
382
+
383
+ if result.success:
384
+ logging.info(f"Optimization successful: cost={result.fun:.2e}")
385
+ # Apply optimized shifts
386
+ if self.core_shift:
387
+ self.fiber0.shifted_core += self.core_shift[0]
388
+ self.fiber1.shifted_core += self.core_shift[1]
389
+ else:
390
+ logging.warning(f"Optimization failed: {result.message}")
391
+
392
+ def _compute_area_mismatch_cost(self, x: float) -> float:
393
+ """
394
+ Compute area mismatch cost for optimization.
395
+
396
+ Parameters
397
+ ----------
398
+ x : float
399
+ Optimization parameter (0 to 1).
400
+
401
+ Returns
402
+ -------
403
+ float
404
+ Cost value to minimize.
405
+ """
406
+ # Get split positions
407
+ line = self.extended_center_line
408
+ position0 = line.get_position_parametrization(1 - x)
409
+ position1 = line.get_position_parametrization(x)
410
+
411
+ # Calculate small section area
412
+ small_section = self.split_geometry(
413
+ geometry=self.total_area,
414
+ position=position0,
415
+ return_largest=False
416
+ )
417
+
418
+ # Compute cost and store shifts
419
+ target_area = self.fiber0.area / 2.0
420
+ cost = abs(small_section.area - target_area)
421
+
422
+ self.core_shift = (
423
+ position0 - self.fiber0.center,
424
+ position1 - self.fiber1.center
425
+ )
426
+
427
+ logging.debug(f"Optimization step: x={x:.3f}, cost={cost:.2e}")
428
+
429
+ return cost
430
+
431
+ # =============================================================================
432
+ # UTILITY METHODS
433
+ # =============================================================================
434
+
435
+ def get_connection_summary(self) -> dict:
436
+ """
437
+ Get summary of connection properties.
438
+
439
+ Returns
440
+ -------
441
+ dict
442
+ Dictionary containing connection summary.
443
+ """
444
+ return {
445
+ 'distance_between_cores': self.distance_between_cores,
446
+ 'topology': self.topology.value,
447
+ 'shift': self.shift,
448
+ 'added_area': self.added_section.area if hasattr(self.added_section, 'area') else 0,
449
+ 'removed_area': getattr(self.removed_section, 'Area', 0),
450
+ 'total_area': self.total_area.area,
451
+ 'fiber0_center': (self.fiber0.center.x, self.fiber0.center.y),
452
+ 'fiber1_center': (self.fiber1.center.x, self.fiber1.center.y),
453
+ }
454
+
455
+ def __repr__(self) -> str:
456
+ """String representation of the connection."""
457
+ return (f"Connection(fiber0=Circle({self.fiber0.center.x:.2f}, {self.fiber0.center.y:.2f}), "
458
+ f"fiber1=Circle({self.fiber1.center.x:.2f}, {self.fiber1.center.y:.2f}), "
459
+ f"topology={self.topology.value})")
@@ -1,9 +1,9 @@
1
- from typing import Tuple
2
1
  import logging
3
2
  from scipy.optimize import minimize_scalar
4
3
  from itertools import combinations
5
- from FiberFusing.connection import Connection
6
- from FiberFusing.buffer import Polygon
4
+ from FiberFusing.connection.connection import Connection
5
+ from FiberFusing.connection.utils import TopologyType
6
+ from FiberFusing.shapes.circle import Polygon
7
7
  from FiberFusing import utils
8
8
 
9
9
 
@@ -70,7 +70,7 @@ class ConnectionOptimization:
70
70
  self._removed_section = self.get_removed_section()
71
71
  return self._removed_section
72
72
 
73
- def iterate_over_connected_fibers(self) -> Tuple:
73
+ def iterate_over_connected_fibers(self):
74
74
  """
75
75
  Generator that iterates over all connected fibers in the structure.
76
76
 
@@ -95,7 +95,7 @@ class ConnectionOptimization:
95
95
  self.virtual_shift = virtual_shift
96
96
  topology = self.get_overall_topology()
97
97
  for connection in self.connected_fibers:
98
- connection.set_shift_and_topology(shift=virtual_shift, topology=topology)
98
+ connection.configure_connection(shift=virtual_shift, topology=topology)
99
99
 
100
100
  def get_added_section(self) -> Polygon:
101
101
  """
@@ -154,7 +154,7 @@ class ConnectionOptimization:
154
154
  limit = [conn.limit_added_area for conn in self.connected_fibers]
155
155
  overall_limit = utils.union_geometries(*limit) - utils.union_geometries(*self.fiber_list)
156
156
  total_removed_area = self.get_removed_area()
157
- return 'convex' if total_removed_area > overall_limit.area else 'concave'
157
+ return TopologyType.CONVEX if total_removed_area > overall_limit.area else TopologyType.CONCAVE
158
158
 
159
159
  def optimize_core_positions(self) -> None:
160
160
  """
@@ -162,7 +162,7 @@ class ConnectionOptimization:
162
162
  """
163
163
  logging.info("Computing the optimal core positions")
164
164
  for connection in self.connected_fibers:
165
- connection.optimize_core_position()
165
+ connection.optimize_core_positions()
166
166
 
167
167
  def get_cost_value(self, virtual_shift: float) -> float:
168
168
  """