PyFiberModes 0.17.7__tar.gz → 1.0.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.17.7 → pyfibermodes-1.0.0}/.zenodo.json +1 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/CHANGELOG.md +6 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PKG-INFO +29 -14
- pyfibermodes-0.17.7/PyFiberModes/fiber.py → pyfibermodes-1.0.0/PyFiberModes/_fiber.py +2 -2
- pyfibermodes-0.17.7/PyFiberModes/field.py → pyfibermodes-1.0.0/PyFiberModes/_field.py +2 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/_version.py +2 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/analysis.py +45 -19
- pyfibermodes-1.0.0/PyFiberModes/coordinates.py +153 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/factory.py +14 -13
- pyfibermodes-1.0.0/PyFiberModes/fiber.py +447 -0
- pyfibermodes-1.0.0/PyFiberModes/field.py +181 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fundamentals.py +1 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/loader.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/materials.py +43 -22
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/models.py +9 -6
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/optimization.py +39 -11
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/plotting.py +1 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/propagation.py +36 -10
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/services.py +1 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/base_solver.py +4 -2
- pyfibermodes-1.0.0/PyFiberModes/source.py +100 -0
- pyfibermodes-1.0.0/PyFiberModes/units.py +67 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes.egg-info/PKG-INFO +29 -14
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes.egg-info/SOURCES.txt +5 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes.egg-info/requires.txt +2 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/README.rst +26 -13
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/benchmarks/test_field_performance.py +6 -5
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/conda.recipe/meta.yaml +3 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/SMF28/plot_smf28.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/SMF28/plot_smf28_dispersion_vs_wavelength.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/SMF28/plot_smf28_group_index_vs_wavelength.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/analysis/plot_coupled_mode_exchange.py +5 -4
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/analysis/plot_guided_mode_discovery.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/analysis/plot_structured_wavelength_sweep.py +5 -4
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_U_vs_V.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_comparison_solvers.py +3 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_dispersion.py +6 -5
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_effective_index.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_fiber_LP_modes.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_group_index.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_mode_field.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_mode_field_1.py +5 -4
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_mode_field_2.py +3 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/plot_neff_tapered_fiber.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/benchmarks/plot_component_batching_speedup.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/benchmarks/plot_field_grid_scaling.py +3 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/benchmarks/plot_modal_cache_speedup.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/fields/plot_confinement_by_radius.py +5 -4
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/fields/plot_polarization_rotation.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/fields/plot_vector_components.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/specialty_fibers/plot_refractive_index_profile.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/specialty_fibers/plot_specialty_fiber_catalog.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/specialty_fibers/plot_specialty_mode_indices.py +2 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/validation/plot_effective_index_bounds.py +3 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/validation/plot_field_area_convergence.py +4 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/validation/plot_normalized_effective_index.py +3 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/getting_started.rst +9 -5
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/migration_guide.rst +40 -3
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/public_api_contract.rst +15 -5
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/user_guide/fibers.rst +14 -9
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/user_guide/fields.rst +10 -4
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/user_guide/modes.rst +7 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/user_guide/sweeps.rst +17 -9
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/pyproject.toml +3 -1
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/api_snapshot.json +2 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_advanced_features.py +11 -10
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_api.py +7 -5
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_architecture_enhancements.py +9 -8
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_coordinates.py +28 -27
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_fiber.py +7 -5
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_field.py +2 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_file_loading.py +3 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_physics_regression.py +6 -5
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_three_layer_solver.py +4 -2
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_two_layer_solver.py +3 -1
- pyfibermodes-1.0.0/tests/test_units.py +247 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_validation.py +7 -5
- pyfibermodes-0.17.7/PyFiberModes/source.py +0 -81
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/.coveragerc +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/.github/dependabot.yml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/.github/workflows/deploy_coverage.yml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/.github/workflows/deploy_documentation.yml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/.github/workflows/deploy_release.yml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/.github/workflows/quality.yml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/.github/workflows/tests.yml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/.gitignore +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/CITATION.cff +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/CONTRIBUTING.md +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/LICENSE +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/MANIFEST.in +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/Makefile +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/__init__.py +0 -0
- /pyfibermodes-0.17.7/PyFiberModes/coordinates.py → /pyfibermodes-1.0.0/PyFiberModes/_coordinates.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/directories.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/exceptions.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/1550BHP.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/DCF13.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/DCF1300S_20.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/DCF1300S_26.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/DCF1300S_33.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/DCF1300S_42.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/F2028M12.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/F2028M21.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/F2028M24.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/F2058G1.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/F2058L1.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/HI1060.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/HP630.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/SM1950.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/SMF28.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/fluorine_doped_1%_capillary.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/fluorine_doped_2%_capillary.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/test_fiber.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/fiber_files/test_multimode_fiber.yaml +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/mode.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/mode_instances.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/__init__.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/multilayer/__init__.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/multilayer/effective_index.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/protocols.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/results.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/three_layer/__init__.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/three_layer/cutoff.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/two_layer/__init__.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/two_layer/cutoff.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/solver/two_layer/effective_index.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes/stepindex.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes.egg-info/dependency_links.txt +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/PyFiberModes.egg-info/top_level.txt +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/benchmarks/README.md +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/Makefile +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/README.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/SMF28/README.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/analysis/README.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/basic/README.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/benchmarks/README.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/fields/README.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/specialty_fibers/README.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/examples/validation/README.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/make.bat +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/redirect.html +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/_static/default.css +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/_static/favicon.png +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/_static/logo.png +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/_static/thumbnail.png +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/api_policy.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/architecture.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/code/analysis.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/code/fibers.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/code/fields.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/code/fundamentals.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/code.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/conf.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/examples.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/guide.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/index.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/performance.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/references.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/resources.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/theory.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/troubleshooting.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/user_guide/index.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/user_guide/reproducibility.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/user_guide/units.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/docs/source/workflows.rst +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/pytest.ini +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/setup.cfg +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/__init__.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/helpers.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_architecture.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_docstrings.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_public_api.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tests/test_release_tools.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tools/check_release.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tools/next_release_version.py +0 -0
- {pyfibermodes-0.17.7 → pyfibermodes-1.0.0}/tools/release_tag.py +0 -0
|
@@ -6,6 +6,10 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.0.0] - 2026-10-23
|
|
10
|
+
|
|
11
|
+
- Require TypedUnit/Pint quantities for physical inputs and return unit-bearing fiber, field, sweep, material, design and propagation results. Numerical solvers continue to operate in SI internally.
|
|
12
|
+
|
|
9
13
|
## [0.17.7] - 2026-10-23
|
|
10
14
|
|
|
11
15
|
## [0.17.6] - 2026-10-22
|
|
@@ -175,7 +179,8 @@ use [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
175
179
|
|
|
176
180
|
- Established the current tagged baseline for subsequent documented releases.
|
|
177
181
|
|
|
178
|
-
[Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/
|
|
182
|
+
[Unreleased]: https://github.com/MartinPdeS/PyFiberModes/compare/v1.0.0...HEAD
|
|
183
|
+
[1.0.0]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v1.0.0
|
|
179
184
|
[0.17.7]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.17.7
|
|
180
185
|
[0.17.6]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.17.6
|
|
181
186
|
[0.17.5]: https://github.com/MartinPdeS/PyFiberModes/releases/tag/v0.17.5
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyFiberModes
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Guided-mode analysis and design for circular optical fibers.
|
|
5
5
|
Author-email: Martin Poinsinet de Sivry-Houle <martin.poinsinet.de.sivry@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -699,6 +699,8 @@ Requires-Python: >=3.11
|
|
|
699
699
|
Description-Content-Type: text/x-rst
|
|
700
700
|
License-File: LICENSE
|
|
701
701
|
Requires-Dist: PyFinitDiff
|
|
702
|
+
Requires-Dist: TypedUnit>=0.2.9
|
|
703
|
+
Requires-Dist: pint<0.26,>=0.24
|
|
702
704
|
Requires-Dist: pyyaml
|
|
703
705
|
Requires-Dist: numpy
|
|
704
706
|
Requires-Dist: scipy
|
|
@@ -818,22 +820,25 @@ First mode calculation
|
|
|
818
820
|
----------------------
|
|
819
821
|
|
|
820
822
|
Load the bundled SMF-28 definition at 1550 nm and solve its fundamental LP
|
|
821
|
-
mode.
|
|
823
|
+
mode. Physical inputs require Pint quantities; lengths may use any compatible unit.
|
|
824
|
+
Results also carry units, using the shared TypedUnit registry as in PyMieSim.
|
|
822
825
|
|
|
823
826
|
.. code-block:: python
|
|
824
827
|
|
|
828
|
+
from PyFiberModes.units import ureg
|
|
829
|
+
|
|
825
830
|
from PyFiberModes import LP01
|
|
826
831
|
from PyFiberModes.fiber import load_fiber
|
|
827
832
|
|
|
828
|
-
fiber = load_fiber("SMF28", wavelength=1550e-9)
|
|
833
|
+
fiber = load_fiber("SMF28", wavelength=1550e-9 * ureg.meter)
|
|
829
834
|
|
|
830
835
|
effective_index = fiber.get_effective_index(LP01)
|
|
831
836
|
propagation_constant = fiber.get_propagation_constant(LP01)
|
|
832
837
|
dispersion = fiber.get_dispersion(LP01)
|
|
833
838
|
|
|
834
839
|
print(f"n_eff = {effective_index:.9f}")
|
|
835
|
-
print(f"beta = {propagation_constant:.6e}
|
|
836
|
-
print(f"D = {dispersion:.3f}
|
|
840
|
+
print(f"beta = {propagation_constant:.6e}")
|
|
841
|
+
print(f"D = {dispersion:.3f}")
|
|
837
842
|
|
|
838
843
|
``load_fiber`` accepts the stem of any YAML definition in
|
|
839
844
|
``PyFiberModes/fiber_files``. A fiber can also be assembled programmatically
|
|
@@ -848,6 +853,8 @@ fiber index:
|
|
|
848
853
|
|
|
849
854
|
.. code-block:: python
|
|
850
855
|
|
|
856
|
+
from PyFiberModes.units import ureg
|
|
857
|
+
|
|
851
858
|
modes = fiber.find_modes(
|
|
852
859
|
families=("LP",),
|
|
853
860
|
max_nu=4,
|
|
@@ -869,9 +876,11 @@ values and whose columns correspond to modes.
|
|
|
869
876
|
|
|
870
877
|
.. code-block:: python
|
|
871
878
|
|
|
879
|
+
from PyFiberModes.units import ureg
|
|
880
|
+
|
|
872
881
|
import numpy as np
|
|
873
882
|
|
|
874
|
-
wavelengths = np.linspace(1260e-9, 1650e-9, 101)
|
|
883
|
+
wavelengths = np.linspace(1260e-9, 1650e-9, 101) * ureg.meter
|
|
875
884
|
result = fiber.sweep(
|
|
876
885
|
wavelengths,
|
|
877
886
|
modes=modes,
|
|
@@ -892,16 +901,18 @@ Create a two-dimensional field grid from a solved mode:
|
|
|
892
901
|
|
|
893
902
|
.. code-block:: python
|
|
894
903
|
|
|
904
|
+
from PyFiberModes.units import ureg
|
|
905
|
+
|
|
895
906
|
field = fiber.get_mode_field(
|
|
896
907
|
mode=LP01,
|
|
897
|
-
limit=20e-6,
|
|
908
|
+
limit=20e-6 * ureg.meter,
|
|
898
909
|
n_point=201,
|
|
899
910
|
)
|
|
900
911
|
|
|
901
912
|
electric_x = field.Ex()
|
|
902
913
|
intensity = field.Emod() ** 2
|
|
903
914
|
effective_area = field.get_effective_area()
|
|
904
|
-
confinement = field.get_confinement_factor(radius=4.1e-6)
|
|
915
|
+
confinement = field.get_confinement_factor(radius=4.1e-6 * ureg.meter)
|
|
905
916
|
power = field.get_power()
|
|
906
917
|
sx, sy, sz = field.get_poynting_vector()
|
|
907
918
|
|
|
@@ -921,17 +932,19 @@ scalar value to minimize.
|
|
|
921
932
|
|
|
922
933
|
.. code-block:: python
|
|
923
934
|
|
|
935
|
+
from PyFiberModes.units import ureg
|
|
936
|
+
|
|
924
937
|
from PyFiberModes import DesignParameter, optimize_fiber
|
|
925
938
|
|
|
926
939
|
core_radius = DesignParameter.layer_radius(
|
|
927
940
|
layer=0,
|
|
928
|
-
bounds=(3.0e-6, 6.0e-6),
|
|
941
|
+
bounds=(3.0e-6 * ureg.meter, 6.0e-6 * ureg.meter),
|
|
929
942
|
)
|
|
930
943
|
|
|
931
944
|
design = optimize_fiber(
|
|
932
945
|
fiber,
|
|
933
946
|
parameters=[core_radius],
|
|
934
|
-
objective=lambda candidate: abs(candidate.get_dispersion(LP01)),
|
|
947
|
+
objective=lambda candidate: abs(candidate.get_dispersion(LP01).to("ps / nm / km").magnitude),
|
|
935
948
|
constraints=(
|
|
936
949
|
lambda candidate: candidate.get_effective_index(LP01)
|
|
937
950
|
- candidate.last_layer.refractive_index,
|
|
@@ -956,10 +969,12 @@ electric field. Modal amplitudes then evolve according to
|
|
|
956
969
|
|
|
957
970
|
.. code-block:: python
|
|
958
971
|
|
|
972
|
+
from PyFiberModes.units import ureg
|
|
973
|
+
|
|
959
974
|
import numpy as np
|
|
960
975
|
from PyFiberModes import CoupledModeSystem
|
|
961
976
|
|
|
962
|
-
multimode_fiber = load_fiber("test_multimode_fiber", wavelength=1550e-9)
|
|
977
|
+
multimode_fiber = load_fiber("test_multimode_fiber", wavelength=1550e-9 * ureg.meter)
|
|
963
978
|
multimode_modes = multimode_fiber.find_modes(
|
|
964
979
|
families=("LP",),
|
|
965
980
|
max_nu=3,
|
|
@@ -968,16 +983,16 @@ electric field. Modal amplitudes then evolve according to
|
|
|
968
983
|
selected_modes = multimode_modes[:2]
|
|
969
984
|
fields = [multimode_fiber.get_mode_field(mode, n_point=151) for mode in selected_modes]
|
|
970
985
|
betas = [multimode_fiber.get_propagation_constant(mode) for mode in selected_modes]
|
|
971
|
-
relative_betas =
|
|
986
|
+
relative_betas = ureg.Quantity.from_list(betas) - betas[0]
|
|
972
987
|
mode_overlap = fields[0].overlap(fields[1])
|
|
973
988
|
|
|
974
989
|
coupling = np.array([
|
|
975
990
|
[0.0, 0.25],
|
|
976
991
|
[0.25, 0.0],
|
|
977
|
-
])
|
|
992
|
+
]) / ureg.meter
|
|
978
993
|
system = CoupledModeSystem(betas=relative_betas, coupling=coupling)
|
|
979
994
|
|
|
980
|
-
z = np.linspace(0, 20, 500)
|
|
995
|
+
z = np.linspace(0, 20, 500) * ureg.meter
|
|
981
996
|
propagation = system.propagate(initial=[1.0, 0.0], z=z)
|
|
982
997
|
modal_power = propagation.powers
|
|
983
998
|
|
|
@@ -12,7 +12,7 @@ from scipy.constants import c
|
|
|
12
12
|
from PyFiberModes.stepindex import StepIndex
|
|
13
13
|
from PyFiberModes import Mode
|
|
14
14
|
from PyFinitDiff.finite_difference_1D import get_function_derivative
|
|
15
|
-
from PyFiberModes.
|
|
15
|
+
from PyFiberModes._field import Field
|
|
16
16
|
|
|
17
17
|
from PyFiberModes.fundamentals import (
|
|
18
18
|
get_radial_field,
|
|
@@ -20,7 +20,7 @@ from PyFiberModes.fundamentals import (
|
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
from PyFiberModes import loader
|
|
23
|
-
from PyFiberModes.
|
|
23
|
+
from PyFiberModes._coordinates import CylindricalCoordinates
|
|
24
24
|
from PyFiberModes.exceptions import ConvergenceError, ValidationError
|
|
25
25
|
from PyFiberModes.materials import DEFAULT_MATERIALS, MaterialRegistry
|
|
26
26
|
from PyFiberModes.services import FieldAnalysis, ModalAnalysis
|
|
@@ -7,8 +7,8 @@ import numpy as np
|
|
|
7
7
|
from PyFiberModes.mode_instances import HE11
|
|
8
8
|
from PyFiberModes.mode import Mode
|
|
9
9
|
from dataclasses import dataclass
|
|
10
|
-
from PyFiberModes.
|
|
11
|
-
from PyFiberModes.
|
|
10
|
+
from PyFiberModes._coordinates import CartesianCoordinates
|
|
11
|
+
from PyFiberModes._coordinates import CylindricalCoordinates as CylindricalCoordinates # noqa: F401
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@dataclass
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (
|
|
31
|
+
__version__ = version = '1.0.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 0, 0)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -8,6 +8,7 @@ import numpy as np
|
|
|
8
8
|
|
|
9
9
|
from PyFiberModes.exceptions import ConvergenceError, ValidationError
|
|
10
10
|
from PyFiberModes.mode import Mode
|
|
11
|
+
from PyFiberModes.units import MODAL_UNITS, Quantity, magnitude, quantity
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@dataclass(frozen=True)
|
|
@@ -30,9 +31,9 @@ class ModeSweepResult:
|
|
|
30
31
|
"""
|
|
31
32
|
|
|
32
33
|
parameter_name: str
|
|
33
|
-
parameters: np.ndarray
|
|
34
|
+
parameters: np.ndarray | Quantity
|
|
34
35
|
modes: tuple[Mode, ...]
|
|
35
|
-
values: dict[str, np.ndarray]
|
|
36
|
+
values: dict[str, np.ndarray | Quantity]
|
|
36
37
|
|
|
37
38
|
def __getitem__(self, metric: str) -> np.ndarray:
|
|
38
39
|
"""Return the array associated with a metric name.
|
|
@@ -74,9 +75,11 @@ class ModeSweepResult:
|
|
|
74
75
|
One record for every parameter and mode combination.
|
|
75
76
|
"""
|
|
76
77
|
return [
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
{
|
|
79
|
+
self.parameter_name: parameter,
|
|
80
|
+
"mode": mode,
|
|
81
|
+
**{name: array[i, j] for name, array in self.values.items()},
|
|
82
|
+
}
|
|
80
83
|
for i, parameter in enumerate(self.parameters)
|
|
81
84
|
for j, mode in enumerate(self.modes)
|
|
82
85
|
]
|
|
@@ -137,11 +140,7 @@ def find_modes(fiber, families=("LP",), max_nu=6, max_m=6) -> tuple[Mode, ...]:
|
|
|
137
140
|
for mode in candidate_modes(families, max_nu, max_m):
|
|
138
141
|
try:
|
|
139
142
|
effective_index = fiber.get_effective_index(mode)
|
|
140
|
-
guided =
|
|
141
|
-
fiber.last_layer.refractive_index
|
|
142
|
-
< effective_index
|
|
143
|
-
<= fiber.maximum_index
|
|
144
|
-
)
|
|
143
|
+
guided = fiber.last_layer.refractive_index < effective_index <= fiber.maximum_index
|
|
145
144
|
if np.isfinite(effective_index) and guided:
|
|
146
145
|
found.append(mode)
|
|
147
146
|
except ConvergenceError:
|
|
@@ -167,8 +166,8 @@ def sweep_modes(
|
|
|
167
166
|
----------
|
|
168
167
|
fiber : Fiber
|
|
169
168
|
Fiber used as the immutable sweep template.
|
|
170
|
-
parameters : iterable of
|
|
171
|
-
Ordered parameter values.
|
|
169
|
+
parameters : pint.Quantity or iterable of pint.Quantity
|
|
170
|
+
Ordered parameter values with explicit units for public fibers.
|
|
172
171
|
modes : sequence of Mode, optional
|
|
173
172
|
Modes to evaluate. When omitted, modes are discovered automatically.
|
|
174
173
|
parameter_name : str, optional
|
|
@@ -195,7 +194,26 @@ def sweep_modes(
|
|
|
195
194
|
If ``parameters`` is empty or not one-dimensional, or when a custom
|
|
196
195
|
parameter is requested without a setter.
|
|
197
196
|
"""
|
|
198
|
-
|
|
197
|
+
unit_aware = hasattr(fiber, "_si")
|
|
198
|
+
parameter_unit = None
|
|
199
|
+
if unit_aware:
|
|
200
|
+
if isinstance(parameters, Quantity):
|
|
201
|
+
parameter_unit = parameters.units
|
|
202
|
+
if setter is None:
|
|
203
|
+
magnitude(parameters, "meter", "parameters")
|
|
204
|
+
parameters = np.asarray(parameters.magnitude, dtype=float)
|
|
205
|
+
else:
|
|
206
|
+
items = tuple(parameters)
|
|
207
|
+
if not items:
|
|
208
|
+
raise ValueError("parameters must be a non-empty one-dimensional sequence")
|
|
209
|
+
parameter_unit = items[0].units if isinstance(items[0], Quantity) else "meter"
|
|
210
|
+
parameters = np.asarray(
|
|
211
|
+
[magnitude(item, parameter_unit, "parameters") for item in items], dtype=float
|
|
212
|
+
)
|
|
213
|
+
if setter is None:
|
|
214
|
+
quantity(parameters, parameter_unit).to("meter")
|
|
215
|
+
else:
|
|
216
|
+
parameters = np.asarray(tuple(parameters), dtype=float)
|
|
199
217
|
if parameters.ndim != 1 or not len(parameters):
|
|
200
218
|
raise ValueError("parameters must be a non-empty one-dimensional sequence")
|
|
201
219
|
if setter is None:
|
|
@@ -205,11 +223,14 @@ def sweep_modes(
|
|
|
205
223
|
def setter(current_fiber, value):
|
|
206
224
|
"""Update wavelength for the default sweep behavior."""
|
|
207
225
|
current_fiber.update_wavelength(value)
|
|
226
|
+
|
|
208
227
|
if modes is None:
|
|
209
228
|
discovered = []
|
|
210
229
|
for parameter in parameters:
|
|
211
230
|
parameter_fiber = deepcopy(fiber)
|
|
212
|
-
setter(
|
|
231
|
+
setter(
|
|
232
|
+
parameter_fiber, quantity(parameter, parameter_unit) if unit_aware else parameter
|
|
233
|
+
)
|
|
213
234
|
for mode in find_modes(parameter_fiber, families, max_nu, max_m):
|
|
214
235
|
if mode not in discovered:
|
|
215
236
|
discovered.append(mode)
|
|
@@ -218,17 +239,22 @@ def sweep_modes(
|
|
|
218
239
|
values = {metric: np.full((len(parameters), len(modes)), np.nan) for metric in metrics}
|
|
219
240
|
parameter_fibers = tuple(deepcopy(fiber) for _ in parameters)
|
|
220
241
|
for parameter_fiber, parameter in zip(parameter_fibers, parameters, strict=True):
|
|
221
|
-
setter(parameter_fiber,
|
|
242
|
+
setter(parameter_fiber, quantity(parameter, parameter_unit) if unit_aware else parameter)
|
|
222
243
|
|
|
223
244
|
for i, parameter_fiber in enumerate(parameter_fibers):
|
|
224
|
-
metric_functions = {
|
|
225
|
-
metric: getattr(parameter_fiber, f"get_{metric}") for metric in metrics
|
|
226
|
-
}
|
|
245
|
+
metric_functions = {metric: getattr(parameter_fiber, f"get_{metric}") for metric in metrics}
|
|
227
246
|
for metric, metric_function in metric_functions.items():
|
|
228
247
|
for j, mode in enumerate(modes):
|
|
229
248
|
try:
|
|
230
249
|
value = metric_function(mode)
|
|
231
|
-
values[metric][i, j] =
|
|
250
|
+
values[metric][i, j] = (
|
|
251
|
+
(value.to(MODAL_UNITS[metric]).magnitude if unit_aware else value)
|
|
252
|
+
if np.isfinite(value)
|
|
253
|
+
else np.nan
|
|
254
|
+
)
|
|
232
255
|
except ConvergenceError:
|
|
233
256
|
pass
|
|
257
|
+
if unit_aware:
|
|
258
|
+
parameters = quantity(parameters, parameter_unit)
|
|
259
|
+
values = {metric: quantity(array, MODAL_UNITS[metric]) for metric, array in values.items()}
|
|
234
260
|
return ModeSweepResult(parameter_name, parameters, modes, values)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Length-valued Cartesian and cylindrical coordinate grids."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from PyFiberModes import _coordinates
|
|
7
|
+
from PyFiberModes.units import Angle, Length, magnitude, quantity
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class CylindricalCoordinates:
|
|
12
|
+
"""Cylindrical positions with length-valued rho/z and angle-valued phi."""
|
|
13
|
+
|
|
14
|
+
rho: Length
|
|
15
|
+
phi: Angle
|
|
16
|
+
z: Length
|
|
17
|
+
|
|
18
|
+
def __post_init__(self):
|
|
19
|
+
"""Validate and normalize coordinate quantities."""
|
|
20
|
+
self.rho = quantity(magnitude(self.rho, "meter", "rho"), "meter")
|
|
21
|
+
self.phi = quantity(magnitude(self.phi, "radian", "phi"), "radian")
|
|
22
|
+
self.z = quantity(magnitude(self.z, "meter", "z"), "meter")
|
|
23
|
+
|
|
24
|
+
def to_cartesian(self):
|
|
25
|
+
"""Convert cylindrical positions to Cartesian positions."""
|
|
26
|
+
return CartesianCoordinates(
|
|
27
|
+
x=self.rho * np.cos(self.phi),
|
|
28
|
+
y=self.rho * np.sin(self.phi),
|
|
29
|
+
z=self.z,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def to_cylindrical(self):
|
|
33
|
+
"""Return these cylindrical positions."""
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class CartesianCoordinates:
|
|
39
|
+
"""Cartesian positions with explicit length units on every axis."""
|
|
40
|
+
|
|
41
|
+
x: Length
|
|
42
|
+
y: Length
|
|
43
|
+
z: Length
|
|
44
|
+
is_structured: bool = False
|
|
45
|
+
is_3D: bool = False
|
|
46
|
+
|
|
47
|
+
def __post_init__(self):
|
|
48
|
+
"""Validate lengths and normalize numerical coordinate arrays to meters."""
|
|
49
|
+
for name in ("x", "y", "z"):
|
|
50
|
+
setattr(
|
|
51
|
+
self,
|
|
52
|
+
name,
|
|
53
|
+
quantity(
|
|
54
|
+
np.asarray(magnitude(getattr(self, name), "meter", name), dtype=float), "meter"
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def _from_si(cls, coordinates):
|
|
60
|
+
"""Attach length units to a numerical coordinate grid."""
|
|
61
|
+
return cls(
|
|
62
|
+
x=quantity(coordinates.x, "meter"),
|
|
63
|
+
y=quantity(coordinates.y, "meter"),
|
|
64
|
+
z=quantity(coordinates.z, "meter"),
|
|
65
|
+
is_structured=coordinates.is_structured,
|
|
66
|
+
is_3D=coordinates.is_3D,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def x_boundaries(self):
|
|
71
|
+
"""Minimum and maximum x positions."""
|
|
72
|
+
return self.x.min(), self.x.max()
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def y_boundaries(self):
|
|
76
|
+
"""Minimum and maximum y positions."""
|
|
77
|
+
return self.y.min(), self.y.max()
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def dx(self):
|
|
81
|
+
"""Structured grid spacing along x."""
|
|
82
|
+
if not self.is_structured:
|
|
83
|
+
raise ValueError("dx value cannot be inferred from an unstructured mesh")
|
|
84
|
+
return quantity(np.diff(np.unique(self.x.magnitude))[0], self.x.units)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def dy(self):
|
|
88
|
+
"""Structured grid spacing along y."""
|
|
89
|
+
if not self.is_structured:
|
|
90
|
+
raise ValueError("dy value cannot be inferred from an unstructured mesh")
|
|
91
|
+
return quantity(np.diff(np.unique(self.y.magnitude))[0], self.y.units)
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def generate_from_square(cls, length: Length, center=None, n_points: int = 100):
|
|
95
|
+
"""Generate a square grid with a length-valued side and center."""
|
|
96
|
+
center_si = (
|
|
97
|
+
(0.0, 0.0)
|
|
98
|
+
if center is None
|
|
99
|
+
else tuple(magnitude(item, "meter", "center") for item in center)
|
|
100
|
+
)
|
|
101
|
+
return cls._from_si(
|
|
102
|
+
_coordinates.CartesianCoordinates.generate_from_square(
|
|
103
|
+
length=magnitude(length, "meter", "length"),
|
|
104
|
+
center=center_si,
|
|
105
|
+
n_points=n_points,
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def generate_from_boundaries(cls, x_limits, y_limits, z_limits, x_points, y_points, z_points):
|
|
111
|
+
"""Generate a structured grid from length-valued axis limits."""
|
|
112
|
+
limits = [
|
|
113
|
+
tuple(magnitude(item, "meter", "limits") for item in axis)
|
|
114
|
+
for axis in (x_limits, y_limits, z_limits)
|
|
115
|
+
]
|
|
116
|
+
return cls._from_si(
|
|
117
|
+
_coordinates.CartesianCoordinates.generate_from_boundaries(
|
|
118
|
+
x_limits=limits[0],
|
|
119
|
+
y_limits=limits[1],
|
|
120
|
+
z_limits=limits[2],
|
|
121
|
+
x_points=x_points,
|
|
122
|
+
y_points=y_points,
|
|
123
|
+
z_points=z_points,
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def to_cylindrical(self):
|
|
128
|
+
"""Convert positions to cylindrical coordinates."""
|
|
129
|
+
return CylindricalCoordinates(
|
|
130
|
+
rho=np.sqrt(self.x**2 + self.y**2),
|
|
131
|
+
phi=np.arctan2(self.y, self.x),
|
|
132
|
+
z=self.z,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def centering(self):
|
|
136
|
+
"""Center each axis in place."""
|
|
137
|
+
self.x -= self.x.mean()
|
|
138
|
+
self.y -= self.y.mean()
|
|
139
|
+
self.z -= self.z.mean()
|
|
140
|
+
|
|
141
|
+
def shift_coordinates(self, shift):
|
|
142
|
+
"""Shift the grid by three length-valued displacements."""
|
|
143
|
+
# Validate all inputs before mutating the grid.
|
|
144
|
+
values = [quantity(magnitude(item, "meter", "shift"), "meter") for item in shift]
|
|
145
|
+
self.x += values[0]
|
|
146
|
+
self.y += values[1]
|
|
147
|
+
self.z += values[2]
|
|
148
|
+
|
|
149
|
+
def scale_coordinates(self, scale):
|
|
150
|
+
"""Scale axes by dimensionless factors."""
|
|
151
|
+
self.x *= float(scale[0])
|
|
152
|
+
self.y *= float(scale[1])
|
|
153
|
+
self.z *= float(scale[2])
|
|
@@ -4,6 +4,7 @@ from itertools import product
|
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
import numpy as np
|
|
6
6
|
from PyFiberModes.fiber import Fiber
|
|
7
|
+
from PyFiberModes.units import Length, RefractiveIndex, magnitude, quantity, ureg
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
@dataclass
|
|
@@ -15,9 +16,9 @@ class ProxyLayer:
|
|
|
15
16
|
----------
|
|
16
17
|
name : str
|
|
17
18
|
Name of the layer.
|
|
18
|
-
radius :
|
|
19
|
+
radius : pint.Quantity
|
|
19
20
|
Radius values for the layer (in meters).
|
|
20
|
-
index :
|
|
21
|
+
index : pint.Quantity
|
|
21
22
|
Refractive index values for the layer.
|
|
22
23
|
"""
|
|
23
24
|
name: str
|
|
@@ -27,8 +28,8 @@ class ProxyLayer:
|
|
|
27
28
|
def __post_init__(self):
|
|
28
29
|
"""Normalize scalar layer parameters into one-dimensional arrays."""
|
|
29
30
|
self.name = [self.name]
|
|
30
|
-
self.radius = np.atleast_1d(self.radius)
|
|
31
|
-
self.index = np.atleast_1d(self.index)
|
|
31
|
+
self.radius = quantity(np.atleast_1d(magnitude(self.radius, "meter", "radius")), "meter")
|
|
32
|
+
self.index = quantity(np.atleast_1d(magnitude(self.index, "dimensionless", "index")), "dimensionless")
|
|
32
33
|
|
|
33
34
|
def get_generator(self):
|
|
34
35
|
"""
|
|
@@ -48,40 +49,40 @@ class FiberFactory:
|
|
|
48
49
|
|
|
49
50
|
Parameters
|
|
50
51
|
----------
|
|
51
|
-
wavelength :
|
|
52
|
+
wavelength : TypedUnit.Length
|
|
52
53
|
Wavelength (in meters) used for fiber simulations.
|
|
53
54
|
|
|
54
55
|
Attributes
|
|
55
56
|
----------
|
|
56
57
|
layers_list : list[ProxyLayer]
|
|
57
58
|
List of ProxyLayer objects representing the layers of the fiber.
|
|
58
|
-
wavelength :
|
|
59
|
+
wavelength : TypedUnit.Length
|
|
59
60
|
Wavelength used in simulations.
|
|
60
61
|
"""
|
|
61
62
|
|
|
62
|
-
def __init__(self, wavelength:
|
|
63
|
+
def __init__(self, wavelength: Length):
|
|
63
64
|
"""Initialize an empty fiber-configuration factory.
|
|
64
65
|
|
|
65
66
|
Parameters
|
|
66
67
|
----------
|
|
67
|
-
wavelength :
|
|
68
|
+
wavelength : TypedUnit.Length
|
|
68
69
|
Vacuum wavelength in meters for generated fibers.
|
|
69
70
|
"""
|
|
70
71
|
self.layers_list = []
|
|
71
|
-
self.wavelength = wavelength
|
|
72
|
+
self.wavelength = quantity(magnitude(wavelength, "meter", "wavelength"), "meter")
|
|
72
73
|
|
|
73
|
-
def add_layer(self, index:
|
|
74
|
+
def add_layer(self, index: RefractiveIndex, name: str = "", radius: Length = np.inf * ureg.meter):
|
|
74
75
|
"""
|
|
75
76
|
Add a new layer to the fiber factory.
|
|
76
77
|
|
|
77
78
|
Parameters
|
|
78
79
|
----------
|
|
79
|
-
index :
|
|
80
|
+
index : TypedUnit.RefractiveIndex
|
|
80
81
|
Refractive index of the layer.
|
|
81
82
|
name : str, optional
|
|
82
83
|
Name of the layer (default is an empty string).
|
|
83
|
-
radius :
|
|
84
|
-
Radius of the layer (
|
|
84
|
+
radius : TypedUnit.Length, optional
|
|
85
|
+
Radius of the layer (defaults to an unbounded outer layer).
|
|
85
86
|
"""
|
|
86
87
|
layer = ProxyLayer(name=name, radius=radius, index=index)
|
|
87
88
|
self.layers_list.append(layer)
|