PyFiberModes 0.12.0__tar.gz → 0.13.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.
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.zenodo.json +1 -1
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/CHANGELOG.md +16 -1
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PKG-INFO +12 -6
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/__future__.py +81 -12
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/__init__.py +2 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/_version.py +2 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/analysis.py +113 -4
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/coordinates.py +5 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/factory.py +10 -3
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber.py +272 -155
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/field.py +257 -87
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fundamentals.py +4 -5
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/loader.py +1 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/mode.py +39 -4
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/mode_instances.py +1 -2
- pyfibermodes-0.13.0/PyFiberModes/optimization.py +173 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/propagation.py +96 -3
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/solver/__init__.py +2 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/solver/base_solver.py +100 -35
- pyfibermodes-0.13.0/PyFiberModes/solver/mlsif/__init__.py +3 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/solver/mlsif/neff.py +236 -110
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/solver/ssif/__init__.py +2 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/solver/ssif/cutoff.py +63 -4
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/solver/ssif/neff.py +225 -158
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/solver/tlsif/__init__.py +2 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/solver/tlsif/cutoff.py +167 -66
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/source.py +16 -2
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/stepindex.py +10 -7
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes.egg-info/PKG-INFO +12 -6
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes.egg-info/SOURCES.txt +22 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes.egg-info/requires.txt +6 -5
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/README.rst +5 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/conda.recipe/meta.yaml +1 -2
- pyfibermodes-0.13.0/docs/examples/analysis/README.rst +6 -0
- pyfibermodes-0.13.0/docs/examples/analysis/plot_coupled_mode_exchange.py +22 -0
- pyfibermodes-0.13.0/docs/examples/analysis/plot_structured_wavelength_sweep.py +27 -0
- pyfibermodes-0.13.0/docs/examples/benchmarks/README.rst +7 -0
- pyfibermodes-0.13.0/docs/examples/benchmarks/plot_field_grid_scaling.py +28 -0
- pyfibermodes-0.13.0/docs/examples/fields/README.rst +7 -0
- pyfibermodes-0.13.0/docs/examples/fields/plot_vector_components.py +24 -0
- pyfibermodes-0.13.0/docs/examples/validation/README.rst +7 -0
- pyfibermodes-0.13.0/docs/examples/validation/plot_effective_index_bounds.py +25 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/source/_static/default.css +21 -1
- pyfibermodes-0.13.0/docs/source/_static/favicon.png +0 -0
- pyfibermodes-0.13.0/docs/source/_static/logo.png +0 -0
- pyfibermodes-0.13.0/docs/source/_static/thumbnail.png +0 -0
- pyfibermodes-0.13.0/docs/source/code/analysis.rst +14 -0
- pyfibermodes-0.13.0/docs/source/code/fibers.rst +15 -0
- pyfibermodes-0.13.0/docs/source/code/fields.rst +11 -0
- pyfibermodes-0.13.0/docs/source/code/fundamentals.rst +14 -0
- pyfibermodes-0.13.0/docs/source/code.rst +42 -0
- pyfibermodes-0.13.0/docs/source/conf.py +193 -0
- pyfibermodes-0.13.0/docs/source/examples.rst +73 -0
- pyfibermodes-0.13.0/docs/source/getting_started.rst +34 -0
- pyfibermodes-0.13.0/docs/source/index.rst +22 -0
- pyfibermodes-0.13.0/docs/source/performance.rst +20 -0
- pyfibermodes-0.13.0/docs/source/references.rst +12 -0
- pyfibermodes-0.13.0/docs/source/theory.rst +34 -0
- pyfibermodes-0.13.0/docs/source/troubleshooting.rst +33 -0
- pyfibermodes-0.13.0/docs/source/workflows.rst +35 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/pyproject.toml +7 -6
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_architecture.py +17 -0
- pyfibermodes-0.13.0/tests/test_docstrings.py +34 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_field.py +36 -0
- pyfibermodes-0.12.0/PyFiberModes/optimization.py +0 -86
- 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.0}/.coveragerc +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.github/dependabot.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.github/workflows/deploy_PyPi.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.github/workflows/deploy_anaconda.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.github/workflows/deploy_coverage.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.github/workflows/deploy_documentation.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.github/workflows/quality.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.github/workflows/tests.yml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/.gitignore +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/CITATION.cff +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/CONTRIBUTING.md +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/LICENSE +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/MANIFEST.in +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/Makefile +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/directories.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/1550BHP.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/DCF13.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/DCF1300S_20.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/DCF1300S_26.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/DCF1300S_33.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/DCF1300S_42.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/F2028M12.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/F2028M21.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/F2028M24.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/F2058G1.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/F2058L1.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/HI1060.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/HP630.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/SM1950.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/SMF28.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/fluorine_doped_1%_capillary.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/fluorine_doped_2%_capillary.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/test_fiber.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes/fiber_files/test_multimode_fiber.yaml +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes.egg-info/dependency_links.txt +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/PyFiberModes.egg-info/top_level.txt +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/Makefile +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/DCF/README.rst +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/DCF/plot_DCF_fields.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/README.rst +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/SMF28/README.rst +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/SMF28/plot_smf28.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/SMF28/plot_smf28_dispersion_vs_wavelength.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/SMF28/plot_smf28_group_index_vs_wavelength.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/README.rst +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_U_vs_V.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_comparison_solvers.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_dispersion.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_effective_index.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_fiber_LP_modes.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_group_index.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_mode_field.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_mode_field_1.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_mode_field_2.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/examples/basic/plot_neff_tapered_fiber.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/docs/make.bat +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/pytest.ini +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/setup.cfg +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/__init__.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/helpers.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_advanced_features.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_api.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_coordinates.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_fiber.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_file_loading.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_release_tools.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_ssif.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_tlsif.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tests/test_validation.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tools/check_release.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tools/next_release_version.py +0 -0
- {pyfibermodes-0.12.0 → pyfibermodes-0.13.0}/tools/release_tag.py +0 -0
|
@@ -6,6 +6,20 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.13.0] - 2026-09-22
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Replaced MPSPlots styling and colormaps with native Matplotlib equivalents,
|
|
14
|
+
removing MPSPlots from all runtime and documentation dependencies.
|
|
15
|
+
- Field maps now share one radial solver pass across all electric and magnetic
|
|
16
|
+
components and cache interpolated, azimuthal, and batched component arrays.
|
|
17
|
+
- Added NumPyDoc documentation across modules, public APIs, data models, and
|
|
18
|
+
numerical solver helpers, with structural coverage enforced by tests.
|
|
19
|
+
- Reorganized the documentation into learning, theory, workflow, performance,
|
|
20
|
+
troubleshooting, gallery, and task-oriented API sections; added four new
|
|
21
|
+
example series and a unified logo and favicon identity.
|
|
22
|
+
|
|
9
23
|
## [0.12.0] - 2026-09-22
|
|
10
24
|
|
|
11
25
|
### Changed
|
|
@@ -41,7 +55,8 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
41
55
|
|
|
42
56
|
- Established the current tagged baseline for subsequent documented releases.
|
|
43
57
|
|
|
44
|
-
[Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/v0.
|
|
58
|
+
[Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/v0.13.0...HEAD
|
|
59
|
+
[0.13.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.13.0
|
|
45
60
|
[0.12.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.12.0
|
|
46
61
|
[0.11.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.11.0
|
|
47
62
|
[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.0
|
|
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,34 @@ 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
712
|
Provides-Extra: documentation
|
|
713
|
-
Requires-Dist: numpydoc==1.
|
|
713
|
+
Requires-Dist: numpydoc==1.10.0; extra == "documentation"
|
|
714
714
|
Requires-Dist: sphinx>=5.1.1; extra == "documentation"
|
|
715
|
-
Requires-Dist: sphinx-gallery==0.
|
|
715
|
+
Requires-Dist: sphinx-gallery==0.21.0; extra == "documentation"
|
|
716
|
+
Requires-Dist: sphinx-design<1,>=0.6; extra == "documentation"
|
|
716
717
|
Requires-Dist: sphinx-rtd-theme==3.1.0; extra == "documentation"
|
|
717
|
-
Requires-Dist: pydata-sphinx-theme==0.
|
|
718
|
+
Requires-Dist: pydata-sphinx-theme==0.17.1; extra == "documentation"
|
|
718
719
|
Provides-Extra: dev
|
|
719
720
|
Requires-Dist: ruff<1,>=0.8; extra == "dev"
|
|
720
721
|
Dynamic: license-file
|
|
721
722
|
|
|
723
|
+
.. image:: https://raw.githubusercontent.com/MartinPdeS/PyFiberModes/master/docs/source/_static/logo.png
|
|
724
|
+
:width: 620
|
|
725
|
+
:align: center
|
|
726
|
+
:alt: PyFiberModes logo
|
|
727
|
+
|
|
722
728
|
.. list-table::
|
|
723
729
|
:widths: 35 65
|
|
724
730
|
:header-rows: 1
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
1
|
+
"""Experimental field-normalization helpers retained for future APIs."""
|
|
3
2
|
|
|
4
3
|
import numpy
|
|
5
4
|
|
|
@@ -7,20 +6,28 @@ from PyFiberModes import Mode
|
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
def get_normalized_LP_coupling(fiber, mode_0: Mode, mode_1: Mode) -> float:
|
|
10
|
-
r"""
|
|
11
|
-
Gets the normalized coupling between two supermodes as defined in Equation 7.39 Jacques Bures.
|
|
9
|
+
r"""Calculate normalized coupling between two LP supermodes.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
fiber : Fiber
|
|
14
|
+
Fiber providing propagation constants and interface fields.
|
|
15
|
+
mode_0, mode_1 : Mode
|
|
16
|
+
Linearly polarized modes to couple.
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
float
|
|
21
|
+
Normalized coupling coefficient.
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
Notes
|
|
24
|
+
-----
|
|
25
|
+
The calculation follows Equation 7.39 of Jacques Bures,
|
|
26
|
+
*Optical Fiber Theory*:
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
.. math::
|
|
29
|
+
|
|
30
|
+
\tilde{C_{ij}} = \frac{0.5 k_0^2}{(\beta_0 - \beta_1) \sqrt{\beta_0 * \beta_1}} \sum_i r_i^2 \psi_0(r_i) * \psi_1(r_i)
|
|
24
31
|
"""
|
|
25
32
|
assert mode_0.family == 'LP' and mode_1.family == 'LP', "The normalized coupling equation are only valid for scalar [LP] modes"
|
|
26
33
|
|
|
@@ -56,6 +63,20 @@ def get_normalized_LP_coupling(fiber, mode_0: Mode, mode_1: Mode) -> float:
|
|
|
56
63
|
|
|
57
64
|
|
|
58
65
|
def get_LP_mode_norm(fiber, mode: Mode) -> float:
|
|
66
|
+
"""Calculate the radial normalization integral of an LP mode.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
fiber : Fiber
|
|
71
|
+
Fiber providing radial fields and outer radius.
|
|
72
|
+
mode : Mode
|
|
73
|
+
Linearly polarized mode to normalize.
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
float
|
|
78
|
+
Scalar radial-field norm.
|
|
79
|
+
"""
|
|
59
80
|
radius_list = numpy.linspace(0, 2 * fiber.radius, 100)
|
|
60
81
|
|
|
61
82
|
amplitudes = get_LP_mode_radial_field(
|
|
@@ -70,6 +91,24 @@ def get_LP_mode_norm(fiber, mode: Mode) -> float:
|
|
|
70
91
|
|
|
71
92
|
|
|
72
93
|
def get_LP_mode_radial_normalized_field(fiber, mode: Mode, radius_list: numpy.ndarray = None) -> float:
|
|
94
|
+
"""Sample and normalize the scalar radial field of an LP mode.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
fiber : Fiber
|
|
99
|
+
Fiber providing radial fields.
|
|
100
|
+
mode : Mode
|
|
101
|
+
Linearly polarized mode to sample.
|
|
102
|
+
radius_list : numpy.ndarray, optional
|
|
103
|
+
Radial sampling positions in meters.
|
|
104
|
+
|
|
105
|
+
Returns
|
|
106
|
+
-------
|
|
107
|
+
normalized_field : numpy.ndarray
|
|
108
|
+
Unit-normalized scalar field samples.
|
|
109
|
+
radius_list : numpy.ndarray
|
|
110
|
+
Radial positions associated with the samples.
|
|
111
|
+
"""
|
|
73
112
|
if radius_list is None:
|
|
74
113
|
radius_list = numpy.linspace(0, 2 * fiber.radius, 200)
|
|
75
114
|
|
|
@@ -85,6 +124,22 @@ def get_LP_mode_radial_normalized_field(fiber, mode: Mode, radius_list: numpy.nd
|
|
|
85
124
|
|
|
86
125
|
|
|
87
126
|
def get_LP_mode_radial_field(fiber, mode: Mode, radius_list: numpy.ndarray) -> float:
|
|
127
|
+
"""Sample the scalar radial electric field of an LP mode.
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
fiber : Fiber
|
|
132
|
+
Fiber providing radial fields.
|
|
133
|
+
mode : Mode
|
|
134
|
+
Linearly polarized mode to sample.
|
|
135
|
+
radius_list : numpy.ndarray
|
|
136
|
+
Radial sampling positions in meters.
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
numpy.ndarray
|
|
141
|
+
Radial electric-field amplitude at each position.
|
|
142
|
+
"""
|
|
88
143
|
amplitudes = numpy.empty(radius_list.size)
|
|
89
144
|
|
|
90
145
|
for idx, rho in enumerate(radius_list):
|
|
@@ -95,6 +150,20 @@ def get_LP_mode_radial_field(fiber, mode: Mode, radius_list: numpy.ndarray) -> f
|
|
|
95
150
|
|
|
96
151
|
|
|
97
152
|
def get_scalar_field_norm(rho_list: numpy.ndarray, field: numpy.ndarray) -> float:
|
|
153
|
+
r"""Integrate the cylindrical norm of a scalar radial field.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
rho_list : numpy.ndarray
|
|
158
|
+
Uniform radial sampling positions.
|
|
159
|
+
field : numpy.ndarray
|
|
160
|
+
Scalar field amplitude at each radial position.
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
float
|
|
165
|
+
Value of :math:`2\pi\int |E(\rho)|^2\rho\,d\rho`.
|
|
166
|
+
"""
|
|
98
167
|
rho_list = numpy.asarray(rho_list)
|
|
99
168
|
field = numpy.asarray(field)
|
|
100
169
|
dr = rho_list[1] - rho_list[0]
|
|
@@ -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.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 13, 0)
|
|
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,6 +73,7 @@ class CartesianCoordinates:
|
|
|
71
73
|
is_3D: bool = False
|
|
72
74
|
|
|
73
75
|
def __post_init__(self) -> None:
|
|
76
|
+
"""Convert all coordinate arrays to floating-point arrays."""
|
|
74
77
|
self.x = self.x.astype(float)
|
|
75
78
|
self.y = self.y.astype(float)
|
|
76
79
|
self.z = self.z.astype(float)
|
|
@@ -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
|