PyFiberModes 0.13.1__tar.gz → 0.14.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 (166) hide show
  1. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.github/workflows/quality.yml +1 -0
  2. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.github/workflows/tests.yml +1 -1
  3. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.zenodo.json +6 -3
  4. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/CHANGELOG.md +30 -1
  5. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/CITATION.cff +3 -0
  6. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/CONTRIBUTING.md +1 -1
  7. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/Makefile +1 -0
  8. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PKG-INFO +33 -12
  9. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/__init__.py +38 -3
  10. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/_version.py +2 -2
  11. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/analysis.py +22 -12
  12. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/factory.py +0 -6
  13. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber.py +11 -2
  14. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/field.py +20 -36
  15. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fundamentals.py +83 -28
  16. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/loader.py +37 -14
  17. pyfibermodes-0.14.0/PyFiberModes/materials.py +118 -0
  18. pyfibermodes-0.14.0/PyFiberModes/plotting.py +76 -0
  19. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/services.py +2 -10
  20. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/solver/__init__.py +6 -6
  21. pyfibermodes-0.14.0/PyFiberModes/solver/multilayer/__init__.py +5 -0
  22. pyfibermodes-0.13.1/PyFiberModes/solver/mlsif/neff.py → pyfibermodes-0.14.0/PyFiberModes/solver/multilayer/effective_index.py +162 -51
  23. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/solver/protocols.py +16 -1
  24. {pyfibermodes-0.13.1/PyFiberModes/solver/tlsif → pyfibermodes-0.14.0/PyFiberModes/solver/three_layer}/__init__.py +2 -0
  25. {pyfibermodes-0.13.1/PyFiberModes/solver/tlsif → pyfibermodes-0.14.0/PyFiberModes/solver/three_layer}/cutoff.py +14 -16
  26. pyfibermodes-0.14.0/PyFiberModes/solver/two_layer/__init__.py +6 -0
  27. {pyfibermodes-0.13.1/PyFiberModes/solver/ssif → pyfibermodes-0.14.0/PyFiberModes/solver/two_layer}/cutoff.py +1 -6
  28. pyfibermodes-0.13.1/PyFiberModes/solver/ssif/neff.py → pyfibermodes-0.14.0/PyFiberModes/solver/two_layer/effective_index.py +54 -16
  29. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes.egg-info/PKG-INFO +33 -12
  30. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes.egg-info/SOURCES.txt +26 -11
  31. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes.egg-info/requires.txt +7 -5
  32. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/README.rst +22 -5
  33. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/conda.recipe/meta.yaml +14 -11
  34. pyfibermodes-0.14.0/docs/examples/analysis/plot_guided_mode_discovery.py +22 -0
  35. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_mode_field_1.py +1 -1
  36. pyfibermodes-0.14.0/docs/examples/benchmarks/plot_component_batching_speedup.py +33 -0
  37. pyfibermodes-0.14.0/docs/examples/benchmarks/plot_modal_cache_speedup.py +28 -0
  38. pyfibermodes-0.14.0/docs/examples/fields/plot_confinement_by_radius.py +28 -0
  39. pyfibermodes-0.14.0/docs/examples/fields/plot_polarization_rotation.py +27 -0
  40. pyfibermodes-0.14.0/docs/examples/specialty_fibers/README.rst +7 -0
  41. pyfibermodes-0.14.0/docs/examples/specialty_fibers/plot_refractive_index_profile.py +26 -0
  42. pyfibermodes-0.14.0/docs/examples/specialty_fibers/plot_specialty_fiber_catalog.py +33 -0
  43. pyfibermodes-0.14.0/docs/examples/specialty_fibers/plot_specialty_mode_indices.py +25 -0
  44. pyfibermodes-0.14.0/docs/examples/validation/plot_field_area_convergence.py +26 -0
  45. pyfibermodes-0.14.0/docs/examples/validation/plot_normalized_effective_index.py +31 -0
  46. pyfibermodes-0.14.0/docs/source/api_policy.rst +59 -0
  47. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/architecture.rst +5 -0
  48. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/code/analysis.rst +12 -0
  49. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/code.rst +3 -0
  50. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/conf.py +1 -1
  51. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/examples.rst +2 -2
  52. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/index.rst +2 -0
  53. pyfibermodes-0.14.0/docs/source/migration_guide.rst +69 -0
  54. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/pyproject.toml +32 -10
  55. pyfibermodes-0.14.0/tests/api_snapshot.json +54 -0
  56. pyfibermodes-0.14.0/tests/test_architecture.py +87 -0
  57. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_architecture_enhancements.py +2 -2
  58. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_file_loading.py +15 -3
  59. pyfibermodes-0.14.0/tests/test_public_api.py +44 -0
  60. pyfibermodes-0.14.0/tests/test_three_layer_solver.py +42 -0
  61. pyfibermodes-0.13.1/tests/test_ssif.py → pyfibermodes-0.14.0/tests/test_two_layer_solver.py +1 -1
  62. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_validation.py +1 -1
  63. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tools/check_release.py +1 -4
  64. pyfibermodes-0.13.1/PyFiberModes/solver/mlsif/__init__.py +0 -3
  65. pyfibermodes-0.13.1/PyFiberModes/solver/ssif/__init__.py +0 -4
  66. pyfibermodes-0.13.1/docs/examples/DCF/README.rst +0 -6
  67. pyfibermodes-0.13.1/docs/examples/DCF/plot_DCF_fields.py +0 -35
  68. pyfibermodes-0.13.1/tests/test_architecture.py +0 -36
  69. pyfibermodes-0.13.1/tests/test_tlsif.py +0 -20
  70. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.coveragerc +0 -0
  71. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.github/dependabot.yml +0 -0
  72. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.github/workflows/deploy_PyPi.yml +0 -0
  73. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.github/workflows/deploy_anaconda.yml +0 -0
  74. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.github/workflows/deploy_coverage.yml +0 -0
  75. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.github/workflows/deploy_documentation.yml +0 -0
  76. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/.gitignore +0 -0
  77. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/LICENSE +0 -0
  78. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/MANIFEST.in +0 -0
  79. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/coordinates.py +0 -0
  80. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/directories.py +0 -0
  81. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/exceptions.py +0 -0
  82. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/1550BHP.yaml +0 -0
  83. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/DCF13.yaml +0 -0
  84. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/DCF1300S_20.yaml +0 -0
  85. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/DCF1300S_26.yaml +0 -0
  86. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/DCF1300S_33.yaml +0 -0
  87. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/DCF1300S_42.yaml +0 -0
  88. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/F2028M12.yaml +0 -0
  89. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/F2028M21.yaml +0 -0
  90. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/F2028M24.yaml +0 -0
  91. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/F2058G1.yaml +0 -0
  92. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/F2058L1.yaml +0 -0
  93. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/HI1060.yaml +0 -0
  94. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/HP630.yaml +0 -0
  95. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/SM1950.yaml +0 -0
  96. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/SMF28.yaml +0 -0
  97. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/fluorine_doped_1%_capillary.yaml +0 -0
  98. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/fluorine_doped_2%_capillary.yaml +0 -0
  99. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/test_fiber.yaml +0 -0
  100. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/fiber_files/test_multimode_fiber.yaml +0 -0
  101. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/mode.py +0 -0
  102. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/mode_instances.py +0 -0
  103. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/models.py +0 -0
  104. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/optimization.py +0 -0
  105. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/propagation.py +0 -0
  106. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/solver/base_solver.py +0 -0
  107. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/solver/results.py +0 -0
  108. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/source.py +0 -0
  109. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes/stepindex.py +0 -0
  110. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes.egg-info/dependency_links.txt +0 -0
  111. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/PyFiberModes.egg-info/top_level.txt +0 -0
  112. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/benchmarks/README.md +0 -0
  113. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/benchmarks/test_field_performance.py +0 -0
  114. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/Makefile +0 -0
  115. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/README.rst +0 -0
  116. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/SMF28/README.rst +0 -0
  117. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/SMF28/plot_smf28.py +0 -0
  118. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/SMF28/plot_smf28_dispersion_vs_wavelength.py +0 -0
  119. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/SMF28/plot_smf28_group_index_vs_wavelength.py +0 -0
  120. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/analysis/README.rst +0 -0
  121. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/analysis/plot_coupled_mode_exchange.py +0 -0
  122. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/analysis/plot_structured_wavelength_sweep.py +0 -0
  123. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/README.rst +0 -0
  124. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_U_vs_V.py +0 -0
  125. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_comparison_solvers.py +0 -0
  126. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_dispersion.py +0 -0
  127. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_effective_index.py +0 -0
  128. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_fiber_LP_modes.py +0 -0
  129. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_group_index.py +0 -0
  130. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_mode_field.py +0 -0
  131. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_mode_field_2.py +0 -0
  132. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/basic/plot_neff_tapered_fiber.py +0 -0
  133. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/benchmarks/README.rst +0 -0
  134. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/benchmarks/plot_field_grid_scaling.py +0 -0
  135. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/fields/README.rst +0 -0
  136. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/fields/plot_vector_components.py +0 -0
  137. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/validation/README.rst +0 -0
  138. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/examples/validation/plot_effective_index_bounds.py +0 -0
  139. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/make.bat +0 -0
  140. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/_static/default.css +0 -0
  141. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/_static/favicon.png +0 -0
  142. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/_static/logo.png +0 -0
  143. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/_static/thumbnail.png +0 -0
  144. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/code/fibers.rst +0 -0
  145. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/code/fields.rst +0 -0
  146. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/code/fundamentals.rst +0 -0
  147. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/getting_started.rst +0 -0
  148. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/performance.rst +0 -0
  149. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/references.rst +0 -0
  150. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/theory.rst +0 -0
  151. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/troubleshooting.rst +0 -0
  152. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/docs/source/workflows.rst +0 -0
  153. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/pytest.ini +0 -0
  154. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/setup.cfg +0 -0
  155. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/__init__.py +0 -0
  156. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/helpers.py +0 -0
  157. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_advanced_features.py +0 -0
  158. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_api.py +0 -0
  159. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_coordinates.py +0 -0
  160. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_docstrings.py +0 -0
  161. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_fiber.py +0 -0
  162. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_field.py +0 -0
  163. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_physics_regression.py +0 -0
  164. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tests/test_release_tools.py +0 -0
  165. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tools/next_release_version.py +0 -0
  166. {pyfibermodes-0.13.1 → pyfibermodes-0.14.0}/tools/release_tag.py +0 -0
@@ -19,4 +19,5 @@ jobs:
19
19
  python-version: "3.11"
20
20
  - run: python -m pip install --upgrade pip && python -m pip install -e ".[dev]"
21
21
  - run: python -m ruff check PyFiberModes tests tools
22
+ - run: python -m mypy
22
23
  - run: python tools/check_release.py
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- python-version: ["3.10", "3.11", "3.12", "3.13"]
19
+ python-version: ["3.11", "3.12", "3.13"]
20
20
  steps:
21
21
  - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09
22
22
  - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "title": "PyFiberModes: guided-mode analysis and design for optical fibers",
3
- "description": "PyFiberModes solves guided modes in circularly symmetric step-index and multilayer optical fibers, including field analysis, modal sweeps, inverse design, and coupled-mode propagation.",
3
+ "description": "Guided-mode analysis and design for circular optical fibers, with field analysis, dispersion, modal sweeps, inverse design, and coupled-mode propagation.",
4
4
  "creators": [
5
5
  {
6
6
  "name": "Poinsinet de Sivry-Houle, Martin"
@@ -9,11 +9,14 @@
9
9
  "license": "MIT",
10
10
  "upload_type": "software",
11
11
  "access_right": "open",
12
- "version": "0.13.1",
13
- "publication_date": "2026-09-22",
12
+ "version": "0.14.0",
13
+ "publication_date": "2026-09-23",
14
14
  "keywords": [
15
15
  "optical fibers",
16
16
  "guided modes",
17
+ "mode solver",
18
+ "optical waveguides",
19
+ "photonics",
17
20
  "effective index",
18
21
  "dispersion",
19
22
  "coupled-mode theory"
@@ -6,6 +6,33 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.14.0] - 2026-09-23
10
+
11
+ ### Added
12
+
13
+ - Expanded the specialty-fiber, field, analysis, validation, and performance
14
+ galleries so every documentation series contains multiple examples.
15
+ - Defined a stable root-level public API, compatibility and deprecation policy,
16
+ API snapshot regression test, and migration guide.
17
+
18
+ ### Changed
19
+
20
+ - Replaced the opaque `ssif`, `tlsif`, `mlsif`, and `NeffSolver` names with
21
+ descriptive two-layer, three-layer, multilayer, and effective-index solver
22
+ namespaces and class names.
23
+
24
+ ## [0.13.2] - 2026-09-23
25
+
26
+ ### Changed
27
+
28
+ - Raised the minimum supported Python version to 3.11 and aligned CI,
29
+ contributor guidance, Ruff, and Conda metadata with that policy.
30
+ - Moved Matplotlib rendering into the optional `PyFiberModes.plotting` module
31
+ and added the `plotting` installation extra, keeping it out of core runtime
32
+ dependencies while preserving the `Field.plot` convenience method.
33
+ - Replaced generic package descriptions and keywords with fiber-mode,
34
+ photonics, waveguide, dispersion, and coupled-mode metadata.
35
+
9
36
  ## [0.13.1] - 2026-09-22
10
37
 
11
38
  ### Added
@@ -74,7 +101,9 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
74
101
 
75
102
  - Established the current tagged baseline for subsequent documented releases.
76
103
 
77
- [Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/v0.13.1...HEAD
104
+ [Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/v0.14.0...HEAD
105
+ [0.14.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.14.0
106
+ [0.13.2]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.13.2
78
107
  [0.13.1]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.13.1
79
108
  [0.13.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.13.0
80
109
  [0.12.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.12.0
@@ -14,6 +14,9 @@ url: "https://martinpdes.github.io/PyFiberModes/"
14
14
  keywords:
15
15
  - optical fibers
16
16
  - guided modes
17
+ - mode solver
18
+ - optical waveguides
19
+ - photonics
17
20
  - effective index
18
21
  - dispersion
19
22
  - coupled-mode theory
@@ -1,6 +1,6 @@
1
1
  # Contributing to PyFiberModes
2
2
 
3
- Use Python 3.10 or newer. Install development dependencies with `python -m pip install -e ".[testing,documentation]"`, then run `python -m pytest`.
3
+ Use Python 3.11 or newer. Install development dependencies with `python -m pip install -e ".[testing,documentation]"`, then run `python -m pytest`.
4
4
 
5
5
  Releases use semantic version tags. Run `make patch`, `make minor`, or `make major` from a clean `master` checkout; the command creates the release commit, tags it, and pushes both. Publishing workflows run only for `v*` tags.
6
6
 
@@ -31,6 +31,7 @@ test:
31
31
 
32
32
  quality:
33
33
  $(PYTHON) -m ruff check PyFiberModes tests tools
34
+ $(PYTHON) -m mypy
34
35
 
35
36
  release-check:
36
37
  $(PYTHON) tools/check_release.py $(if $(VERSION),--version $(VERSION),)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyFiberModes
3
- Version: 0.13.1
4
- Summary: A package for light propagation in fiber optics.
3
+ Version: 0.14.0
4
+ Summary: Guided-mode analysis and design for circular optical fibers.
5
5
  Author-email: Martin Poinsinet de Sivry-Houle <martin.poinsinet.de.sivry@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
7
7
  Version 3, 29 June 2007
@@ -682,9 +682,10 @@ Project-URL: Homepage, https://github.com/MartinPdeS/PyFiberModes
682
682
  Project-URL: Repository, https://github.com/MartinPdeS/PyFiberModes
683
683
  Project-URL: Issues, https://github.com/MartinPdeS/PyFiberModes/issues
684
684
  Project-URL: Documentation, https://martinpdes.github.io/PyFiberModes/
685
- Keywords: finit-difference,matrix
685
+ Keywords: fiber optics,guided modes,mode solver,optical waveguides,photonics,dispersion,coupled-mode theory
686
686
  Classifier: Programming Language :: Python
687
687
  Classifier: Programming Language :: Python :: 3
688
+ Classifier: Programming Language :: Python :: 3 :: Only
688
689
  Classifier: Programming Language :: Python :: 3.11
689
690
  Classifier: Programming Language :: Python :: 3.12
690
691
  Classifier: Programming Language :: Python :: 3.13
@@ -693,12 +694,10 @@ Classifier: Development Status :: 4 - Beta
693
694
  Classifier: Topic :: Scientific/Engineering :: Physics
694
695
  Classifier: License :: OSI Approved :: MIT License
695
696
  Classifier: Intended Audience :: Science/Research
696
- Requires-Python: >=3.10
697
+ Requires-Python: >=3.11
697
698
  Description-Content-Type: text/x-rst
698
699
  License-File: LICENSE
699
- Requires-Dist: PyOptik<3,>=2
700
700
  Requires-Dist: PyFinitDiff
701
- Requires-Dist: matplotlib>=3.8
702
701
  Requires-Dist: pyyaml
703
702
  Requires-Dist: numpy
704
703
  Requires-Dist: scipy
@@ -708,10 +707,14 @@ Requires-Dist: pytest-cov<8,>=2; extra == "testing"
708
707
  Requires-Dist: pytest-json-report~=1.5; extra == "testing"
709
708
  Requires-Dist: coverage~=7.6; extra == "testing"
710
709
  Requires-Dist: ruff<1,>=0.8; extra == "testing"
711
- Requires-Dist: tomli<3,>=2; python_version < "3.11" and extra == "testing"
710
+ Requires-Dist: matplotlib>=3.8; extra == "testing"
711
+ Requires-Dist: mypy<2,>=1.15; extra == "testing"
712
+ Provides-Extra: plotting
713
+ Requires-Dist: matplotlib>=3.8; extra == "plotting"
712
714
  Provides-Extra: benchmarking
713
715
  Requires-Dist: pytest-benchmark<6,>=5; extra == "benchmarking"
714
716
  Provides-Extra: documentation
717
+ Requires-Dist: matplotlib>=3.8; extra == "documentation"
715
718
  Requires-Dist: numpydoc==1.10.0; extra == "documentation"
716
719
  Requires-Dist: sphinx>=5.1.1; extra == "documentation"
717
720
  Requires-Dist: sphinx-gallery==0.21.0; extra == "documentation"
@@ -720,6 +723,7 @@ Requires-Dist: sphinx-rtd-theme==3.1.0; extra == "documentation"
720
723
  Requires-Dist: pydata-sphinx-theme==0.17.1; extra == "documentation"
721
724
  Provides-Extra: dev
722
725
  Requires-Dist: ruff<1,>=0.8; extra == "dev"
726
+ Requires-Dist: mypy<2,>=1.15; extra == "dev"
723
727
  Dynamic: license-file
724
728
 
725
729
  .. image:: https://raw.githubusercontent.com/MartinPdeS/PyFiberModes/master/docs/source/_static/logo.png
@@ -784,13 +788,19 @@ Features
784
788
  Installation
785
789
  ------------
786
790
 
787
- PyFiberModes requires Python 3.10 or newer. Install the released package from
791
+ PyFiberModes requires Python 3.11 or newer. Install the released package from
788
792
  PyPI:
789
793
 
790
794
  .. code-block:: bash
791
795
 
792
796
  python -m pip install PyFiberModes
793
797
 
798
+ Matplotlib-based field visualizations are optional:
799
+
800
+ .. code-block:: bash
801
+
802
+ python -m pip install "PyFiberModes[plotting]"
803
+
794
804
  or from Anaconda:
795
805
 
796
806
  .. code-block:: bash
@@ -804,9 +814,9 @@ simulations:
804
814
 
805
815
  python -c "import PyFiberModes; print(PyFiberModes.__version__)"
806
816
 
807
- PyFiberModes currently uses the ``MaterialBank`` interface provided by
808
- PyOptik 2.x. Released dependency metadata selects the compatible
809
- ``PyOptik>=2,<3`` range automatically.
817
+ Fiber material names are resolved through a lightweight, pluggable registry.
818
+ PyOptik is not required; applications can register their own dispersive model
819
+ objects or simple wavelength-to-index callables.
810
820
 
811
821
  First mode calculation
812
822
  ----------------------
@@ -1003,6 +1013,17 @@ contains the API reference and executable example gallery, including:
1003
1013
  * double-clad fiber field analysis; and
1004
1014
  * comparisons between supported analytical solvers.
1005
1015
 
1016
+ API stability
1017
+ -------------
1018
+
1019
+ Supported imports come from the package root, for example
1020
+ ``from PyFiberModes import Fiber, LP01``. The
1021
+ `public API policy <https://martinpdes.github.io/PyFiberModes/latest/api_policy.html>`_
1022
+ defines compatibility guarantees and the deprecation period. Review the
1023
+ `migration guide <https://martinpdes.github.io/PyFiberModes/latest/migration_guide.html>`_
1024
+ when upgrading across minor or major versions. Internal solver modules are not
1025
+ covered by the compatibility guarantee.
1026
+
1006
1027
  Development and testing
1007
1028
  -----------------------
1008
1029
 
@@ -1028,7 +1049,7 @@ Or run the complete local check target:
1028
1049
 
1029
1050
  make check
1030
1051
 
1031
- Tests run on Python 3.10 through 3.13 in GitHub Actions. Bug reports and
1052
+ Tests run on Python 3.11 through 3.13 in GitHub Actions. Bug reports and
1032
1053
  feature proposals are welcome through the
1033
1054
  `issue tracker <https://github.com/MartinPdeS/PyFiberModes/issues>`_.
1034
1055
 
@@ -1,7 +1,27 @@
1
1
  """Public API for circular optical-fiber mode analysis."""
2
2
 
3
- from PyFiberModes.mode import Mode, Family # noqa: F401
4
- from PyFiberModes.mode_instances import * # noqa: F403
3
+ from PyFiberModes.mode import Family, Mode
4
+ from PyFiberModes.mode_instances import (
5
+ EH11,
6
+ HE11,
7
+ HE12,
8
+ HE21,
9
+ HE22,
10
+ HE31,
11
+ HE32,
12
+ LP01,
13
+ LP02,
14
+ LP03,
15
+ LP11,
16
+ LP12,
17
+ LP21,
18
+ LP22,
19
+ LP31,
20
+ LP32,
21
+ LP41,
22
+ TE01,
23
+ TM01,
24
+ )
5
25
  from PyFiberModes.factory import FiberFactory
6
26
  from PyFiberModes.fiber import Fiber, load_fiber
7
27
  from PyFiberModes.field import Field
@@ -12,6 +32,13 @@ from PyFiberModes.solver.results import SolverResult
12
32
  from PyFiberModes.analysis import ModeSweepResult, find_modes, sweep_modes
13
33
  from PyFiberModes.optimization import DesignParameter, DesignResult, optimize_fiber
14
34
  from PyFiberModes.propagation import CoupledModeSystem, PropagationResult, coupling_matrix, overlap
35
+ from PyFiberModes.materials import (
36
+ CallableIndex,
37
+ ConstantIndex,
38
+ FusedSilica,
39
+ MaterialRegistry,
40
+ RefractiveIndexModel,
41
+ )
15
42
 
16
43
 
17
44
  try:
@@ -21,7 +48,7 @@ except ImportError:
21
48
  __version__ = "0.0.0"
22
49
 
23
50
 
24
- __all__ = [ # noqa: F405
51
+ __all__ = [
25
52
  'Mode',
26
53
  'Family',
27
54
  'Fiber',
@@ -34,10 +61,17 @@ __all__ = [ # noqa: F405
34
61
  'ModeSweepResult', 'find_modes', 'sweep_modes',
35
62
  'DesignParameter', 'DesignResult', 'optimize_fiber',
36
63
  'CoupledModeSystem', 'PropagationResult', 'coupling_matrix', 'overlap',
64
+ 'RefractiveIndexModel', 'ConstantIndex', 'CallableIndex', 'FusedSilica',
65
+ 'MaterialRegistry',
37
66
  'HE11',
38
67
  'HE12',
68
+ 'HE21',
39
69
  'HE22',
40
70
  'HE31',
71
+ 'HE32',
72
+ 'EH11',
73
+ 'TE01',
74
+ 'TM01',
41
75
  'LP01',
42
76
  'LP11',
43
77
  'LP21',
@@ -47,4 +81,5 @@ __all__ = [ # noqa: F405
47
81
  'LP22',
48
82
  'LP03',
49
83
  'LP32',
84
+ 'LP41',
50
85
  ]
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.13.1'
22
- __version_tuple__ = version_tuple = (0, 13, 1)
21
+ __version__ = version = '0.14.0'
22
+ __version_tuple__ = version_tuple = (0, 14, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -64,7 +64,7 @@ class ModeSweepResult:
64
64
  index = self.modes.index(mode)
65
65
  return {name: value[:, index] for name, value in self.values.items()}
66
66
 
67
- def as_records(self) -> list[dict]:
67
+ def as_records(self) -> list[dict[str, float | Mode]]:
68
68
  """Convert the dense result into row-oriented records.
69
69
 
70
70
  Returns
@@ -133,9 +133,13 @@ def find_modes(fiber, families=("LP",), max_nu=6, max_m=6) -> tuple[Mode, ...]:
133
133
  found = []
134
134
  for mode in candidate_modes(families, max_nu, max_m):
135
135
  try:
136
- neff = fiber.get_effective_index(mode)
137
- guided = fiber.last_layer.refractive_index < neff <= fiber.maximum_index
138
- if np.isfinite(neff) and guided:
136
+ effective_index = fiber.get_effective_index(mode)
137
+ guided = (
138
+ fiber.last_layer.refractive_index
139
+ < effective_index
140
+ <= fiber.maximum_index
141
+ )
142
+ if np.isfinite(effective_index) and guided:
139
143
  found.append(mode)
140
144
  except (ArithmeticError, AssertionError, RuntimeError, ValueError):
141
145
  continue
@@ -191,7 +195,6 @@ def sweep_modes(
191
195
  parameters = np.asarray(tuple(parameters), dtype=float)
192
196
  if parameters.ndim != 1 or not len(parameters):
193
197
  raise ValueError("parameters must be a non-empty one-dimensional sequence")
194
- working_fiber = deepcopy(fiber)
195
198
  if setter is None:
196
199
  if parameter_name != "wavelength":
197
200
  raise ValueError("a setter is required for non-wavelength sweeps")
@@ -202,19 +205,26 @@ def sweep_modes(
202
205
  if modes is None:
203
206
  discovered = []
204
207
  for parameter in parameters:
205
- setter(working_fiber, float(parameter))
206
- for mode in find_modes(working_fiber, families, max_nu, max_m):
208
+ parameter_fiber = deepcopy(fiber)
209
+ setter(parameter_fiber, float(parameter))
210
+ for mode in find_modes(parameter_fiber, families, max_nu, max_m):
207
211
  if mode not in discovered:
208
212
  discovered.append(mode)
209
213
  modes = discovered
210
214
  modes = tuple(modes)
211
215
  values = {metric: np.full((len(parameters), len(modes)), np.nan) for metric in metrics}
212
- for i, parameter in enumerate(parameters):
213
- setter(working_fiber, float(parameter))
214
- for j, mode in enumerate(modes):
215
- for metric in metrics:
216
+ parameter_fibers = tuple(deepcopy(fiber) for _ in parameters)
217
+ for parameter_fiber, parameter in zip(parameter_fibers, parameters, strict=True):
218
+ setter(parameter_fiber, float(parameter))
219
+
220
+ for i, parameter_fiber in enumerate(parameter_fibers):
221
+ metric_functions = {
222
+ metric: getattr(parameter_fiber, f"get_{metric}") for metric in metrics
223
+ }
224
+ for metric, metric_function in metric_functions.items():
225
+ for j, mode in enumerate(modes):
216
226
  try:
217
- value = getattr(working_fiber, f"get_{metric}")(mode)
227
+ value = metric_function(mode)
218
228
  values[metric][i, j] = value if np.isfinite(value) else np.nan
219
229
  except (ArithmeticError, AssertionError, RuntimeError, ValueError):
220
230
  pass
@@ -55,10 +55,6 @@ class FiberFactory:
55
55
  ----------
56
56
  layers_list : list[ProxyLayer]
57
57
  List of ProxyLayer objects representing the layers of the fiber.
58
- neff_solver : None
59
- Placeholder for a solver object (if required).
60
- cutoff_solver : None
61
- Placeholder for a cutoff solver object (if required).
62
58
  wavelength : float
63
59
  Wavelength used in simulations.
64
60
  """
@@ -72,8 +68,6 @@ class FiberFactory:
72
68
  Vacuum wavelength in meters for generated fibers.
73
69
  """
74
70
  self.layers_list = []
75
- self.neff_solver = None
76
- self.cutoff_solver = None
77
71
  self.wavelength = wavelength
78
72
 
79
73
  def add_layer(self, index: float, name: str = "", radius: float = 0.0):
@@ -22,6 +22,7 @@ from PyFiberModes.fundamentals import (
22
22
  from PyFiberModes import loader
23
23
  from PyFiberModes.coordinates import CylindricalCoordinates
24
24
  from PyFiberModes.exceptions import ValidationError
25
+ from PyFiberModes.materials import DEFAULT_MATERIALS, MaterialRegistry
25
26
  from PyFiberModes.services import FieldAnalysis, ModalAnalysis
26
27
 
27
28
 
@@ -1004,7 +1005,12 @@ def get_fiber_from_delta_and_V0(delta: float, V0: float, wavelength: float) -> F
1004
1005
  return fiber
1005
1006
 
1006
1007
 
1007
- def load_fiber(fiber_name: str, wavelength: float = None, add_air_layer: bool = False) -> Fiber:
1008
+ def load_fiber(
1009
+ fiber_name: str,
1010
+ wavelength: float | None = None,
1011
+ add_air_layer: bool = False,
1012
+ materials: MaterialRegistry = DEFAULT_MATERIALS,
1013
+ ) -> Fiber:
1008
1014
  """Load a named YAML fiber definition.
1009
1015
 
1010
1016
  Parameters
@@ -1015,6 +1021,8 @@ def load_fiber(fiber_name: str, wavelength: float = None, add_air_layer: bool =
1015
1021
  Vacuum wavelength in meters used to evaluate material indices.
1016
1022
  add_air_layer : bool, optional
1017
1023
  Add an outer air layer when true.
1024
+ materials : MaterialRegistry, optional
1025
+ Registry used to resolve material names in the YAML definition.
1018
1026
 
1019
1027
  Returns
1020
1028
  -------
@@ -1024,7 +1032,8 @@ def load_fiber(fiber_name: str, wavelength: float = None, add_air_layer: bool =
1024
1032
  fiber_dict = loader.load_fiber_as_dict(
1025
1033
  fiber_name=fiber_name,
1026
1034
  wavelength=wavelength,
1027
- order='out-to-in'
1035
+ order='out-to-in',
1036
+ materials=materials,
1028
1037
  )
1029
1038
 
1030
1039
  fiber = Fiber(wavelength=wavelength)
@@ -1,24 +1,16 @@
1
1
  """Vectorized electric and magnetic field evaluation on Cartesian grids."""
2
2
 
3
3
  import numpy
4
- from typing import Callable
4
+ from typing import Any, Callable
5
5
  import scipy
6
6
  import numpy as np
7
7
  from PyFiberModes.mode_instances import HE11
8
8
  from PyFiberModes.mode import Mode
9
9
  from dataclasses import dataclass
10
- import matplotlib.pyplot as plt
11
- from matplotlib.colors import LinearSegmentedColormap
12
10
  from PyFiberModes.coordinates import CartesianCoordinates
13
11
  from PyFiberModes.coordinates import CylindricalCoordinates as CylindricalCoordinates # noqa: F401
14
12
 
15
13
 
16
- BLUE_BLACK_RED = LinearSegmentedColormap.from_list(
17
- "blue_black_red",
18
- ("#2455a4", "#000000", "#d73027"),
19
- )
20
-
21
-
22
14
  @dataclass
23
15
  class Field:
24
16
  """
@@ -1167,10 +1159,12 @@ class Field:
1167
1159
  return overlap(self, other)
1168
1160
 
1169
1161
  def plot(
1170
- self, plot_type: list = (), show: bool = True, save_filename: str = None
1171
- ) -> plt.Figure:
1172
- """
1173
- Plotting function.
1162
+ self,
1163
+ plot_type: list[str] | tuple[str, ...] = (),
1164
+ show: bool = True,
1165
+ save_filename: str | None = None,
1166
+ ) -> Any:
1167
+ """Plot selected field components using the optional plotting layer.
1174
1168
 
1175
1169
  Parameters
1176
1170
  ----------
@@ -1184,32 +1178,22 @@ class Field:
1184
1178
 
1185
1179
  Returns
1186
1180
  -------
1187
- plt.Figure
1181
+ matplotlib.figure.Figure
1188
1182
  The matplotlib Figure object created or used for the plot.
1189
- """
1190
- with plt.style.context("default"):
1191
- figure, axes = plt.subplots(1, len(plot_type))
1192
-
1193
- axes = np.atleast_1d(axes)
1194
- fields = self.get_components(components=plot_type)
1195
- for ax, field_string in zip(axes, plot_type):
1196
- ax.set_aspect("equal")
1197
- field = fields[field_string]
1198
- field = numpy.real_if_close(field)
1199
- if numpy.iscomplexobj(field):
1200
- field = numpy.abs(field)
1201
- max_abs = abs(max(field.max(), field.min()))
1202
- ax.pcolormesh(field, vmin=-max_abs, vmax=max_abs, cmap=BLUE_BLACK_RED)
1203
1183
 
1204
- figure.tight_layout()
1205
-
1206
- if save_filename:
1207
- figure.savefig(save_filename)
1208
-
1209
- if show:
1210
- plt.show()
1184
+ Raises
1185
+ ------
1186
+ ImportError
1187
+ If the optional plotting dependencies are not installed.
1188
+ """
1189
+ from PyFiberModes.plotting import plot_field
1211
1190
 
1212
- return figure
1191
+ return plot_field(
1192
+ self,
1193
+ plot_type=plot_type,
1194
+ show=show,
1195
+ save_filename=save_filename,
1196
+ )
1213
1197
 
1214
1198
 
1215
1199
  # -