PyFiberModes 0.12.0__tar.gz → 0.13.1__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.
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.gitignore +2 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.zenodo.json +1 -1
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/CHANGELOG.md +36 -1
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PKG-INFO +17 -6
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/__init__.py +13 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/_version.py +2 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/analysis.py +113 -4
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/coordinates.py +12 -7
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/directories.py +0 -12
- pyfibermodes-0.13.1/PyFiberModes/exceptions.py +17 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/factory.py +10 -3
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber.py +421 -222
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/field.py +223 -104
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fundamentals.py +4 -5
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/loader.py +1 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/mode.py +26 -21
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/mode_instances.py +1 -2
- pyfibermodes-0.13.1/PyFiberModes/models.py +63 -0
- pyfibermodes-0.13.1/PyFiberModes/optimization.py +173 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/propagation.py +96 -3
- pyfibermodes-0.13.1/PyFiberModes/services.py +162 -0
- pyfibermodes-0.13.1/PyFiberModes/solver/__init__.py +18 -0
- pyfibermodes-0.13.1/PyFiberModes/solver/base_solver.py +329 -0
- pyfibermodes-0.13.1/PyFiberModes/solver/mlsif/__init__.py +3 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/mlsif/neff.py +211 -182
- pyfibermodes-0.13.1/PyFiberModes/solver/protocols.py +32 -0
- pyfibermodes-0.13.1/PyFiberModes/solver/results.py +56 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/ssif/__init__.py +2 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/ssif/cutoff.py +63 -4
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/ssif/neff.py +225 -158
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/tlsif/__init__.py +2 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/tlsif/cutoff.py +167 -66
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/source.py +16 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/stepindex.py +33 -16
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/PKG-INFO +17 -6
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/SOURCES.txt +32 -1
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/requires.txt +9 -5
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/README.rst +8 -0
- pyfibermodes-0.13.1/benchmarks/README.md +11 -0
- pyfibermodes-0.13.1/benchmarks/test_field_performance.py +32 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/conda.recipe/meta.yaml +1 -2
- pyfibermodes-0.13.1/docs/examples/analysis/README.rst +6 -0
- pyfibermodes-0.13.1/docs/examples/analysis/plot_coupled_mode_exchange.py +22 -0
- pyfibermodes-0.13.1/docs/examples/analysis/plot_structured_wavelength_sweep.py +27 -0
- pyfibermodes-0.13.1/docs/examples/benchmarks/README.rst +7 -0
- pyfibermodes-0.13.1/docs/examples/benchmarks/plot_field_grid_scaling.py +28 -0
- pyfibermodes-0.13.1/docs/examples/fields/README.rst +7 -0
- pyfibermodes-0.13.1/docs/examples/fields/plot_vector_components.py +24 -0
- pyfibermodes-0.13.1/docs/examples/validation/README.rst +7 -0
- pyfibermodes-0.13.1/docs/examples/validation/plot_effective_index_bounds.py +25 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/source/_static/default.css +21 -1
- pyfibermodes-0.13.1/docs/source/_static/favicon.png +0 -0
- pyfibermodes-0.13.1/docs/source/_static/logo.png +0 -0
- pyfibermodes-0.13.1/docs/source/_static/thumbnail.png +0 -0
- pyfibermodes-0.13.1/docs/source/architecture.rst +37 -0
- pyfibermodes-0.13.1/docs/source/code/analysis.rst +26 -0
- pyfibermodes-0.13.1/docs/source/code/fibers.rst +15 -0
- pyfibermodes-0.13.1/docs/source/code/fields.rst +11 -0
- pyfibermodes-0.13.1/docs/source/code/fundamentals.rst +22 -0
- pyfibermodes-0.13.1/docs/source/code.rst +42 -0
- pyfibermodes-0.13.1/docs/source/conf.py +193 -0
- pyfibermodes-0.13.1/docs/source/examples.rst +73 -0
- pyfibermodes-0.13.1/docs/source/getting_started.rst +34 -0
- pyfibermodes-0.13.1/docs/source/index.rst +23 -0
- pyfibermodes-0.13.1/docs/source/performance.rst +20 -0
- pyfibermodes-0.13.1/docs/source/references.rst +12 -0
- pyfibermodes-0.13.1/docs/source/theory.rst +34 -0
- pyfibermodes-0.13.1/docs/source/troubleshooting.rst +33 -0
- pyfibermodes-0.13.1/docs/source/workflows.rst +35 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/pyproject.toml +11 -6
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_api.py +2 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_architecture.py +17 -8
- pyfibermodes-0.13.1/tests/test_architecture_enhancements.py +86 -0
- pyfibermodes-0.13.1/tests/test_docstrings.py +34 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_field.py +50 -3
- pyfibermodes-0.13.1/tests/test_physics_regression.py +41 -0
- pyfibermodes-0.12.0/PyFiberModes/__future__.py +0 -108
- pyfibermodes-0.12.0/PyFiberModes/optimization.py +0 -86
- pyfibermodes-0.12.0/PyFiberModes/solver/__init__.py +0 -3
- pyfibermodes-0.12.0/PyFiberModes/solver/base_solver.py +0 -184
- pyfibermodes-0.12.0/PyFiberModes/solver/mlsif/__init__.py +0 -1
- pyfibermodes-0.12.0/docs/source/_static/thumbnail.png +0 -0
- pyfibermodes-0.12.0/docs/source/code.rst +0 -55
- pyfibermodes-0.12.0/docs/source/conf.py +0 -177
- pyfibermodes-0.12.0/docs/source/examples.rst +0 -14
- pyfibermodes-0.12.0/docs/source/index.rst +0 -14
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.coveragerc +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.github/dependabot.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.github/workflows/deploy_PyPi.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.github/workflows/deploy_anaconda.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.github/workflows/deploy_coverage.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.github/workflows/deploy_documentation.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.github/workflows/quality.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/.github/workflows/tests.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/CITATION.cff +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/CONTRIBUTING.md +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/LICENSE +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/MANIFEST.in +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/Makefile +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/1550BHP.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF13.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF1300S_20.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF1300S_26.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF1300S_33.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF1300S_42.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2028M12.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2028M21.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2028M24.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2058G1.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2058L1.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/HI1060.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/HP630.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/SM1950.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/SMF28.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/fluorine_doped_1%_capillary.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/fluorine_doped_2%_capillary.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/test_fiber.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/test_multimode_fiber.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/dependency_links.txt +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/top_level.txt +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/Makefile +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/DCF/README.rst +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/DCF/plot_DCF_fields.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/README.rst +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/SMF28/README.rst +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/SMF28/plot_smf28.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/SMF28/plot_smf28_dispersion_vs_wavelength.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/SMF28/plot_smf28_group_index_vs_wavelength.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/README.rst +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_U_vs_V.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_comparison_solvers.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_dispersion.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_effective_index.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_fiber_LP_modes.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_group_index.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_mode_field.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_mode_field_1.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_mode_field_2.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_neff_tapered_fiber.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/docs/make.bat +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/pytest.ini +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/setup.cfg +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/__init__.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/helpers.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_advanced_features.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_coordinates.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_fiber.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_file_loading.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_release_tools.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_ssif.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_tlsif.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tests/test_validation.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tools/check_release.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tools/next_release_version.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.1}/tools/release_tag.py +0 -0
|
@@ -6,6 +6,39 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.13.1] - 2026-09-22
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added validated immutable layer and solver settings, structural solver
|
|
14
|
+
protocols, domain-specific exceptions, and structured solver diagnostics.
|
|
15
|
+
- Added deterministic physical-reference, convergence, caching, architecture,
|
|
16
|
+
and opt-in `pytest-benchmark` performance suites.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Unified cylindrical coordinates under one canonical model, split modal and
|
|
21
|
+
field orchestration into focused services, and added geometry-aware caching.
|
|
22
|
+
- Vectorized radial index lookup and routed field construction through a
|
|
23
|
+
single batched radial-field interface.
|
|
24
|
+
- Standardized the group-velocity API on `get_group_velocity` and removed
|
|
25
|
+
unreferenced experimental modules, unfinished solver branches, misspelled
|
|
26
|
+
methods, lowercase directory aliases, and obsolete compatibility wrappers.
|
|
27
|
+
|
|
28
|
+
## [0.13.0] - 2026-09-22
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Replaced MPSPlots styling and colormaps with native Matplotlib equivalents,
|
|
33
|
+
removing MPSPlots from all runtime and documentation dependencies.
|
|
34
|
+
- Field maps now share one radial solver pass across all electric and magnetic
|
|
35
|
+
components and cache interpolated, azimuthal, and batched component arrays.
|
|
36
|
+
- Added NumPyDoc documentation across modules, public APIs, data models, and
|
|
37
|
+
numerical solver helpers, with structural coverage enforced by tests.
|
|
38
|
+
- Reorganized the documentation into learning, theory, workflow, performance,
|
|
39
|
+
troubleshooting, gallery, and task-oriented API sections; added four new
|
|
40
|
+
example series and a unified logo and favicon identity.
|
|
41
|
+
|
|
9
42
|
## [0.12.0] - 2026-09-22
|
|
10
43
|
|
|
11
44
|
### Changed
|
|
@@ -41,7 +74,9 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
41
74
|
|
|
42
75
|
- Established the current tagged baseline for subsequent documented releases.
|
|
43
76
|
|
|
44
|
-
[Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/v0.
|
|
77
|
+
[Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/v0.13.1...HEAD
|
|
78
|
+
[0.13.1]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.13.1
|
|
79
|
+
[0.13.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.13.0
|
|
45
80
|
[0.12.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.12.0
|
|
46
81
|
[0.11.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.11.0
|
|
47
82
|
[0.10.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.10.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyFiberModes
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.1
|
|
4
4
|
Summary: A package for light propagation in fiber optics.
|
|
5
5
|
Author-email: Martin Poinsinet de Sivry-Houle <martin.poinsinet.de.sivry@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -697,28 +697,36 @@ Requires-Python: >=3.10
|
|
|
697
697
|
Description-Content-Type: text/x-rst
|
|
698
698
|
License-File: LICENSE
|
|
699
699
|
Requires-Dist: PyOptik<3,>=2
|
|
700
|
-
Requires-Dist: MPSPlots
|
|
701
700
|
Requires-Dist: PyFinitDiff
|
|
701
|
+
Requires-Dist: matplotlib>=3.8
|
|
702
702
|
Requires-Dist: pyyaml
|
|
703
703
|
Requires-Dist: numpy
|
|
704
704
|
Requires-Dist: scipy
|
|
705
705
|
Provides-Extra: testing
|
|
706
|
-
Requires-Dist: pytest<
|
|
706
|
+
Requires-Dist: pytest<10.0,>=7.4; extra == "testing"
|
|
707
707
|
Requires-Dist: pytest-cov<8,>=2; extra == "testing"
|
|
708
708
|
Requires-Dist: pytest-json-report~=1.5; extra == "testing"
|
|
709
709
|
Requires-Dist: coverage~=7.6; extra == "testing"
|
|
710
710
|
Requires-Dist: ruff<1,>=0.8; extra == "testing"
|
|
711
711
|
Requires-Dist: tomli<3,>=2; python_version < "3.11" and extra == "testing"
|
|
712
|
+
Provides-Extra: benchmarking
|
|
713
|
+
Requires-Dist: pytest-benchmark<6,>=5; extra == "benchmarking"
|
|
712
714
|
Provides-Extra: documentation
|
|
713
|
-
Requires-Dist: numpydoc==1.
|
|
715
|
+
Requires-Dist: numpydoc==1.10.0; extra == "documentation"
|
|
714
716
|
Requires-Dist: sphinx>=5.1.1; extra == "documentation"
|
|
715
|
-
Requires-Dist: sphinx-gallery==0.
|
|
717
|
+
Requires-Dist: sphinx-gallery==0.21.0; extra == "documentation"
|
|
718
|
+
Requires-Dist: sphinx-design<1,>=0.6; extra == "documentation"
|
|
716
719
|
Requires-Dist: sphinx-rtd-theme==3.1.0; extra == "documentation"
|
|
717
|
-
Requires-Dist: pydata-sphinx-theme==0.
|
|
720
|
+
Requires-Dist: pydata-sphinx-theme==0.17.1; extra == "documentation"
|
|
718
721
|
Provides-Extra: dev
|
|
719
722
|
Requires-Dist: ruff<1,>=0.8; extra == "dev"
|
|
720
723
|
Dynamic: license-file
|
|
721
724
|
|
|
725
|
+
.. image:: https://raw.githubusercontent.com/MartinPdeS/PyFiberModes/master/docs/source/_static/logo.png
|
|
726
|
+
:width: 620
|
|
727
|
+
:align: center
|
|
728
|
+
:alt: PyFiberModes logo
|
|
729
|
+
|
|
722
730
|
.. list-table::
|
|
723
731
|
:widths: 35 65
|
|
724
732
|
:header-rows: 1
|
|
@@ -769,6 +777,9 @@ Features
|
|
|
769
777
|
* Constrained optimization of layer radii, refractive indices, and custom parameters.
|
|
770
778
|
* Constant or longitudinally varying coupled-mode propagation.
|
|
771
779
|
* A catalog of common and example fiber definitions stored as readable YAML files.
|
|
780
|
+
* Structured solver diagnostics, validated configuration models, and explicit
|
|
781
|
+
solver protocols for extending numerical backends.
|
|
782
|
+
* Geometry-aware modal caching and vectorized radial index and field workflows.
|
|
772
783
|
|
|
773
784
|
Installation
|
|
774
785
|
------------
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
"""Public API for circular optical-fiber mode analysis."""
|
|
2
|
+
|
|
1
3
|
from PyFiberModes.mode import Mode, Family # noqa: F401
|
|
2
4
|
from PyFiberModes.mode_instances import * # noqa: F403
|
|
3
5
|
from PyFiberModes.factory import FiberFactory
|
|
6
|
+
from PyFiberModes.fiber import Fiber, load_fiber
|
|
4
7
|
from PyFiberModes.field import Field
|
|
8
|
+
from PyFiberModes.coordinates import CartesianCoordinates, CylindricalCoordinates
|
|
9
|
+
from PyFiberModes.exceptions import ConvergenceError, SolverError, ValidationError
|
|
10
|
+
from PyFiberModes.models import LayerSpec, SolverSettings
|
|
11
|
+
from PyFiberModes.solver.results import SolverResult
|
|
5
12
|
from PyFiberModes.analysis import ModeSweepResult, find_modes, sweep_modes
|
|
6
13
|
from PyFiberModes.optimization import DesignParameter, DesignResult, optimize_fiber
|
|
7
14
|
from PyFiberModes.propagation import CoupledModeSystem, PropagationResult, coupling_matrix, overlap
|
|
@@ -15,11 +22,15 @@ except ImportError:
|
|
|
15
22
|
|
|
16
23
|
|
|
17
24
|
__all__ = [ # noqa: F405
|
|
18
|
-
'Wavelength',
|
|
19
25
|
'Mode',
|
|
20
|
-
'
|
|
26
|
+
'Family',
|
|
27
|
+
'Fiber',
|
|
28
|
+
'load_fiber',
|
|
21
29
|
'FiberFactory',
|
|
22
30
|
'Field',
|
|
31
|
+
'CartesianCoordinates', 'CylindricalCoordinates',
|
|
32
|
+
'LayerSpec', 'SolverSettings', 'SolverResult',
|
|
33
|
+
'ValidationError', 'SolverError', 'ConvergenceError',
|
|
23
34
|
'ModeSweepResult', 'find_modes', 'sweep_modes',
|
|
24
35
|
'DesignParameter', 'DesignResult', 'optimize_fiber',
|
|
25
36
|
'CoupledModeSystem', 'PropagationResult', 'coupling_matrix', 'overlap',
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.13.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 13, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -11,10 +11,21 @@ from PyFiberModes.mode import Mode
|
|
|
11
11
|
|
|
12
12
|
@dataclass(frozen=True)
|
|
13
13
|
class ModeSweepResult:
|
|
14
|
-
"""
|
|
14
|
+
"""Store modal quantities evaluated over a parameter sweep.
|
|
15
15
|
|
|
16
16
|
Rows correspond to ``parameters`` and columns to ``modes``. Missing or
|
|
17
17
|
unguided solutions are represented by NaN.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
parameter_name : str
|
|
22
|
+
Name of the swept parameter.
|
|
23
|
+
parameters : numpy.ndarray
|
|
24
|
+
One-dimensional parameter values.
|
|
25
|
+
modes : tuple of Mode
|
|
26
|
+
Modes represented by the columns of every value array.
|
|
27
|
+
values : dict of str to numpy.ndarray
|
|
28
|
+
Modal metrics shaped ``(n_parameters, n_modes)``.
|
|
18
29
|
"""
|
|
19
30
|
|
|
20
31
|
parameter_name: str
|
|
@@ -23,13 +34,44 @@ class ModeSweepResult:
|
|
|
23
34
|
values: dict[str, np.ndarray]
|
|
24
35
|
|
|
25
36
|
def __getitem__(self, metric: str) -> np.ndarray:
|
|
37
|
+
"""Return the array associated with a metric name.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
metric : str
|
|
42
|
+
Metric key stored in :attr:`values`.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
numpy.ndarray
|
|
47
|
+
Metric values shaped ``(n_parameters, n_modes)``.
|
|
48
|
+
"""
|
|
26
49
|
return self.values[metric]
|
|
27
50
|
|
|
28
51
|
def for_mode(self, mode: Mode) -> dict[str, np.ndarray]:
|
|
52
|
+
"""Extract every metric for one mode.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
mode : Mode
|
|
57
|
+
Mode whose column is requested.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
dict of str to numpy.ndarray
|
|
62
|
+
Mapping from metric names to one-dimensional sweep values.
|
|
63
|
+
"""
|
|
29
64
|
index = self.modes.index(mode)
|
|
30
65
|
return {name: value[:, index] for name, value in self.values.items()}
|
|
31
66
|
|
|
32
67
|
def as_records(self) -> list[dict]:
|
|
68
|
+
"""Convert the dense result into row-oriented records.
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
list of dict
|
|
73
|
+
One record for every parameter and mode combination.
|
|
74
|
+
"""
|
|
33
75
|
return [
|
|
34
76
|
{self.parameter_name: float(parameter), "mode": mode, **{
|
|
35
77
|
name: float(array[i, j]) for name, array in self.values.items()
|
|
@@ -42,7 +84,22 @@ class ModeSweepResult:
|
|
|
42
84
|
def candidate_modes(
|
|
43
85
|
families: Sequence[str] = ("LP",), max_nu: int = 6, max_m: int = 6
|
|
44
86
|
) -> tuple[Mode, ...]:
|
|
45
|
-
"""Generate deterministic
|
|
87
|
+
"""Generate a deterministic bounded set of mode candidates.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
families : sequence of str, optional
|
|
92
|
+
Mode families to enumerate.
|
|
93
|
+
max_nu : int, optional
|
|
94
|
+
Largest azimuthal order to include.
|
|
95
|
+
max_m : int, optional
|
|
96
|
+
Largest radial order to include.
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
tuple of Mode
|
|
101
|
+
Candidates ordered by family, azimuthal order, and radial order.
|
|
102
|
+
"""
|
|
46
103
|
modes = []
|
|
47
104
|
for family in families:
|
|
48
105
|
nus = (0,) if family in ("TE", "TM") else range(max_nu + 1)
|
|
@@ -54,7 +111,25 @@ def candidate_modes(
|
|
|
54
111
|
|
|
55
112
|
|
|
56
113
|
def find_modes(fiber, families=("LP",), max_nu=6, max_m=6) -> tuple[Mode, ...]:
|
|
57
|
-
"""
|
|
114
|
+
"""Find guided modes supported by a fiber.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
fiber : Fiber
|
|
119
|
+
Fiber on which effective indices are evaluated.
|
|
120
|
+
families : sequence of str, optional
|
|
121
|
+
Mode families to search.
|
|
122
|
+
max_nu : int, optional
|
|
123
|
+
Largest azimuthal order to test.
|
|
124
|
+
max_m : int, optional
|
|
125
|
+
Largest radial order to test.
|
|
126
|
+
|
|
127
|
+
Returns
|
|
128
|
+
-------
|
|
129
|
+
tuple of Mode
|
|
130
|
+
Candidates with finite effective indices between the cladding and
|
|
131
|
+
maximum material indices.
|
|
132
|
+
"""
|
|
58
133
|
found = []
|
|
59
134
|
for mode in candidate_modes(families, max_nu, max_m):
|
|
60
135
|
try:
|
|
@@ -79,7 +154,40 @@ def sweep_modes(
|
|
|
79
154
|
max_nu=6,
|
|
80
155
|
max_m=6,
|
|
81
156
|
) -> ModeSweepResult:
|
|
82
|
-
"""
|
|
157
|
+
"""Evaluate modal metrics over wavelength or another scalar parameter.
|
|
158
|
+
|
|
159
|
+
Parameters
|
|
160
|
+
----------
|
|
161
|
+
fiber : Fiber
|
|
162
|
+
Fiber used as the immutable sweep template.
|
|
163
|
+
parameters : iterable of float
|
|
164
|
+
Ordered parameter values.
|
|
165
|
+
modes : sequence of Mode, optional
|
|
166
|
+
Modes to evaluate. When omitted, modes are discovered automatically.
|
|
167
|
+
parameter_name : str, optional
|
|
168
|
+
Name recorded in the returned result.
|
|
169
|
+
setter : callable, optional
|
|
170
|
+
Function accepting ``(fiber, value)`` for non-wavelength sweeps.
|
|
171
|
+
metrics : sequence of str, optional
|
|
172
|
+
Suffixes of ``Fiber.get_<metric>`` methods to evaluate.
|
|
173
|
+
families : sequence of str, optional
|
|
174
|
+
Families used during automatic discovery.
|
|
175
|
+
max_nu : int, optional
|
|
176
|
+
Maximum discovered azimuthal order.
|
|
177
|
+
max_m : int, optional
|
|
178
|
+
Maximum discovered radial order.
|
|
179
|
+
|
|
180
|
+
Returns
|
|
181
|
+
-------
|
|
182
|
+
ModeSweepResult
|
|
183
|
+
Dense arrays for each requested metric.
|
|
184
|
+
|
|
185
|
+
Raises
|
|
186
|
+
------
|
|
187
|
+
ValueError
|
|
188
|
+
If ``parameters`` is empty or not one-dimensional, or when a custom
|
|
189
|
+
parameter is requested without a setter.
|
|
190
|
+
"""
|
|
83
191
|
parameters = np.asarray(tuple(parameters), dtype=float)
|
|
84
192
|
if parameters.ndim != 1 or not len(parameters):
|
|
85
193
|
raise ValueError("parameters must be a non-empty one-dimensional sequence")
|
|
@@ -89,6 +197,7 @@ def sweep_modes(
|
|
|
89
197
|
raise ValueError("a setter is required for non-wavelength sweeps")
|
|
90
198
|
|
|
91
199
|
def setter(current_fiber, value):
|
|
200
|
+
"""Update wavelength for the default sweep behavior."""
|
|
92
201
|
current_fiber.update_wavelength(value)
|
|
93
202
|
if modes is None:
|
|
94
203
|
discovered = []
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Cartesian and cylindrical sampling-grid definitions."""
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
4
|
from dataclasses import dataclass
|
|
3
5
|
from typing import Tuple
|
|
@@ -8,7 +10,7 @@ class CylindricalCoordinates:
|
|
|
8
10
|
"""
|
|
9
11
|
Represents a set of points in cylindrical coordinates.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Parameters
|
|
12
14
|
----------
|
|
13
15
|
rho : np.ndarray
|
|
14
16
|
Radial distance from the z-axis.
|
|
@@ -51,7 +53,7 @@ class CartesianCoordinates:
|
|
|
51
53
|
"""
|
|
52
54
|
Represents a set of points in cartesian coordinates.
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
Parameters
|
|
55
57
|
----------
|
|
56
58
|
x : np.ndarray
|
|
57
59
|
x-coordinates (must be a 1D array).
|
|
@@ -71,9 +73,10 @@ class CartesianCoordinates:
|
|
|
71
73
|
is_3D: bool = False
|
|
72
74
|
|
|
73
75
|
def __post_init__(self) -> None:
|
|
74
|
-
|
|
75
|
-
self.
|
|
76
|
-
self.
|
|
76
|
+
"""Convert all coordinate arrays to floating-point arrays."""
|
|
77
|
+
self.x = np.asarray(self.x, dtype=float)
|
|
78
|
+
self.y = np.asarray(self.y, dtype=float)
|
|
79
|
+
self.z = np.asarray(self.z, dtype=float)
|
|
77
80
|
|
|
78
81
|
@property
|
|
79
82
|
def x_boundaries(self) -> Tuple[float, float]:
|
|
@@ -116,7 +119,8 @@ class CartesianCoordinates:
|
|
|
116
119
|
"""
|
|
117
120
|
if self.is_structured:
|
|
118
121
|
x_min, x_max = self.x_boundaries
|
|
119
|
-
|
|
122
|
+
unique_x = np.unique(self.x)
|
|
123
|
+
return float(unique_x[1] - unique_x[0])
|
|
120
124
|
raise ValueError("dx value cannot be inferred from an unstructured mesh.")
|
|
121
125
|
|
|
122
126
|
@property
|
|
@@ -136,7 +140,8 @@ class CartesianCoordinates:
|
|
|
136
140
|
"""
|
|
137
141
|
if self.is_structured:
|
|
138
142
|
y_min, y_max = self.y_boundaries
|
|
139
|
-
|
|
143
|
+
unique_y = np.unique(self.y)
|
|
144
|
+
return float(unique_y[1] - unique_y[0])
|
|
140
145
|
raise ValueError("dx value cannot be inferred from an unstructured mesh.")
|
|
141
146
|
|
|
142
147
|
@classmethod
|
|
@@ -9,11 +9,6 @@ __all__ = [
|
|
|
9
9
|
"DOCS_PATH",
|
|
10
10
|
"EXAMPLES_PATH",
|
|
11
11
|
"DOC_CSS_PATH",
|
|
12
|
-
"root_path",
|
|
13
|
-
"project_path",
|
|
14
|
-
"examples_path",
|
|
15
|
-
"doc_path",
|
|
16
|
-
"doc_css_path",
|
|
17
12
|
]
|
|
18
13
|
|
|
19
14
|
PACKAGE_PATH = Path(__file__).resolve().parent
|
|
@@ -21,10 +16,3 @@ PROJECT_PATH = PACKAGE_PATH.parent
|
|
|
21
16
|
DOCS_PATH = PROJECT_PATH / "docs"
|
|
22
17
|
EXAMPLES_PATH = DOCS_PATH / "examples"
|
|
23
18
|
DOC_CSS_PATH = DOCS_PATH / "source" / "_static" / "default.css"
|
|
24
|
-
|
|
25
|
-
# Backwards-compatible aliases for the original public names.
|
|
26
|
-
root_path = PACKAGE_PATH
|
|
27
|
-
project_path = PROJECT_PATH
|
|
28
|
-
doc_path = DOCS_PATH
|
|
29
|
-
examples_path = EXAMPLES_PATH
|
|
30
|
-
doc_css_path = DOC_CSS_PATH
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Domain-specific exceptions raised by PyFiberModes."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PyFiberModesError(Exception):
|
|
5
|
+
"""Base class for package-specific errors."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ValidationError(PyFiberModesError, ValueError):
|
|
9
|
+
"""Indicate invalid physical geometry or solver configuration."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SolverError(PyFiberModesError, RuntimeError):
|
|
13
|
+
"""Indicate that a modal solver could not complete normally."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ConvergenceError(SolverError):
|
|
17
|
+
"""Indicate that a numerical solver did not converge to a valid root."""
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
1
|
+
"""Factories for constructing parameterized multilayer fibers."""
|
|
3
2
|
|
|
4
3
|
from itertools import product
|
|
5
4
|
from dataclasses import dataclass, field
|
|
@@ -12,7 +11,7 @@ class ProxyLayer:
|
|
|
12
11
|
"""
|
|
13
12
|
Represents a layer configuration in a fiber, with name, radius, and refractive index.
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
Parameters
|
|
16
15
|
----------
|
|
17
16
|
name : str
|
|
18
17
|
Name of the layer.
|
|
@@ -26,6 +25,7 @@ class ProxyLayer:
|
|
|
26
25
|
index: list = field(default_factory=list)
|
|
27
26
|
|
|
28
27
|
def __post_init__(self):
|
|
28
|
+
"""Normalize scalar layer parameters into one-dimensional arrays."""
|
|
29
29
|
self.name = [self.name]
|
|
30
30
|
self.radius = np.atleast_1d(self.radius)
|
|
31
31
|
self.index = np.atleast_1d(self.index)
|
|
@@ -64,6 +64,13 @@ class FiberFactory:
|
|
|
64
64
|
"""
|
|
65
65
|
|
|
66
66
|
def __init__(self, wavelength: float):
|
|
67
|
+
"""Initialize an empty fiber-configuration factory.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
wavelength : float
|
|
72
|
+
Vacuum wavelength in meters for generated fibers.
|
|
73
|
+
"""
|
|
67
74
|
self.layers_list = []
|
|
68
75
|
self.neff_solver = None
|
|
69
76
|
self.cutoff_solver = None
|