PyFiberModes 0.13.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.13.0 → pyfibermodes-0.13.1}/.gitignore +2 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.zenodo.json +1 -1
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/CHANGELOG.md +21 -1
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PKG-INFO +6 -1
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/__init__.py +11 -2
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/_version.py +2 -2
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/coordinates.py +7 -5
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/directories.py +0 -12
- pyfibermodes-0.13.1/PyFiberModes/exceptions.py +17 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber.py +154 -72
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/field.py +7 -58
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/mode.py +0 -30
- pyfibermodes-0.13.1/PyFiberModes/models.py +63 -0
- pyfibermodes-0.13.1/PyFiberModes/services.py +162 -0
- pyfibermodes-0.13.1/PyFiberModes/solver/__init__.py +18 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/base_solver.py +88 -8
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/mlsif/neff.py +0 -97
- pyfibermodes-0.13.1/PyFiberModes/solver/protocols.py +32 -0
- pyfibermodes-0.13.1/PyFiberModes/solver/results.py +56 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/stepindex.py +23 -9
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/PKG-INFO +6 -1
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/SOURCES.txt +10 -1
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/requires.txt +3 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/README.rst +3 -0
- pyfibermodes-0.13.1/benchmarks/README.md +11 -0
- pyfibermodes-0.13.1/benchmarks/test_field_performance.py +32 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/conda.recipe/meta.yaml +1 -1
- pyfibermodes-0.13.1/docs/source/architecture.rst +37 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/code/analysis.rst +12 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/code/fundamentals.rst +8 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/conf.py +2 -2
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/index.rst +1 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/pyproject.toml +5 -1
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_api.py +2 -2
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_architecture.py +0 -8
- pyfibermodes-0.13.1/tests/test_architecture_enhancements.py +86 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_field.py +21 -10
- pyfibermodes-0.13.1/tests/test_physics_regression.py +41 -0
- pyfibermodes-0.13.0/PyFiberModes/__future__.py +0 -177
- pyfibermodes-0.13.0/PyFiberModes/solver/__init__.py +0 -5
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.coveragerc +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.github/dependabot.yml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.github/workflows/deploy_PyPi.yml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.github/workflows/deploy_anaconda.yml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.github/workflows/deploy_coverage.yml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.github/workflows/deploy_documentation.yml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.github/workflows/quality.yml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/.github/workflows/tests.yml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/CITATION.cff +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/CONTRIBUTING.md +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/LICENSE +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/MANIFEST.in +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/Makefile +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/analysis.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/factory.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/1550BHP.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF13.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF1300S_20.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF1300S_26.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF1300S_33.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/DCF1300S_42.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2028M12.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2028M21.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2028M24.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2058G1.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/F2058L1.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/HI1060.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/HP630.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/SM1950.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/SMF28.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/fluorine_doped_1%_capillary.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/fluorine_doped_2%_capillary.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/test_fiber.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fiber_files/test_multimode_fiber.yaml +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/fundamentals.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/loader.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/mode_instances.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/optimization.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/propagation.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/mlsif/__init__.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/ssif/__init__.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/ssif/cutoff.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/ssif/neff.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/tlsif/__init__.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/solver/tlsif/cutoff.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes/source.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/dependency_links.txt +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/PyFiberModes.egg-info/top_level.txt +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/Makefile +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/DCF/README.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/DCF/plot_DCF_fields.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/README.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/SMF28/README.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/SMF28/plot_smf28.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/SMF28/plot_smf28_dispersion_vs_wavelength.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/SMF28/plot_smf28_group_index_vs_wavelength.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/analysis/README.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/analysis/plot_coupled_mode_exchange.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/analysis/plot_structured_wavelength_sweep.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/README.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_U_vs_V.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_comparison_solvers.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_dispersion.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_effective_index.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_fiber_LP_modes.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_group_index.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_mode_field.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_mode_field_1.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_mode_field_2.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/basic/plot_neff_tapered_fiber.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/benchmarks/README.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/benchmarks/plot_field_grid_scaling.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/fields/README.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/fields/plot_vector_components.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/validation/README.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/examples/validation/plot_effective_index_bounds.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/make.bat +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/_static/default.css +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/_static/favicon.png +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/_static/logo.png +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/_static/thumbnail.png +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/code/fibers.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/code/fields.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/code.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/examples.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/getting_started.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/performance.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/references.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/theory.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/troubleshooting.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/docs/source/workflows.rst +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/pytest.ini +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/setup.cfg +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/__init__.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/helpers.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_advanced_features.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_coordinates.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_docstrings.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_fiber.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_file_loading.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_release_tools.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_ssif.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_tlsif.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tests/test_validation.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tools/check_release.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tools/next_release_version.py +0 -0
- {pyfibermodes-0.13.0 → pyfibermodes-0.13.1}/tools/release_tag.py +0 -0
|
@@ -6,6 +6,25 @@ 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
|
+
|
|
9
28
|
## [0.13.0] - 2026-09-22
|
|
10
29
|
|
|
11
30
|
### Changed
|
|
@@ -55,7 +74,8 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
55
74
|
|
|
56
75
|
- Established the current tagged baseline for subsequent documented releases.
|
|
57
76
|
|
|
58
|
-
[Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/v0.13.
|
|
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
|
|
59
79
|
[0.13.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.13.0
|
|
60
80
|
[0.12.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.12.0
|
|
61
81
|
[0.11.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.11.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyFiberModes
|
|
3
|
-
Version: 0.13.
|
|
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
|
|
@@ -709,6 +709,8 @@ 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
715
|
Requires-Dist: numpydoc==1.10.0; extra == "documentation"
|
|
714
716
|
Requires-Dist: sphinx>=5.1.1; extra == "documentation"
|
|
@@ -775,6 +777,9 @@ Features
|
|
|
775
777
|
* Constrained optimization of layer radii, refractive indices, and custom parameters.
|
|
776
778
|
* Constant or longitudinally varying coupled-mode propagation.
|
|
777
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.
|
|
778
783
|
|
|
779
784
|
Installation
|
|
780
785
|
------------
|
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
from PyFiberModes.mode import Mode, Family # noqa: F401
|
|
4
4
|
from PyFiberModes.mode_instances import * # noqa: F403
|
|
5
5
|
from PyFiberModes.factory import FiberFactory
|
|
6
|
+
from PyFiberModes.fiber import Fiber, load_fiber
|
|
6
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
|
|
7
12
|
from PyFiberModes.analysis import ModeSweepResult, find_modes, sweep_modes
|
|
8
13
|
from PyFiberModes.optimization import DesignParameter, DesignResult, optimize_fiber
|
|
9
14
|
from PyFiberModes.propagation import CoupledModeSystem, PropagationResult, coupling_matrix, overlap
|
|
@@ -17,11 +22,15 @@ except ImportError:
|
|
|
17
22
|
|
|
18
23
|
|
|
19
24
|
__all__ = [ # noqa: F405
|
|
20
|
-
'Wavelength',
|
|
21
25
|
'Mode',
|
|
22
|
-
'
|
|
26
|
+
'Family',
|
|
27
|
+
'Fiber',
|
|
28
|
+
'load_fiber',
|
|
23
29
|
'FiberFactory',
|
|
24
30
|
'Field',
|
|
31
|
+
'CartesianCoordinates', 'CylindricalCoordinates',
|
|
32
|
+
'LayerSpec', 'SolverSettings', 'SolverResult',
|
|
33
|
+
'ValidationError', 'SolverError', 'ConvergenceError',
|
|
25
34
|
'ModeSweepResult', 'find_modes', 'sweep_modes',
|
|
26
35
|
'DesignParameter', 'DesignResult', 'optimize_fiber',
|
|
27
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.13.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 13,
|
|
21
|
+
__version__ = version = '0.13.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 13, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -74,9 +74,9 @@ class CartesianCoordinates:
|
|
|
74
74
|
|
|
75
75
|
def __post_init__(self) -> None:
|
|
76
76
|
"""Convert all coordinate arrays to floating-point arrays."""
|
|
77
|
-
self.x = self.x
|
|
78
|
-
self.y = self.y
|
|
79
|
-
self.z = self.z
|
|
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)
|
|
80
80
|
|
|
81
81
|
@property
|
|
82
82
|
def x_boundaries(self) -> Tuple[float, float]:
|
|
@@ -119,7 +119,8 @@ class CartesianCoordinates:
|
|
|
119
119
|
"""
|
|
120
120
|
if self.is_structured:
|
|
121
121
|
x_min, x_max = self.x_boundaries
|
|
122
|
-
|
|
122
|
+
unique_x = np.unique(self.x)
|
|
123
|
+
return float(unique_x[1] - unique_x[0])
|
|
123
124
|
raise ValueError("dx value cannot be inferred from an unstructured mesh.")
|
|
124
125
|
|
|
125
126
|
@property
|
|
@@ -139,7 +140,8 @@ class CartesianCoordinates:
|
|
|
139
140
|
"""
|
|
140
141
|
if self.is_structured:
|
|
141
142
|
y_min, y_max = self.y_boundaries
|
|
142
|
-
|
|
143
|
+
unique_y = np.unique(self.y)
|
|
144
|
+
return float(unique_y[1] - unique_y[0])
|
|
143
145
|
raise ValueError("dx value cannot be inferred from an unstructured mesh.")
|
|
144
146
|
|
|
145
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."""
|
|
@@ -15,14 +15,14 @@ from PyFinitDiff.finite_difference_1D import get_function_derivative
|
|
|
15
15
|
from PyFiberModes.field import Field
|
|
16
16
|
|
|
17
17
|
from PyFiberModes.fundamentals import (
|
|
18
|
-
get_effective_index,
|
|
19
|
-
get_mode_cutoff_v0,
|
|
20
18
|
get_radial_field,
|
|
21
19
|
get_propagation_constant_from_omega
|
|
22
20
|
)
|
|
23
21
|
|
|
24
22
|
from PyFiberModes import loader
|
|
25
23
|
from PyFiberModes.coordinates import CylindricalCoordinates
|
|
24
|
+
from PyFiberModes.exceptions import ValidationError
|
|
25
|
+
from PyFiberModes.services import FieldAnalysis, ModalAnalysis
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
@dataclass
|
|
@@ -55,9 +55,62 @@ class Fiber(object):
|
|
|
55
55
|
|
|
56
56
|
def __post_init__(self):
|
|
57
57
|
"""Initialize mutable layer and solver state after construction."""
|
|
58
|
+
if self.wavelength is not None and (
|
|
59
|
+
not numpy.isfinite(self.wavelength) or self.wavelength <= 0
|
|
60
|
+
):
|
|
61
|
+
raise ValidationError("wavelength must be positive and finite")
|
|
58
62
|
self.layers_parameters = []
|
|
59
63
|
self.radius_in = 0
|
|
60
64
|
self.layers = []
|
|
65
|
+
self._analysis_service = None
|
|
66
|
+
self._field_service = None
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def geometry_signature(self) -> tuple:
|
|
70
|
+
"""Return an immutable signature of all solver-relevant fiber state.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
tuple
|
|
75
|
+
Wavelength and ordered layer geometry/index values.
|
|
76
|
+
"""
|
|
77
|
+
layers = tuple(
|
|
78
|
+
(layer.radius_in, layer.radius_out, layer.refractive_index)
|
|
79
|
+
for layer in self.layers
|
|
80
|
+
)
|
|
81
|
+
return self.wavelength, layers
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def analysis(self) -> ModalAnalysis:
|
|
85
|
+
"""Return the focused modal-analysis service.
|
|
86
|
+
|
|
87
|
+
Returns
|
|
88
|
+
-------
|
|
89
|
+
ModalAnalysis
|
|
90
|
+
Geometry-aware cached analysis service.
|
|
91
|
+
"""
|
|
92
|
+
if self._analysis_service is None:
|
|
93
|
+
self._analysis_service = ModalAnalysis(self)
|
|
94
|
+
return self._analysis_service
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def fields(self) -> FieldAnalysis:
|
|
98
|
+
"""Return the focused field-construction service.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
FieldAnalysis
|
|
103
|
+
Field orchestration service.
|
|
104
|
+
"""
|
|
105
|
+
if self._field_service is None:
|
|
106
|
+
self._field_service = FieldAnalysis(self)
|
|
107
|
+
return self._field_service
|
|
108
|
+
|
|
109
|
+
def clear_caches(self) -> None:
|
|
110
|
+
"""Clear modal and radial-field caches after a physical mutation."""
|
|
111
|
+
if self._analysis_service is not None:
|
|
112
|
+
self._analysis_service.clear()
|
|
113
|
+
self.get_radial_field.cache_clear()
|
|
61
114
|
|
|
62
115
|
def scale(self, factor: float) -> None:
|
|
63
116
|
"""
|
|
@@ -195,7 +248,7 @@ class Fiber(object):
|
|
|
195
248
|
self.wavelength = wavelength
|
|
196
249
|
for layer in self.layers:
|
|
197
250
|
layer.wavelength = wavelength
|
|
198
|
-
self.
|
|
251
|
+
self.clear_caches()
|
|
199
252
|
|
|
200
253
|
def add_layer(self, name: str, radius: float, index: float) -> None:
|
|
201
254
|
"""
|
|
@@ -214,6 +267,16 @@ class Fiber(object):
|
|
|
214
267
|
-----
|
|
215
268
|
Layers should be added in order, starting with the innermost layer (core).
|
|
216
269
|
"""
|
|
270
|
+
if not name:
|
|
271
|
+
raise ValidationError("layer name must not be empty")
|
|
272
|
+
if not numpy.isfinite(index) or index <= 0:
|
|
273
|
+
raise ValidationError("refractive index must be positive and finite")
|
|
274
|
+
radius = float(radius)
|
|
275
|
+
if radius <= 0:
|
|
276
|
+
radius = numpy.inf
|
|
277
|
+
if radius <= self.radius_in:
|
|
278
|
+
raise ValidationError("layer radii must be strictly increasing")
|
|
279
|
+
|
|
217
280
|
self.layer_names.append(name)
|
|
218
281
|
self.index_list.append(index)
|
|
219
282
|
|
|
@@ -231,6 +294,7 @@ class Fiber(object):
|
|
|
231
294
|
self.layers.append(layer)
|
|
232
295
|
|
|
233
296
|
self.radius_in = radius
|
|
297
|
+
self.clear_caches()
|
|
234
298
|
|
|
235
299
|
def initialize_layers(self) -> None:
|
|
236
300
|
"""Initializes the layers.
|
|
@@ -240,6 +304,8 @@ class Fiber(object):
|
|
|
240
304
|
None
|
|
241
305
|
No returns
|
|
242
306
|
"""
|
|
307
|
+
if not self.layers:
|
|
308
|
+
raise ValidationError("a fiber must contain at least one layer")
|
|
243
309
|
self.layers[-1].is_last_layer = True
|
|
244
310
|
self.layers[0].is_first_layer = True
|
|
245
311
|
|
|
@@ -247,6 +313,7 @@ class Fiber(object):
|
|
|
247
313
|
|
|
248
314
|
for position, layer in enumerate(self.layers):
|
|
249
315
|
layer.position = position
|
|
316
|
+
self.clear_caches()
|
|
250
317
|
|
|
251
318
|
def get_layer_at_radius(self, radius: float) -> StepIndex:
|
|
252
319
|
"""Gets the layer that is associated to a given radius.
|
|
@@ -263,8 +330,29 @@ class Fiber(object):
|
|
|
263
330
|
"""
|
|
264
331
|
radius = abs(radius)
|
|
265
332
|
for layer in self.layers:
|
|
266
|
-
if
|
|
333
|
+
if layer.radius_in <= radius <= layer.radius_out:
|
|
267
334
|
return layer
|
|
335
|
+
raise ValidationError(f"radius {radius} lies outside the fiber geometry")
|
|
336
|
+
|
|
337
|
+
def get_index_profile(self, radius) -> numpy.ndarray:
|
|
338
|
+
"""Evaluate the refractive-index profile for many radii at once.
|
|
339
|
+
|
|
340
|
+
Parameters
|
|
341
|
+
----------
|
|
342
|
+
radius : array-like
|
|
343
|
+
Scalar or array of radial positions in meters.
|
|
344
|
+
|
|
345
|
+
Returns
|
|
346
|
+
-------
|
|
347
|
+
numpy.ndarray
|
|
348
|
+
Refractive indices with the same shape as ``radius``.
|
|
349
|
+
"""
|
|
350
|
+
radii = numpy.abs(numpy.asarray(radius, dtype=float))
|
|
351
|
+
boundaries = numpy.asarray([layer.radius_out for layer in self.layers])
|
|
352
|
+
indices = numpy.asarray([layer.refractive_index for layer in self.layers])
|
|
353
|
+
positions = numpy.searchsorted(boundaries, radii, side="left")
|
|
354
|
+
positions = numpy.clip(positions, 0, len(indices) - 1)
|
|
355
|
+
return indices[positions]
|
|
268
356
|
|
|
269
357
|
@property
|
|
270
358
|
def radius(self) -> float:
|
|
@@ -417,13 +505,8 @@ class Fiber(object):
|
|
|
417
505
|
float
|
|
418
506
|
The cutoff wavelength.
|
|
419
507
|
"""
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
fiber=self,
|
|
423
|
-
wavelength=self.wavelength
|
|
424
|
-
)
|
|
425
|
-
|
|
426
|
-
return cutoff_V0
|
|
508
|
+
result = self.analysis.cutoff_result(mode)
|
|
509
|
+
return result.value if result.converged else numpy.nan
|
|
427
510
|
|
|
428
511
|
def get_mode_cutoff_wavelength(self, mode: Mode) -> float:
|
|
429
512
|
"""
|
|
@@ -472,13 +555,22 @@ class Fiber(object):
|
|
|
472
555
|
float
|
|
473
556
|
The effective index.
|
|
474
557
|
"""
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
)
|
|
558
|
+
return self.analysis.effective_index(mode)
|
|
559
|
+
|
|
560
|
+
def solve_effective_index(self, mode: Mode):
|
|
561
|
+
"""Return a structured effective-index solver result.
|
|
480
562
|
|
|
481
|
-
|
|
563
|
+
Parameters
|
|
564
|
+
----------
|
|
565
|
+
mode : Mode
|
|
566
|
+
Mode to solve.
|
|
567
|
+
|
|
568
|
+
Returns
|
|
569
|
+
-------
|
|
570
|
+
SolverResult[float]
|
|
571
|
+
Value and explicit convergence diagnostics.
|
|
572
|
+
"""
|
|
573
|
+
return self.analysis.effective_index_result(mode)
|
|
482
574
|
|
|
483
575
|
def get_normalized_beta(self, mode: Mode) -> float:
|
|
484
576
|
"""Gets the normalized propagation constant [beta].
|
|
@@ -493,11 +585,7 @@ class Fiber(object):
|
|
|
493
585
|
float
|
|
494
586
|
The normalized propagation constant.
|
|
495
587
|
"""
|
|
496
|
-
neff = get_effective_index(
|
|
497
|
-
fiber=self,
|
|
498
|
-
wavelength=self.wavelength,
|
|
499
|
-
mode=mode,
|
|
500
|
-
)
|
|
588
|
+
neff = self.get_effective_index(mode)
|
|
501
589
|
|
|
502
590
|
n_max = self.maximum_index
|
|
503
591
|
|
|
@@ -522,11 +610,7 @@ class Fiber(object):
|
|
|
522
610
|
float
|
|
523
611
|
The propagation constant [:math:`beta`].
|
|
524
612
|
"""
|
|
525
|
-
neff = get_effective_index(
|
|
526
|
-
fiber=self,
|
|
527
|
-
wavelength=self.wavelength,
|
|
528
|
-
mode=mode,
|
|
529
|
-
)
|
|
613
|
+
neff = self.get_effective_index(mode)
|
|
530
614
|
|
|
531
615
|
beta = neff * (2 * numpy.pi / self.wavelength)
|
|
532
616
|
|
|
@@ -555,11 +639,7 @@ class Fiber(object):
|
|
|
555
639
|
|
|
556
640
|
where :math:`n_{eff}` is the effective refractive index.
|
|
557
641
|
"""
|
|
558
|
-
n_eff = get_effective_index(
|
|
559
|
-
fiber=self,
|
|
560
|
-
wavelength=self.wavelength,
|
|
561
|
-
mode=mode,
|
|
562
|
-
)
|
|
642
|
+
n_eff = self.get_effective_index(mode)
|
|
563
643
|
|
|
564
644
|
return constants.c / n_eff
|
|
565
645
|
|
|
@@ -589,34 +669,20 @@ class Fiber(object):
|
|
|
589
669
|
|
|
590
670
|
return derivative * constants.c
|
|
591
671
|
|
|
592
|
-
def
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
.. math::
|
|
596
|
-
\left( \frac{\partial \beta}{\partial \omega} \right)^{-1}
|
|
672
|
+
def get_group_velocity(self, mode: Mode) -> float:
|
|
673
|
+
"""Compute the correctly named modal group velocity.
|
|
597
674
|
|
|
598
675
|
Parameters
|
|
599
676
|
----------
|
|
600
677
|
mode : Mode
|
|
601
|
-
|
|
678
|
+
Mode to evaluate.
|
|
602
679
|
|
|
603
680
|
Returns
|
|
604
681
|
-------
|
|
605
682
|
float
|
|
606
|
-
|
|
683
|
+
Group velocity in meters per second.
|
|
607
684
|
"""
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
derivative = get_function_derivative(
|
|
611
|
-
function=get_propagation_constant_from_omega,
|
|
612
|
-
x_eval=omega,
|
|
613
|
-
derivative=1,
|
|
614
|
-
accuracy=4,
|
|
615
|
-
delta=1e12, # This value is critical for accurate computation
|
|
616
|
-
function_kwargs=dict(fiber=self, mode=mode)
|
|
617
|
-
)
|
|
618
|
-
|
|
619
|
-
return 1 / derivative
|
|
685
|
+
return constants.c / self.get_group_index(mode)
|
|
620
686
|
|
|
621
687
|
def get_group_velocity_dispersion(self, mode: Mode) -> float:
|
|
622
688
|
r"""Gets the fiber group velocity dispersion defined as:
|
|
@@ -736,20 +802,12 @@ class Fiber(object):
|
|
|
736
802
|
Field
|
|
737
803
|
The field instance of the mode.
|
|
738
804
|
"""
|
|
739
|
-
|
|
740
|
-
limit = self.radius * 5.5
|
|
741
|
-
|
|
742
|
-
field = Field(
|
|
743
|
-
fiber=self,
|
|
744
|
-
mode=mode,
|
|
745
|
-
limit=limit,
|
|
746
|
-
n_point=n_point
|
|
747
|
-
)
|
|
748
|
-
|
|
749
|
-
return field
|
|
805
|
+
return self.fields.mode_field(mode=mode, limit=limit, n_point=n_point)
|
|
750
806
|
|
|
751
807
|
@cache
|
|
752
|
-
def get_radial_field(
|
|
808
|
+
def get_radial_field(
|
|
809
|
+
self, mode: Mode, radius: float
|
|
810
|
+
) -> tuple[CylindricalCoordinates, CylindricalCoordinates]:
|
|
753
811
|
r"""Gets the mode field without the azimuthal component.
|
|
754
812
|
Tuple structure is [:math:`E_{r}`, :math:`E_{\phi}`, :math:`E_{z}`], [:math:`H_{r}`, :math:`H_{\phi}`, :math:`H_{z}`]
|
|
755
813
|
|
|
@@ -762,8 +820,8 @@ class Fiber(object):
|
|
|
762
820
|
|
|
763
821
|
Returns
|
|
764
822
|
-------
|
|
765
|
-
|
|
766
|
-
|
|
823
|
+
tuple[CylindricalCoordinates, CylindricalCoordinates]
|
|
824
|
+
Electric and magnetic radial fields.
|
|
767
825
|
"""
|
|
768
826
|
radial_field = get_radial_field(
|
|
769
827
|
fiber=self,
|
|
@@ -774,6 +832,35 @@ class Fiber(object):
|
|
|
774
832
|
|
|
775
833
|
return radial_field
|
|
776
834
|
|
|
835
|
+
def get_radial_fields(self, mode: Mode, radius) -> tuple[CylindricalCoordinates, CylindricalCoordinates]:
|
|
836
|
+
"""Evaluate radial electric and magnetic fields over an array.
|
|
837
|
+
|
|
838
|
+
Parameters
|
|
839
|
+
----------
|
|
840
|
+
mode : Mode
|
|
841
|
+
Mode to evaluate.
|
|
842
|
+
radius : array-like
|
|
843
|
+
Radial sampling positions.
|
|
844
|
+
|
|
845
|
+
Returns
|
|
846
|
+
-------
|
|
847
|
+
tuple[CylindricalCoordinates, CylindricalCoordinates]
|
|
848
|
+
Electric and magnetic cylindrical components as arrays.
|
|
849
|
+
"""
|
|
850
|
+
radii = numpy.asarray(radius, dtype=float)
|
|
851
|
+
flat = radii.ravel()
|
|
852
|
+
solved = [self.get_radial_field(mode, float(value)) for value in flat]
|
|
853
|
+
|
|
854
|
+
def assemble(position):
|
|
855
|
+
"""Assemble one electric or magnetic coordinate container."""
|
|
856
|
+
values = [item[position] for item in solved]
|
|
857
|
+
return CylindricalCoordinates(*(
|
|
858
|
+
numpy.asarray([getattr(value, name) for value in values]).reshape(radii.shape)
|
|
859
|
+
for name in ("rho", "phi", "z")
|
|
860
|
+
))
|
|
861
|
+
|
|
862
|
+
return assemble(0), assemble(1)
|
|
863
|
+
|
|
777
864
|
def get_radial_field_norm(self, mode: Mode, radius: float) -> float:
|
|
778
865
|
r"""Gets the norm of the mode field without the azimuthal component.
|
|
779
866
|
Tuple structure is [:math:`E_{r}`, :math:`E_{\phi}`, :math:`E_{z}`], [:math:`H_{r}`, :math:`H_{\phi}`, :math:`H_{z}`]
|
|
@@ -790,12 +877,7 @@ class Fiber(object):
|
|
|
790
877
|
float
|
|
791
878
|
The radial field.
|
|
792
879
|
"""
|
|
793
|
-
e_field, h_field = get_radial_field(
|
|
794
|
-
fiber=self,
|
|
795
|
-
mode=mode,
|
|
796
|
-
wavelength=self.wavelength,
|
|
797
|
-
radius=radius
|
|
798
|
-
)
|
|
880
|
+
e_field, h_field = self.get_radial_field(mode=mode, radius=radius)
|
|
799
881
|
|
|
800
882
|
norm = numpy.sqrt(e_field.rho**2 + e_field.phi**2 + e_field.z**2)
|
|
801
883
|
|
|
@@ -817,7 +899,7 @@ class Fiber(object):
|
|
|
817
899
|
mode_exist = []
|
|
818
900
|
for mode in mode_list:
|
|
819
901
|
neff = self.get_effective_index(mode=mode)
|
|
820
|
-
if
|
|
902
|
+
if not numpy.isfinite(neff):
|
|
821
903
|
mode_exist.append(False)
|
|
822
904
|
else:
|
|
823
905
|
mode_exist.append(True)
|
|
@@ -10,6 +10,7 @@ from dataclasses import dataclass
|
|
|
10
10
|
import matplotlib.pyplot as plt
|
|
11
11
|
from matplotlib.colors import LinearSegmentedColormap
|
|
12
12
|
from PyFiberModes.coordinates import CartesianCoordinates
|
|
13
|
+
from PyFiberModes.coordinates import CylindricalCoordinates as CylindricalCoordinates # noqa: F401
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
BLUE_BLACK_RED = LinearSegmentedColormap.from_list(
|
|
@@ -18,50 +19,6 @@ BLUE_BLACK_RED = LinearSegmentedColormap.from_list(
|
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
@dataclass
|
|
22
|
-
class CylindricalCoordinates:
|
|
23
|
-
"""Store cylindrical coordinate arrays used by a field grid.
|
|
24
|
-
|
|
25
|
-
Parameters
|
|
26
|
-
----------
|
|
27
|
-
rho : numpy.ndarray
|
|
28
|
-
Radial distances.
|
|
29
|
-
phi : numpy.ndarray
|
|
30
|
-
Azimuthal angles in radians.
|
|
31
|
-
z : numpy.ndarray
|
|
32
|
-
Longitudinal positions.
|
|
33
|
-
"""
|
|
34
|
-
rho: numpy.ndarray
|
|
35
|
-
phi: numpy.ndarray
|
|
36
|
-
z: numpy.ndarray
|
|
37
|
-
|
|
38
|
-
def to_cartesian(self) -> object:
|
|
39
|
-
"""Convert the coordinate arrays to Cartesian form.
|
|
40
|
-
|
|
41
|
-
Returns
|
|
42
|
-
-------
|
|
43
|
-
CartesianCoordinates
|
|
44
|
-
Equivalent Cartesian coordinate arrays.
|
|
45
|
-
"""
|
|
46
|
-
x = self.rho * numpy.cos(self.phi)
|
|
47
|
-
y = self.rho * numpy.sin(self.phi)
|
|
48
|
-
z = self.z
|
|
49
|
-
|
|
50
|
-
cartesian_coordinate = CartesianCoordinates(x=x, y=y, z=z)
|
|
51
|
-
|
|
52
|
-
return cartesian_coordinate
|
|
53
|
-
|
|
54
|
-
def to_cylindrical(self):
|
|
55
|
-
"""Return this already-cylindrical coordinate object.
|
|
56
|
-
|
|
57
|
-
Returns
|
|
58
|
-
-------
|
|
59
|
-
CylindricalCoordinates
|
|
60
|
-
The current object.
|
|
61
|
-
"""
|
|
62
|
-
return self
|
|
63
|
-
|
|
64
|
-
|
|
65
22
|
@dataclass
|
|
66
23
|
class Field:
|
|
67
24
|
"""
|
|
@@ -123,23 +80,15 @@ class Field:
|
|
|
123
80
|
|
|
124
81
|
count = max(257, 2 * self.n_point)
|
|
125
82
|
radii = np.linspace(0.0, np.sqrt(2.0) * self.limit, count)
|
|
126
|
-
|
|
83
|
+
electric, magnetic = self.fiber.get_radial_fields(
|
|
84
|
+
mode=self.mode, radius=radii
|
|
85
|
+
)
|
|
127
86
|
values = {
|
|
128
|
-
(field_name, component): np.
|
|
129
|
-
for field_name in ("E", "H")
|
|
130
|
-
for component in
|
|
87
|
+
(field_name, component): np.asarray(getattr(vector, component), dtype=complex)
|
|
88
|
+
for field_name, vector in (("E", electric), ("H", magnetic))
|
|
89
|
+
for component in ("rho", "phi", "z")
|
|
131
90
|
}
|
|
132
91
|
|
|
133
|
-
for index, radius in enumerate(radii):
|
|
134
|
-
electric, magnetic = self.fiber.get_radial_field(
|
|
135
|
-
mode=self.mode, radius=float(radius)
|
|
136
|
-
)
|
|
137
|
-
for field_name, vector in (("E", electric), ("H", magnetic)):
|
|
138
|
-
for component in component_names:
|
|
139
|
-
values[field_name, component][index] = complex(
|
|
140
|
-
getattr(vector, component)
|
|
141
|
-
)
|
|
142
|
-
|
|
143
92
|
self._radial_cache = {
|
|
144
93
|
key: (radii, component_values)
|
|
145
94
|
for key, component_values in values.items()
|