├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .readthedocs.yml
├── .zenndo.json
├── LICENSE
├── MANIFEST.in
├── README.md
├── data
├── neff_pcf.mat
└── supercontinuum_3pulses.png
├── docs
├── Makefile
├── _static
│ ├── input_pulse.png
│ ├── plot_raman.png
│ └── supercontinuum_3pulses.png
├── code_documentation.rst
├── conf.py
├── dispersion.rst
├── envelopes.rst
├── examples
│ ├── _static
│ │ ├── 3rd_order_soliton.png
│ │ ├── gvd.png
│ │ ├── spm.png
│ │ ├── spm_gvd.png
│ │ ├── supercontinuum_3pulses.png
│ │ ├── test_dispersion.png
│ │ ├── test_nonlinearity.png
│ │ └── test_raman.png
│ ├── example_dispersive_wave.rst
│ ├── example_effective_mode_area.rst
│ ├── example_soliton.rst
│ ├── example_supercontinuum.rst
│ └── index.rst
├── gnlse.rst
├── gnlse_intro.rst
├── import_export.rst
├── index.rst
├── make.bat
├── nonlinearity.rst
├── raman_response.rst
├── references.rst
├── requirements.txt
└── visualisation.rst
├── examples
├── plot_Raman_response.py
├── plot_input_pulse.py
├── test_3rd_order_soliton.py
├── test_Dudley.py
├── test_dispersion.py
├── test_gvd.py
├── test_import_export.py
├── test_nonlinearity.py
├── test_raman.py
├── test_spm+gvd.py
├── test_spm.py
└── test_wl_del_freq.py
├── gnlse
├── __init__.py
├── common.py
├── dispersion.py
├── envelopes.py
├── gnlse.py
├── import_export.py
├── nonlinearity.py
├── raman_response.py
└── visualization.py
├── requirements.txt
├── setup.py
├── test-requirements.txt
└── tox.ini
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | tests:
7 | runs-on: ubuntu-latest
8 | container:
9 | image: python:3.9
10 | steps:
11 | - name: Packages
12 | run: pip install 'tox<4'
13 | - name: Checkout
14 | uses: actions/checkout@v3
15 | - name: Tox
16 | run: |
17 | git config --global --add safe.directory "${GITHUB_WORKSPACE}"
18 | tox -v
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.mat
4 | *.py[cod]
5 | *$py.class
6 |
7 | # C extensions
8 | *.so
9 |
10 | # Distribution / packaging
11 | .Python
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | pip-wheel-metadata/
25 | share/python-wheels/
26 | *.egg-info/
27 | .installed.cfg
28 | *.egg
29 | MANIFEST
30 |
31 | # PyInstaller
32 | # Usually these files are written by a python script from a template
33 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
34 | *.manifest
35 | *.spec
36 |
37 | # Installer logs
38 | pip-log.txt
39 | pip-delete-this-directory.txt
40 |
41 | # Unit test / coverage reports
42 | htmlcov/
43 | .tox/
44 | .nox/
45 | .coverage
46 | .coverage.*
47 | .cache
48 | nosetests.xml
49 | coverage.xml
50 | *.cover
51 | *.py,cover
52 | .hypothesis/
53 | .pytest_cache/
54 |
55 | # Translations
56 | *.mo
57 | *.pot
58 |
59 | # Django stuff:
60 | *.log
61 | local_settings.py
62 | db.sqlite3
63 | db.sqlite3-journal
64 |
65 | # Flask stuff:
66 | instance/
67 | .webassets-cache
68 |
69 | # Scrapy stuff:
70 | .scrapy
71 |
72 | # Sphinx documentation
73 | docs/_build/
74 |
75 | # PyBuilder
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | .python-version
87 |
88 | # pipenv
89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
92 | # install all needed dependencies.
93 | #Pipfile.lock
94 |
95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
96 | __pypackages__/
97 |
98 | # Celery stuff
99 | celerybeat-schedule
100 | celerybeat.pid
101 |
102 | # SageMath parsed files
103 | *.sage.py
104 |
105 | # Environments
106 | .env
107 | .venv
108 | env/
109 | venv/
110 | ENV/
111 | env.bak/
112 | venv.bak/
113 |
114 | # Spyder project settings
115 | .spyderproject
116 | .spyproject
117 |
118 | # Rope project settings
119 | .ropeproject
120 |
121 | # mkdocs documentation
122 | /site
123 |
124 | # mypy
125 | .mypy_cache/
126 | .dmypy.json
127 | dmypy.json
128 |
129 | # Pyre type checker
130 | .pyre/
131 |
132 | # Built Sphinx documentation
133 | docs/_build/
134 |
135 |
--------------------------------------------------------------------------------
/.readthedocs.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | sphinx:
4 | configuration: docs/conf.py
5 |
6 | python:
7 | version: 3.7
8 | install:
9 | - requirements: docs/requirements.txt
10 |
--------------------------------------------------------------------------------
/.zenndo.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "
The propagation of pulses in optical fibers is described by the generalized nonlinear Schrodinger equation (GNLSE), which takes into account the fiber losses, nonlinear effects, and higher-order chromatic dispersion. The GNLSE is a partial differential equation, whose order depends on the accounted nonlinear and dispersion effects. We present gnlse-python, an nonlinear optics modeling toolbox that contains a rich set of components and modules to solve GNLSE using the split-step Fourier transform method (SSFM). The numerical solver is freely available, implemented in Python language and includes a number of optical fiber analysis tools.
",
3 | "license": "MIT",
4 | "title": "WUST-FOG/gnlse-python: v2.0.0 bulit on 26 April 2021",
5 | "version": "2.0.0",
6 | "upload_type": "software",
7 | "publication_date": "2022-04-26",
8 | "creators": [
9 | {
10 | "affiliation": "Wroc\u0142aw University of Science and Technology",
11 | "name": "Sylwia Majchrowska"
12 | },
13 | {
14 | "affiliation": "Wroc\u0142aw University of Science and Technology",
15 | "name": "Pawe\u0142 Redman"
16 | },
17 | {
18 | "affiliation": "Wroc\u0142aw University of Science and Technology",
19 | "name": "Magdalena Zatorska"
20 | },
21 | {
22 | "affiliation": "Wroc\u0142aw University of Science and Technology",
23 | "name": "Daniel Szulc"
24 | },
25 | {
26 | "affiliation": "Wroc\u0142aw University of Science and Technology",
27 | "name": "Adam Paw\u0142owski"
28 | },
29 | {
30 | "affiliation": "Wroc\u0142aw University of Science and Technology",
31 | "name": "Karol Tarnowski"
32 | }
33 |
34 | ],
35 | "access_right": "open",
36 | "related_identifiers": [
37 | {
38 | "scheme": "url",
39 | "identifier": "https://github.com/WUST-FOG/gnlse-python/tree/2.0.0",
40 | "relation": "isSupplementTo"
41 | },
42 | {
43 | "scheme": "doi",
44 | "identifier": "10.5281/zenodo.6495720",
45 | "relation": "isVersionOf"
46 | }
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 WUST-FOG
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include gnlse *.py
2 | include README
3 | include LICENSE
4 | include requirements.txt
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | [](https://doi.org/10.5281/zenodo.6495720)
3 | 
4 |
5 | # GNLSE: Nonlinear optics modeling tool for optical fibers
6 |
7 | `gnlse` is a Python set of scripts for solving
8 | Generalized Nonlinear Schrodringer Equation. It is one of the WUST-FOG students
9 | projects developed by [Fiber Optics Group, WUST](http://www.fog.pwr.edu.pl/).
10 |
11 | Complete documentation is available at
12 | [https://gnlse.readthedocs.io](https://gnlse.readthedocs.io).
13 |
14 | ## Installation
15 |
16 | ### Using pip
17 |
18 | ```
19 | pip install gnlse
20 | ```
21 |
22 | ### From scratch
23 |
24 | 1. Create a virtual environment with `python -m venv gnlse` or using `conda`.
25 | 2. Activate it with `. gnlse/bin/activate`.
26 | 3. Clone this repository `git clone https://github.com/WUST-FOG/gnlse-python.git`
27 | 4. Install gnlse package `pip install .` (or `pip install -v -e .` for develop mode) or set `PYTHONPATH` enviroment variable
28 |
29 | ```bash
30 | python -m venv gnlse
31 | . gnlse/bin/activate
32 | git clone https://github.com/WUST-FOG/gnlse-python.git
33 | cd gnlse-python
34 | pip install .
35 | ```
36 |
37 | ## Usage
38 |
39 | We provided some examples in `examples` subdirectory. They can be run by typing
40 | name of the script without any arguments.
41 |
42 | Example:
43 |
44 | ```bash
45 | cd gnlse-python/examples
46 |
47 | python test_Dudley.py
48 | ```
49 |
50 | And you expect to visualise supercontinuum generation process in use of 3 types
51 | of pulses (simulation similar to Fig.3 of Dudley et. al, RMP 78 1135 (2006)):
52 |
53 | 
54 |
55 | ### Major features
56 |
57 | - **Modular Design**
58 |
59 | Main core of gnlse module is derived from the RK4IP matlab script
60 | written by J.C.Travers, H. Frosz and J.M. Dudley
61 | that is provided in "Supercontinuum Generation in Optical Fibers",
62 | edited by J. M. Dudley and J. R. Taylor (Cambridge 2010).
63 | The toolbox prepares integration using SCIPYs ode solvers (adaptive step size).
64 | We decompose the solver framework into different components
65 | and one can easily construct a customized simulations
66 | by accounting different physical phenomena, ie. self stepening, Raman response.
67 |
68 | - **Raman response models**
69 |
70 | We implement three different raman response functions:
71 | - 'blowwood': Blow and D. Wood, IEEE J. of Quant. Elec., vol. 25, no. 12, pp. 2665–2673, Dec. 1989,
72 | - 'linagrawal': Lin and Agrawal, Opt. Lett., vol. 31, no. 21, pp. 3086–3088, Nov. 2006,
73 | - 'hollenbeck': Hollenbeck and Cantrell, J. Opt. Soc. Am. B, vol. 19, no. 12, Dec. 2002.
74 |
75 | - **Nonlinearity**
76 |
77 | We implement the possibility to account effective mode area's dependence on frequency:
78 | - provide float value for gamma (effective nonlinear coefficient)
79 | - 'NonlinearityFromEffectiveArea': introduce effective mode area's dependence on frequency (J. Laegsgaard, Opt. Express, vol. 15, no. 24, pp. 16110-16123, Nov. 2007).
80 |
81 | - **Dispersion operator**
82 |
83 | We implement two version of dispersion operator:
84 | - dispersion calculated from Taylor expansion,
85 | - dispersion calculated from effective refractive indicies.
86 |
87 | - **Available demos**
88 |
89 | We prepare few examples in `examples` subdirectory:
90 | - plot_input_pulse.py: plots envelope of different pulse shapes,
91 | - plot_Raman_response.py: plots different Raman in temporal domain,
92 | - test_3rd_order_soliton.py: evolution of the spectral and temporal characteristics of the 3rd order soliton,
93 | - test_dispersion.py: example of supercontinuum generation using different dispersion operators,
94 | - test_nonlinearity.py: example of supercontinuum generation using different GNLSE and M-GNLSE (take into account mode profile dispersion),
95 | - test_Dudley.py: example of supercontinuum generation with three types of input pulse,
96 | - test_gvd.py: example of pulse broadening due to group velocity dispersion,
97 | - test_import_export.py: example of saving file with `.mat` extension,
98 | - test_raman.py: example of soliton fision for diffrent raman response functions,
99 | - test_spm.py: example of self phase modulation,
100 | - test_spm+gvd.py: example of generation of 1st order soliton.
101 |
102 | For more advanced examples with Coupled Generalized Nonlinear Schrodringer Equation with two modes please refer to [cgnlse-python](https://github.com/WUST-FOG/cgnlse-python).
103 |
104 | ## Release History
105 |
106 | v2.0.1 was released in 08/01/2023.
107 | The main branch works with **python 3.9**.
108 |
109 | * **2.0.0 -> Apr 26th, 2022**
110 | * CHANGE: Code refactor - rename envelopes module
111 | * FIX: Fixed extrapolation for nonlinear coefficient
112 | * **1.1.3 -> Feb 13th, 2022**
113 | * FIX: Shift scalling data for interpolated dispersion
114 | * **1.1.2 -> Aug 30th, 2021**
115 | * ADD: Continious wave envelope
116 | * FIX: Shift scalling data for nonlinear coefficient
117 | * **1.1.1 -> Aug 28th, 2021**
118 | * CHANGE: Minor bug fix with scaling
119 | * CHANGE: Few minor changes in the documentation
120 | * **1.1.0 -> Aug 21st, 2021**
121 | * Modified-GNLSE extension
122 | * CHANGE: Code refactor - relocate GNLSE's attribiutes setting into constructor
123 | * ADD: Possibility to take into account the effective mode area's dependence on frequency
124 | * **1.0.0 -> Aug 13th, 2020**
125 | * The first proper release
126 | * CHANGE: Complete documentation and code
127 |
128 | ## Authors
129 |
130 | - [Pawel Redman](https://redman.xyz/)
131 | - [Magda Zatorska](https://github.com/magdazatorska)
132 | - [Adam Pawlowski](https://github.com/adampawl)
133 | - [Daniel Szulc](http://szulc.xyz/)
134 | - [Sylwia Majchrowska](https://majsylw.netlify.app/)
135 | - [Karol Tarnowski](http://www.tarnowski.wppt.pwr.edu.pl/)
136 |
137 | ## Acknowledgement
138 |
139 | *gnlse-python* is an open source project that is contributed by researchers,
140 | engineers, and students from Wroclaw University of Science and Technology
141 | as a part of Fiber Optics Group's nonlinear simulations projects.
142 | The python code based on MATLAB code published in
143 | 'Supercontinuum Generation in Optical Fibers'
144 | by J. M. Dudley and J. R. Taylor, available at
145 | [http://scgbook.info/](http://scgbook.info/).
146 |
147 | ## Citation
148 |
149 | If you find this code useful in your research, please consider [citing](https://arxiv.org/abs/2110.00298):
150 |
151 | ```
152 | @misc{redman2021gnlsepython,
153 | title={gnlse-python: Open Source Software to Simulate
154 | Nonlinear Light Propagation In Optical Fibers},
155 | author={Pawel Redman and Magdalena Zatorska and Adam Pawlowski
156 | and Daniel Szulc and Sylwia Majchrowska and Karol Tarnowski},
157 | year={2021},
158 | eprint={2110.00298},
159 | archivePrefix={arXiv},
160 | primaryClass={physics.optics}
161 | }
162 | ```
163 |
164 | ## Contributing
165 | Pull requests are welcome.
166 | For major changes, please open an issue first to discuss
167 | what you would like to change.
168 |
169 | Please make sure to update example tests as appropriate.
170 |
171 | ## License
172 | [MIT](https://choosealicense.com/licenses/mit/)
173 |
--------------------------------------------------------------------------------
/data/neff_pcf.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/data/neff_pcf.mat
--------------------------------------------------------------------------------
/data/supercontinuum_3pulses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/data/supercontinuum_3pulses.png
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/_static/input_pulse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/_static/input_pulse.png
--------------------------------------------------------------------------------
/docs/_static/plot_raman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/_static/plot_raman.png
--------------------------------------------------------------------------------
/docs/_static/supercontinuum_3pulses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/_static/supercontinuum_3pulses.png
--------------------------------------------------------------------------------
/docs/code_documentation.rst:
--------------------------------------------------------------------------------
1 | GNLSE package documentation
2 | ===========================
3 |
4 | Pulse envelopes
5 | -----------------
6 |
7 | This module allows one to model proper input envelope as the given initial
8 | conditions to solve Generalized Nonlinear Schrodiner Equation (GNLSE).
9 |
10 | .. autosummary::
11 |
12 | gnlse.SechEnvelope
13 | gnlse.GaussianEnvelope
14 | gnlse.LorentzianEnvelope
15 |
16 | GNLSE model
17 | -----------
18 |
19 | This part of the module is its core, and it implements the split-step Fourier
20 | method to solve the GNLSE.
21 |
22 | .. autosummary::
23 |
24 | gnlse.GNLSESetup
25 | gnlse.GNLSE
26 | gnlse.Solution
27 |
28 | Dispersion operators
29 | --------------------
30 |
31 | Package supports two dispersion operators: calculated from a Taylor expansion
32 | and calculated from effective refractive indices.
33 |
34 | .. autosummary::
35 |
36 | gnlse.DispersionFiberFromTaylor
37 | gnlse.DispersionFiberFromInterpolation
38 |
39 | Nonlinear coefficient
40 | ---------------------
41 |
42 | The guided fiber mode has a certain effective mode area, which in general
43 | depends on frequency. Package supports two possibilites to account
44 | the parameter: by giving the scalar value for gamma at central wavelength
45 | or calculated values for freqency range from effective refractive indices
46 | and effective mode area (experimantal or simulated data)
47 | Mode profile dispersion in GNLSE is accounted based on algorithm
48 | described in [J07]_.
49 |
50 | .. autosummary::
51 |
52 | gnlse.NonlinearityFromEffectiveArea
53 |
54 | Raman responses
55 | ---------------
56 |
57 | Package supports three Raman response functions: ``blowwood`` [BW89]_,
58 | ``linagrawal`` [LA06]_ and ``hollenbeck`` [HC02]_.
59 |
60 | .. autosummary::
61 |
62 | gnlse.raman_blowwood
63 | gnlse.raman_holltrell
64 | gnlse.raman_linagrawal
65 |
66 | Visualisation
67 | -------------
68 |
69 | Various plotting functions for visualizing GNLSE simulations using Matplotlib
70 | library are prepared.
71 |
72 | .. autosummary::
73 |
74 | gnlse.plot_wavelength_vs_distance
75 | gnlse.plot_delay_vs_distance
76 | gnlse.quick_plot
77 |
78 | Importing and exporting
79 | -----------------------
80 |
81 | The following functions allow one to read and write data as \\*.mat files.
82 |
83 | .. autosummary::
84 |
85 | gnlse.read_mat
86 | gnlse.write_mat
87 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 |
5 | sys.path.insert(0, os.path.abspath('..'))
6 |
7 | project = 'gnlse-python'
8 | copyright = '2020, Developers of gnlse-python'
9 | author = 'Developers of gnlse-python'
10 |
11 | master_doc = 'index'
12 |
13 |
14 | extensions = [
15 | 'sphinx.ext.autodoc',
16 | 'sphinx.ext.autosummary',
17 | 'numpydoc',
18 | ]
19 |
20 | autodoc_mock_imports = [
21 | 'hdf5storage',
22 | 'matplotlib',
23 | 'matplotlib.pyplot',
24 | 'numpy',
25 | 'pyfftw',
26 | 'scipy',
27 | 'scipy.integrate',
28 | 'scipy.interpolate',
29 | 'tqdm',
30 | ]
31 |
32 | autosummary_generate = True
33 | numpydoc_show_class_members = False
34 |
35 | templates_path = ['_templates']
36 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
37 | html_theme = 'sphinx_rtd_theme'
38 | html_static_path = ['_static']
39 |
--------------------------------------------------------------------------------
/docs/dispersion.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Dispersion operators
4 | ====================
5 |
6 | Package supports two dispersion operators: calculated from a Taylor expansion
7 | and calculated from effective refractive indices.
8 |
9 | .. autoclass:: gnlse.DispersionFiberFromTaylor
10 | .. autoclass:: gnlse.DispersionFiberFromInterpolation
11 |
--------------------------------------------------------------------------------
/docs/envelopes.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Pulse envelopes
4 | =================
5 |
6 | In physics, the envelope of an oscillating signal is a smooth curve
7 | outlining its extremes. The given envelope function is a function of time of
8 | input pulse. The below figure illustrates a modulated waves varying between
9 | an upper and a lower envelope of four types of optical signal.
10 |
11 | .. image:: _static/input_pulse.png
12 | :alt: example_input_pulse
13 |
14 | .. autoclass:: gnlse.SechEnvelope
15 | .. autoclass:: gnlse.GaussianEnvelope
16 | .. autoclass:: gnlse.LorentzianEnvelope
17 | .. autoclass:: gnlse.CWEnvelope
18 |
--------------------------------------------------------------------------------
/docs/examples/_static/3rd_order_soliton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/examples/_static/3rd_order_soliton.png
--------------------------------------------------------------------------------
/docs/examples/_static/gvd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/examples/_static/gvd.png
--------------------------------------------------------------------------------
/docs/examples/_static/spm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/examples/_static/spm.png
--------------------------------------------------------------------------------
/docs/examples/_static/spm_gvd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/examples/_static/spm_gvd.png
--------------------------------------------------------------------------------
/docs/examples/_static/supercontinuum_3pulses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/examples/_static/supercontinuum_3pulses.png
--------------------------------------------------------------------------------
/docs/examples/_static/test_dispersion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/examples/_static/test_dispersion.png
--------------------------------------------------------------------------------
/docs/examples/_static/test_nonlinearity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/examples/_static/test_nonlinearity.png
--------------------------------------------------------------------------------
/docs/examples/_static/test_raman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WUST-FOG/gnlse-python/801e440490ca770a363596b50a5ef5cf12813901/docs/examples/_static/test_raman.png
--------------------------------------------------------------------------------
/docs/examples/example_dispersive_wave.rst:
--------------------------------------------------------------------------------
1 | Dispersive wave generation in anomalous dispersion regime
2 | =========================================================
3 |
4 | Example of dispersive wave generation in anomalus dispersion regime at
5 | a central wavelength of 835 nm in a 15 centimeter long photonic
6 | crystal fiber using three different models to model Raman response. ::
7 |
8 | import numpy as np
9 | import matplotlib.pyplot as plt
10 |
11 | import gnlse
12 |
13 | import os
14 |
15 | if __name__ == '__main__':
16 | setup = gnlse.GNLSESetup()
17 |
18 | # Numerical parameters
19 | setup.resolution = 2**14
20 | setup.time_window = 12.5 # ps
21 | setup.z_saves = 200
22 |
23 | # Physical parameters
24 | setup.wavelength = 835 # nm
25 | setup.fiber_length = 0.15 # m
26 | setup.nonlinearity = 0.0 # 1/W/m
27 | setup.raman_model = gnlse.raman_blowwood
28 | setup.self_steepening = True
29 |
30 | # The dispersion model is built from a Taylor expansion with coefficients
31 | # given below.
32 | loss = 0
33 | betas = np.array([-0.024948815481502, 8.875391917212998e-05,
34 | -9.247462376518329e-08, 1.508210856829677e-10])
35 |
36 | # Input pulse parameters
37 | power = 10000
38 | # pulse duration [ps]
39 | tfwhm = 0.05
40 | # hyperbolic secant
41 | setup.pulse_model = gnlse.SechEnvelope(power, tfwhm)
42 |
43 | # Type of dyspersion operator: build from interpolation of given neffs
44 | # read mat file for neffs
45 | mat_path = os.path.join(os.path.dirname(__file__), '..',
46 | 'data', 'neff_pcf.mat')
47 | mat = gnlse.read_mat(mat_path)
48 | # neffs
49 | neff = mat['neff'][:, 1]
50 | # wavelengths in nm
51 | lambdas = mat['neff'][:, 0] * 1e9
52 |
53 | # Visualization
54 | ###########################################################################
55 |
56 | # Set type of dispersion function
57 | simulation_type = {
58 | 'Results for Taylor expansion': gnlse.DispersionFiberFromTaylor(
59 | loss, betas),
60 | 'Results for interpolation': gnlse.DispersionFiberFromInterpolation(
61 | loss, neff, lambdas, setup.wavelength)
62 | }
63 |
64 | count = len(simulation_type)
65 | plt.figure(figsize=(15, 7), facecolor='w', edgecolor='k')
66 | for (i, (name, dispersion_model)) in enumerate(simulation_type.items()):
67 | setup.dispersion_model = dispersion_model
68 | solver = gnlse.GNLSE(setup)
69 | solution = solver.run()
70 |
71 | plt.subplot(2, count, i + 1)
72 | plt.title(name)
73 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[400, 1400])
74 |
75 | plt.subplot(2, count, i + 1 + count)
76 | gnlse.plot_delay_vs_distance(solution, time_range=[-.5, 5])
77 |
78 | plt.tight_layout()
79 | plt.show()
80 |
81 |
82 | Output:
83 |
84 | .. image:: _static/test_raman.png
85 | :alt: example_dispersive_wave
86 |
--------------------------------------------------------------------------------
/docs/examples/example_effective_mode_area.rst:
--------------------------------------------------------------------------------
1 | Consideration of mode profile dispersion
2 | ========================================
3 |
4 | Consideration of mode profile dispersion in GNLSE account
5 | based on algorithm described in [J07]_.
6 | Simulation conducted for a central wavelength of 835 nm in
7 | a 15 centimeter long photonic crystal fiber. ::
8 |
9 | import matplotlib.pyplot as plt
10 | import numpy as np
11 | import os
12 |
13 | import gnlse
14 |
15 | if __name__ == '__main__':
16 | setup = gnlse.GNLSESetup()
17 |
18 | # Numerical parameters
19 | setup.resolution = 2**14
20 | setup.time_window = 12.5 # ps
21 | setup.z_saves = 200
22 |
23 | # Physical parameters
24 | setup.wavelength = 835 # nm
25 | w0 = (2.0 * np.pi * gnlse.common.c) / setup.wavelength # 1/ps = THz
26 | setup.fiber_length = 0.15 # m
27 | setup.raman_model = gnlse.raman_blowwood
28 | setup.self_steepening = True
29 |
30 | # Input pulse parameters
31 | power = 1000
32 | # pulse duration [ps]
33 | tfwhm = 0.05
34 | # hyperbolic secant
35 | setup.pulse_model = gnlse.SechEnvelope(power, tfwhm)
36 |
37 | # The dispersion model is built from a Taylor expansion with coefficients
38 | # given below.
39 | loss = 0
40 | betas = np.array([-0.024948815481502, 8.875391917212998e-05,
41 | -9.247462376518329e-08, 1.508210856829677e-10])
42 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
43 | # parameters for calculating the nonlinearity
44 | n2 = 2.7e-20 # m^2/W
45 | Aeff0 = 1.78e-12 # 1/m^2
46 | gamma = n2 * w0 / gnlse.common.c / 1e-9 / Aeff0 # 1/W/m
47 |
48 | # read mat file for neffs to cover interpolation example
49 | mat_path = os.path.join(os.path.dirname(__file__), '..',
50 | 'data', 'neff_pcf.mat')
51 | mat = gnlse.read_mat(mat_path)
52 |
53 | # neffs
54 | neff = mat['neff'][:, 1]
55 | # wavelengths in nm
56 | lambdas = mat['neff'][:, 0] * 1e9
57 | # efective mode area in m^2
58 | Aeff = mat['neff'][:, 2] * 1e-12
59 |
60 | # This example extends the original code with additional simulations for
61 | nonlinearity_setups = [
62 | ["Scalar $\\gamma$",
63 | gnlse.DispersionFiberFromTaylor(loss, betas),
64 | gamma],
65 | ["Frequency dependent $\\gamma$",
66 | gnlse.DispersionFiberFromTaylor(loss, betas),
67 | gnlse.NonlinearityFromEffectiveArea(
68 | neff, Aeff, lambdas, setup.wavelength,
69 | n2=n2, neff_max=10)]
70 | ]
71 |
72 | count = len(nonlinearity_setups)
73 | plt.figure(figsize=(10, 8), facecolor='w', edgecolor='k')
74 | for i, model in enumerate(nonlinearity_setups):
75 | setup.dispersion = model[1]
76 | setup.nonlinearity = model[2]
77 | solver = gnlse.GNLSE(setup)
78 | solution = solver.run()
79 |
80 | plt.subplot(2, count, i + 1)
81 | plt.title(model[0])
82 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[700, 1000])
83 | plt.subplot(2, count, i + 1 + count)
84 | gnlse.plot_delay_vs_distance(solution, time_range=[-.5, .5])
85 |
86 | plt.tight_layout()
87 | plt.show()
88 |
89 |
90 | Output:
91 |
92 | .. image:: _static/test_nonlinearity.png
93 | :alt: example_effective_mode_area
94 |
--------------------------------------------------------------------------------
/docs/examples/example_soliton.rst:
--------------------------------------------------------------------------------
1 | Propagation of higher-order soliton
2 | ===================================
3 |
4 | Evolution of the spectral and temporal characteristics of the
5 | higher-order N = 3 soliton in three cases:
6 | - propagation without self steppening and Raman response;
7 | - soliton fission with self steppening, but no Raman response accounted;
8 | - soliton fission with self steppening, and Raman response accounted. ::
9 |
10 | import numpy as np
11 | import matplotlib.pyplot as plt
12 |
13 | import gnlse
14 |
15 | if __name__ == '__main__':
16 | setup = gnlse.gnlse.GNLSESetup()
17 |
18 | # Numerical parameters
19 | # number of grid time points
20 | setup.resolution = 2**13
21 | # time window [ps]
22 | setup.time_window = 12.5
23 | # number of distance points to save
24 | setup.z_saves = 200
25 | # relative tolerance for ode solver
26 | setup.rtol = 1e-6
27 | # absoulte tolerance for ode solver
28 | setup.atol = 1e-6
29 |
30 | # Physical parameters
31 | # Central wavelength [nm]
32 | setup.wavelength = 835
33 | # Nonlinear coefficient [1/W/m]
34 | setup.nonlinearity = 0.11
35 | # Dispersion: derivatives of propagation constant at central wavelength
36 | # n derivatives of betas are in [ps^n/m]
37 | betas = np.array([-11.830e-3])
38 | # Input pulse: pulse duration [ps]
39 | tFWHM = 0.050
40 | # for dispersive length calculation
41 | t0 = tFWHM / 2 / np.log(1 + np.sqrt(2))
42 |
43 | # 3rd order soliton conditions
44 | ###########################################################################
45 | # Dispersive length
46 | LD = t0 ** 2 / np.abs(betas[0])
47 | # Non-linear length for 3rd order soliton
48 | LNL = LD / (3 ** 2)
49 | # Input pulse: peak power [W]
50 | power = 1 / (LNL * setup.nonlinearity)
51 | # Length of soliton, in which it break dispersive characteristic
52 | Z0 = np.pi * LD / 2
53 | # Fiber length [m]
54 | setup.fiber_length = .5
55 | # Type of pulse: hyperbolic secant
56 | setup.pulse_model = gnlse.SechEnvelope(power, 0.050)
57 | # Loss coefficient [dB/m]
58 | loss = 0
59 | # Type of dyspersion operator: build from Taylor expansion
60 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
61 |
62 | # Set type of Ramman scattering function and selftepening
63 | simulation_type = {
64 | '3rd order soliton': (False, None),
65 | '3rd order soliton\nwith self-steepening': (True, None),
66 | 'Raman induced fission\nof 3rd order soliton': (True,
67 | gnlse.raman_blowwood)
68 | }
69 |
70 | count = len(simulation_type)
71 | plt.figure(figsize=(15, 7), facecolor='w', edgecolor='k')
72 | for (i, (name,
73 | (self_steepening,
74 | raman_model))) in enumerate(simulation_type.items()):
75 | setup.raman_model = raman_model
76 | setup.self_steepening = self_steepening
77 | solver = gnlse.GNLSE(setup)
78 | solution = solver.run()
79 |
80 | plt.subplot(2, count, i + 1)
81 | plt.title(name)
82 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[400, 1400])
83 |
84 | plt.subplot(2, count, i + 1 + count)
85 | gnlse.plot_delay_vs_distance(solution, time_range=[-.25, .25])
86 |
87 | plt.tight_layout()
88 | plt.show()
89 |
90 |
91 | Output:
92 |
93 | .. image:: _static/3rd_order_soliton.png
94 | :alt: example_soliton
95 |
--------------------------------------------------------------------------------
/docs/examples/example_supercontinuum.rst:
--------------------------------------------------------------------------------
1 | Supercontinuum generation in anomalous dispersion regime
2 | ========================================================
3 |
4 | Example of supercontinuum generation in anomalous dispersion regime at
5 | a central wavelength of 835 nm in a 15 centimeter long fiber using three
6 | different input shape of input pulse's envelopes. ::
7 |
8 | import numpy as np
9 | import matplotlib.pyplot as plt
10 |
11 | import gnlse
12 |
13 |
14 | if __name__ == '__main__':
15 | setup = gnlse.GNLSESetup()
16 |
17 | # Numerical parameters
18 | setup.resolution = 2**14
19 | setup.time_window = 12.5 # ps
20 | setup.z_saves = 200
21 |
22 | # Physical parameters
23 | setup.wavelength = 835 # nm
24 | setup.fiber_length = 0.15 # m
25 | setup.nonlinearity = 0.11 # 1/W/m
26 | setup.raman_model = gnlse.raman_blowwood
27 | setup.self_steepening = True
28 |
29 | # The dispersion model is built from a Taylor expansion with coefficients
30 | # given below.
31 | loss = 0
32 | betas = np.array([
33 | -11.830e-3, 8.1038e-5, -9.5205e-8, 2.0737e-10, -5.3943e-13, 1.3486e-15,
34 | -2.5495e-18, 3.0524e-21, -1.7140e-24
35 | ])
36 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
37 |
38 | # Input pulse parameters
39 | peak_power = 10000 # W
40 | duration = 0.050 # ps
41 |
42 | # This example extends the original code with additional simulations for
43 | pulse_models = [
44 | gnlse.SechEnvelope(peak_power, duration),
45 | gnlse.GaussianEnvelope(peak_power, duration),
46 | gnlse.LorentzianEnvelope(peak_power, duration)
47 | ]
48 |
49 | count = len(pulse_models)
50 | plt.figure(figsize=(14, 8), facecolor='w', edgecolor='k')
51 | for i, pulse_model in enumerate(pulse_models):
52 | print('%s...' % pulse_model.name)
53 |
54 | setup.pulse_model = pulse_model
55 | solver = gnlse.GNLSE(setup)
56 | solution = solver.run()
57 |
58 | plt.subplot(2, count, i + 1)
59 | plt.title(pulse_model.name)
60 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[400, 1400])
61 |
62 | plt.subplot(2, count, i + 1 + count)
63 | gnlse.plot_delay_vs_distance(solution, time_range=[-0.5, 5])
64 |
65 | plt.tight_layout()
66 | plt.show()
67 |
68 |
69 | Output:
70 |
71 | .. image:: _static/supercontinuum_3pulses.png
72 | :alt: example_supercontinuum
73 |
--------------------------------------------------------------------------------
/docs/examples/index.rst:
--------------------------------------------------------------------------------
1 | Examples
2 | ========
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | example_soliton
8 | example_supercontinuum
9 | example_dispersive_wave
10 | example_effective_mode_area
11 |
--------------------------------------------------------------------------------
/docs/gnlse.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Integration
4 | ===========
5 |
6 | This part of the module is its core, and it implements the split-step Fourier
7 | method to solve the Generalized Nonlinear Schrodiner Equation (GNLSE),
8 | which in time domain can be written as
9 |
10 | .. math::
11 |
12 | \frac{\partial A(z,T)}{\partial z} = & -\frac{\alpha}{2}A(z,T) -
13 | \sum_{k\geq 2} \left(\frac{i^{k-1}}{k!}\beta_k
14 | \frac{\partial^k A(z,T)}{\partial T^k} \right) + \\
15 | & + i\gamma\left(1 + \frac{i}{\omega_c} \frac{\partial}{\partial T} \right)
16 | \left( A(z,T) \int_{-\infty}^{+\infty} R(T') |A(z,T-T')|^2 dT' \right),
17 |
18 | where :math:`\alpha` is the attenuation constant, and :math:`\beta_k` are the
19 | higher order dispersion coefficients obtained by a Taylor series expansion of
20 | the propagation constant :math:`\beta(\omega)` around the center frequency
21 | :math:`\omega_c`. The term in second line describes the nonlinear effects -
22 | temporal derivative in this term is responsible for self-steepening
23 | and optical shock formation, whereas the convolution integral describes
24 | the delayed Raman response :math:`R(T')` [H07]_. This form of the GNLSE is
25 | commonly employed for numerical simulations of propagation of pulses in
26 | a nonlinear medium such as optical fiber.
27 |
28 | This solver is efficient, thanks to an adaptive-step-size implementation of
29 | the fourth-order Runge-Kutta in the Interaction Picture method (RK4IP),
30 | adapted from [H07]_. Our Python code is partially based on MATLAB code,
31 | published in [DT10]_, available at http://scgbook.info/. The toolbox prepares
32 | integration using SCIPYs ode solver, while the transitions between time and
33 | frequency domains are accomplished using the FFT and iFFT from pyfftw library.
34 |
35 | The solver is divided into three parts: specific model setup
36 | (``gnlse.GNLSESetup``), the framework for preparing split-step Fourier
37 | alghoritm (``gnlse.GNLSE``), and class for managing the solution
38 | (``gnlse.Solution``).
39 |
40 | .. autoclass:: gnlse.GNLSESetup
41 | .. autoclass:: gnlse.GNLSE
42 | .. autoclass:: gnlse.Solution
43 |
--------------------------------------------------------------------------------
/docs/gnlse_intro.rst:
--------------------------------------------------------------------------------
1 | GNLSE: Nonlinear optics modeling tool for optical fibers
2 | ========================================================
3 |
4 | gnlse-python is a Python set of scripts for solving Generalized Nonlinear
5 | Schrodinger Equation. It is one of the WUST-FOG students projects developed by
6 | `Fiber Optics Group, WUST `_.
7 |
8 | Complete documentation is available at `https://gnlse.readthedocs.io `_.
9 |
10 | Installation
11 | ------------
12 |
13 | Using pip
14 | *********
15 |
16 | Instal the latest version
17 |
18 | ``pip install gnlse``
19 |
20 | or pick appropriate version as v2.0.0
21 |
22 | ``pip install gnlse==2.0.0``
23 |
24 | From scratch
25 | ************
26 |
27 | 1. Create a virtual environment using ``python -m venv gnlse`` or ``conda``.
28 | 2. Activate it:
29 |
30 | ``. gnlse/bin/activate``
31 |
32 | 3. Clone the GitHub repository:
33 |
34 | ``git clone https://github.com/WUST-FOG/gnlse-python.git``
35 |
36 | 4. Install the package with all requirements:
37 |
38 | ``pip install .``
39 |
40 | or add the relevant path to your ``PYTHONPATH`` enviroment variable.
41 |
42 | Dependencies
43 | ************
44 |
45 | The following Python packages are required to install gnlse module. During
46 | instalation of package the latest version of each of listed below package will
47 | automatically be installed if missing:
48 |
49 | ::
50 |
51 | matplotlib>=2.2.2
52 | numpy>=1.14.3
53 | scipy>=1.1.0
54 | pyfftw>=0.10.0
55 | hdf5storage>=0.1.15
56 | tqdm>=4.11.2
57 |
58 | Usage
59 | -----
60 |
61 | We provide some example Python scripts in the ``examples`` subdirectory. For
62 | instance, running ``test_Dudley.py`` demonstrates supercontinuum generation in
63 | an optical fiber using three different input pulse envelopes.
64 |
65 | ::
66 |
67 | cd gnlse-python/examples
68 | python test_Dudley.py
69 |
70 | A visualisation, pictured in the screenshot below, is then displayed.
71 |
72 | .. image:: _static/supercontinuum_3pulses.png
73 |
74 | .. toctree::
75 | :maxdepth: 2
76 | :caption: Examples:
77 |
78 | examples/index
79 |
80 | More examples can be found in the `examples subdirectory
81 | `_.
82 |
83 | Major features
84 | --------------
85 |
86 | * **A modular design**: the solver framework was decomposed into different
87 | components and one can easily construct a customized simulations by
88 | accounting different physical phenomena, ie. self stepening,
89 | Raman response.
90 |
91 | The main core of the module is derived from the RK4IP MATLAB script
92 | written by J. C. Travers, H. Frosz and J. M. Dudley, published [DT10]_.
93 |
94 | * Support for three Raman response functions: ``blowwood`` [BW89]_,
95 | ``linagrawal`` [LA06]_ and ``hollenbeck`` [HC02]_.
96 | * Support for two dispersion operators: calculated from a Taylor expansion
97 | and calculated from effective refractive indices.
98 | * A number of example scripts in the ``examples`` subdirectory:
99 |
100 | * ``plot_input_pulse.py``, plotting various input pulse envelopes,
101 | * ``plot_Raman_response.py``, plotting supported Raman response functions
102 | in the time domain,
103 | * ``test_3rd_order_soliton.py``, demonstrating the evolution of spectral
104 | and temporal characteristics of a third-order soliton,
105 | * ``test_dispersion.py``, an example of supercontinuum generation using
106 | different dispersion operators,
107 | * ``test_nonlinearity.py``, an example of soliton fission using
108 | different GNLSE and Modified GNLSE accounting mode profile dispersion,
109 | (take into account mode profile dispersion),
110 | * ``test_Dudley.py``, an example of supercontinuum generation using
111 | different input pulse envelopes,
112 | * ``test_gvd.py``, showing pulse broadening due to group velocity
113 | dispersion,
114 | * ``test_import_export.py``, an example of saving and loading simulation
115 | results to and from a \*.mat file,
116 | * ``test_raman.py``, showing solition fission in case for different Raman
117 | responses,
118 | * ``test_spm.py``, an example of self-phase modulation,
119 | * ``test_spm+gvd.py``, demonstrating generation of a first-order soliton.
120 |
121 |
122 | Release information
123 | -------------------
124 |
125 | v2.0.0 was released on April 26, 2022. The main branch works with
126 | **Python 3.7.**
127 |
128 | ======= ================= ====================================================
129 | Version Date Notes
130 | ======= ================= ====================================================
131 | 2.0.0 April 26, 2022 * CHANGE: Code refactor - rename modules
132 | * FIX: Fixed extrapolation for nonlinear coefficient
133 | 1.1.3 February 13, 2022 * FIX: Fix scaling for interpolated dispersion
134 | 1.1.2 August 30, 2021 * ADD: Continious wave envelope
135 | * FIX: Shift scalling data for nonlinear coefficient
136 | 1.1.1 August 28, 2021 * CHANGE: Minor bug fix with scaling
137 | * CHANGE: Few minor changes in the documentation
138 | 1.1.0 August 21, 2021 * Modified-GNLSE extension
139 | * CHANGE: Code refactor - relocate attribiutes
140 | 1.0.0 August 13, 2020 * The first proper release
141 | * CHANGE: Complete documentation and code.
142 | ======= ================= ====================================================
143 |
144 | Authors
145 | *******
146 |
147 | * `Adam Pawłowski `_
148 | * `Paweł Redman `_
149 | * `Daniel Szulc `_
150 | * `Magda Zatorska `_
151 | * `Sylwia Majchrowska `_
152 | * `Karol Tarnowski `_
153 |
154 | Citation
155 | ********
156 |
157 | If you use a code please `cite `_ us:
158 |
159 | Paragraph ... ::
160 |
161 | @misc{redman2021gnlsepython,
162 | title={gnlse-python: Open Source Software to Simulate Nonlinear Light Propagation In Optical Fibers},
163 | author={Paweł Redman and Magdalena Zatorska and Adam Pawłowski and Daniel Szulc and Sylwia Majchrowska and Karol Tarnowski},
164 | year={2021},
165 | eprint={2110.00298},
166 | archivePrefix={arXiv},
167 | primaryClass={physics.optics}
168 | }
169 |
170 | Contributing
171 | ************
172 |
173 | Pull requests are welcome. For major changes, please open an issue first to
174 | discuss what you would like to change.
175 |
176 | Please make sure to update examples and tests as appropriate.
177 |
178 | Acknowledgements
179 | ****************
180 |
181 | **gnlse-python** is an open-source project, contributed to by researchers,
182 | engineers and students of the Wrocław University of Science and Technology, as
183 | part of Fiber Optic Group's nonlinear simulation projects. The Python code was
184 | partially based on MATLAB code, published in [DT10]_, available at
185 | http://scgbook.info/.
186 |
187 | License
188 | *******
189 |
190 | This project is licensed under the terms of the `MIT License
191 | `_.
192 |
--------------------------------------------------------------------------------
/docs/import_export.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Importing and exporting
4 | =======================
5 |
6 | The following functions allow one to read and write data as `.mat` files.
7 |
8 | .. autofunction:: gnlse.read_mat
9 | .. autofunction:: gnlse.write_mat
10 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | Welcome to gnlse-python's documentation!
2 | ========================================
3 |
4 | Contents:
5 |
6 | .. toctree::
7 | :maxdepth: 2
8 |
9 | gnlse_intro
10 | code_documentation
11 | examples/index
12 | references
13 |
14 |
15 | Indices and tables
16 | ==================
17 |
18 | * :ref:`genindex`
19 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/nonlinearity.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Nonlinear coefficient
4 | =====================
5 |
6 | The time derivative term inside GNLSE models the dispersion of
7 |
8 | the nonlinearity. This is usually associated with effects such
9 | as self-steepening and optical shock formation, characterized by
10 | a timescale :math:`\tau_0 = 1/\omega_0`. In the context of fibre
11 | propagation, an additional dispersion of the nonlinearity arises
12 | due to the frequency dependence of the effective mode area.
13 | The last effect can be accounted in :math:`\tau_0`
14 | coefficient in an approximate manner.
15 |
16 | A better - still approximate - approach to include the dispersion
17 | of the effective mode area is to
18 | describe it directly in the frequency domain [J07]_.
19 | In this case, we can derive a GNLSE for the pulse evolution using
20 | :math:`\gamma(\omega)` defined as
21 |
22 | .. math::
23 |
24 | \overline{\gamma}(\omega) =
25 | \frac{n_2n_{\mathrm{eff}}(\omega_0)\omega_0}
26 | {\mathrm{c}n_\mathrm{eff}(\omega)\sqrt{A_{\mathrm{eff}}(\omega)A_{\mathrm{eff}}(\omega_0)}}.
27 |
28 |
29 | This approach is more rigorous than the approximation
30 | of (:math:`\gamma = \gamma(\omega_0)`)
31 | and requires the definition of a pseudo-envelope :math:`C(z, \omega)` as
32 |
33 |
34 | .. math::
35 |
36 | C(z, \omega) = \frac{A_{eff}^{1/4}(\omega_0 )}{A_{eff}^{1/4}(\omega )} A(z, \omega).
37 |
38 | .. autoclass:: gnlse.NonlinearityFromEffectiveArea
39 |
--------------------------------------------------------------------------------
/docs/raman_response.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Raman responses
4 | ===============
5 |
6 | Calculates different Raman responses :math:`R(T)`, based on the chosen Raman
7 | model, the response is calculated. There are three available Raman reponse
8 | models for silica optical fibers:
9 | based on K. J. Blow and D. Wood model [BW89]_,
10 | based on Dawn Hollenbeck and Cyrus D. Cantrell model [HC02]_,
11 | and based on Q. Lin and Govind P. Agrawal model [LA06]_.
12 |
13 | The below figure illustrates a various Raman response functions in time
14 | domain.
15 |
16 | .. image:: _static/plot_raman.png
17 | :alt: example_input_raman
18 |
19 | .. autofunction:: gnlse.raman_blowwood
20 | .. autofunction:: gnlse.raman_holltrell
21 | .. autofunction:: gnlse.raman_linagrawal
22 |
--------------------------------------------------------------------------------
/docs/references.rst:
--------------------------------------------------------------------------------
1 | Bibliography
2 | ============
3 |
4 | .. [BW89] Blow, K. J., & Wood, D. (1989). Theoretical description of transient
5 | stimulated Raman scattering in optical fibers. IEEE Journal of Quantum
6 | Electronics, 25(12), 2665–2673. https://doi.org/10.1109/3.40655
7 | .. [DT10] Dudley, J., & Taylor, J. (Eds.). (2010). Supercontinuum Generation
8 | in Optical Fibers. Cambridge: Cambridge University Press.
9 | doi:10.1017/CBO9780511750465
10 | .. [HC02] Hollenbeck, D., & Cantrell, C. D. (2002). Multiple-vibrational-mode
11 | model for fiber-optic Raman gain spectrum and response function. Journal of
12 | the Optical Society of America B, 19(12), 2886.
13 | https://doi.org/10.1364/josab.19.002886
14 | .. [H07] Hult, J. (2010). A Fourth-Order Runge–Kutta
15 | in the Interaction Picture Method for Simulating Supercontinuum Generation
16 | in Optical Fibers. Journal of Lightwave Technology, 25(12), 3770-3775.
17 | https://doi.org/10.1109/JLT.2007.909373
18 | .. [LA06] Lin, Q., & Agrawal, G. P. (2006). Raman response function for silica
19 | fibers. Optics Letters, 31(21), 3086. https://doi.org/10.1364/ol.31.003086
20 | .. [J07] J. Laegsgaard, (2007). Mode profile dispersion in the generalized
21 | nonlinear Schrödinger equation. Optics Express 15(24), 16110-16123.
22 | https://doi.org/10.1364/OE.15.016110
23 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | numpydoc
2 | sphinx_rtd_theme
3 | rinohtype
4 | pygments>=2.5.1
5 |
--------------------------------------------------------------------------------
/docs/visualisation.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Visualisation
4 | =============
5 |
6 | Various plotting functions for visualizing GNLSE simulations using Matplotlib
7 | library are prepared.
8 |
9 | .. autofunction:: gnlse.plot_wavelength_vs_distance
10 | .. autofunction:: gnlse.plot_delay_vs_distance
11 | .. autofunction:: gnlse.quick_plot
12 |
--------------------------------------------------------------------------------
/examples/plot_Raman_response.py:
--------------------------------------------------------------------------------
1 | """Calculates different Raman responses and plots them.
2 | Based on the chosen Raman model, the response is
3 | calculated and shown on the graph. There are three
4 | available Raman reponse models.
5 | """
6 |
7 | import numpy as np
8 | import matplotlib.pyplot as plt
9 | import gnlse
10 |
11 |
12 | if __name__ == '__main__':
13 | # Initial paremeters
14 | ##########################################################################
15 | # Number of grid points
16 | n = 2 ** 13
17 | # Time window width [ps]
18 | time_window = 12.5
19 | # The speed of light [nm/ps]
20 | c = 299792458 * 1e-3
21 | # Central wavelength [nm]
22 | wavelength = 835
23 | # Central frequency [THz]
24 | w0 = (2 * np.pi * c) / wavelength
25 | # Time grid [ps]
26 | T = np.linspace(-time_window / 2, time_window / 2, n)
27 |
28 | # K. J. Blow and D. Wood Raman response
29 | fr, RT1 = gnlse.raman_blowwood(T)
30 | RT1 = RT1 / np.max(RT1)
31 | # Q. Lin and Govind P. Agrawal Raman response
32 | fr2, RT2 = gnlse.raman_linagrawal(T)
33 | RT2 = RT2 / np.max(RT2)
34 | # D. Hollenbeck and C. D. Cantrell Raman response
35 | fr3, RT3 = gnlse.raman_holltrell(T)
36 | RT3 = RT3 / np.max(RT3)
37 |
38 | plt.plot(T, RT1, label="Blow-Wood")
39 | plt.plot(T, RT2, label="Lin-Agrawal")
40 | plt.plot(T, RT3, label="Hollenbeck-Cantrell")
41 |
42 | plt.xlim(-0.025, 1)
43 | plt.ylabel("Raman response [a.u.]")
44 | plt.xlabel("Time [ps]")
45 |
46 | plt.legend()
47 |
48 | plt.show()
49 |
--------------------------------------------------------------------------------
/examples/plot_input_pulse.py:
--------------------------------------------------------------------------------
1 | """Calculates envelopes of various pulses and plots them.
2 | Based on the chosen envelopes pulse, the aplitude envelope is
3 | calculated and shown on the graph. There are three
4 | available envelopes pulses models:
5 | hyperbolic secant, gaussian and lorentzian.
6 | """
7 |
8 | import numpy as np
9 | import matplotlib.pyplot as plt
10 |
11 | import gnlse
12 |
13 | if __name__ == '__main__':
14 | # time full with half maximum of pulse
15 | FWHM = 2
16 | # Time grid [ps]
17 | T = np.linspace(-2 * FWHM, 2 * FWHM, 1000 * FWHM)
18 | # peak power [W]
19 | Pmax = 100
20 |
21 | # Amplitude envelope of gaussina pulse
22 | A1 = gnlse.GaussianEnvelope(Pmax, FWHM).A(T)
23 | # Amplitude envelope of hiperbolic secans pulse
24 | A2 = gnlse.SechEnvelope(Pmax, FWHM).A(T)
25 | # Amplitude envelope of lorentzian pulse
26 | A3 = gnlse.LorentzianEnvelope(Pmax, FWHM).A(T)
27 | # Amplitude envelope of continious wave
28 | A4 = gnlse.CWEnvelope(Pmax).A(T)
29 |
30 | plt.figure(figsize=(12, 8))
31 | plt.subplot(1, 2, 1)
32 | plt.plot(T, A1, label='gauss')
33 | plt.plot(T, A2, label='sech')
34 | plt.plot(T, A3, label='lorentz')
35 | plt.plot(T, A4, label='cw')
36 | plt.xlabel("Time [ps]")
37 | plt.ylabel("Amplitude [sqrt(W)]")
38 | plt.legend()
39 |
40 | plt.subplot(1, 2, 2)
41 | plt.plot(T, A1**2, label='gauss')
42 | plt.plot(T, A2**2, label='sech')
43 | plt.plot(T, A3**2, label='lorentz')
44 | plt.plot(T, A4**2, label='cw')
45 | plt.xlabel("Time [ps]")
46 | plt.ylabel("Power [W]")
47 | plt.legend()
48 |
49 | plt.show()
50 |
--------------------------------------------------------------------------------
/examples/test_3rd_order_soliton.py:
--------------------------------------------------------------------------------
1 | """
2 | Example: Evolution of the spectral and temporal characteristics of the
3 | higher-order N = 3 soliton in three cases:
4 | - propagation without self steppening and Raman response;
5 | - soliton fission with self steppening, but no Raman response accounted;
6 | - soliton fission with self steppening, and Raman response accounted.
7 | """
8 |
9 | import numpy as np
10 | import matplotlib.pyplot as plt
11 |
12 | import gnlse
13 |
14 | if __name__ == '__main__':
15 | setup = gnlse.gnlse.GNLSESetup()
16 |
17 | # Numerical parameters
18 | # number of grid time points
19 | setup.resolution = 2**13
20 | # time window [ps]
21 | setup.time_window = 12.5
22 | # number of distance points to save
23 | setup.z_saves = 200
24 | # relative tolerance for ode solver
25 | setup.rtol = 1e-6
26 | # absoulte tolerance for ode solver
27 | setup.atol = 1e-6
28 |
29 | # Physical parameters
30 | # Central wavelength [nm]
31 | setup.wavelength = 835
32 | # Nonlinear coefficient [1/W/m]
33 | setup.nonlinearity = 0.11
34 | # Dispersion: derivatives of propagation constant at central wavelength
35 | # n derivatives of betas are in [ps^n/m]
36 | betas = np.array([-11.830e-3])
37 | # Input pulse: pulse duration [ps]
38 | tFWHM = 0.050
39 | # for dispersive length calculation
40 | t0 = tFWHM / 2 / np.log(1 + np.sqrt(2))
41 |
42 | # 3rd order soliton conditions
43 | ###########################################################################
44 | # Dispersive length
45 | LD = t0 ** 2 / np.abs(betas[0])
46 | # Non-linear length for 3rd order soliton
47 | LNL = LD / (3 ** 2)
48 | # Input pulse: peak power [W]
49 | power = 1 / (LNL * setup.nonlinearity)
50 | # Length of soliton, in which it break dispersive characteristic
51 | Z0 = np.pi * LD / 2
52 | # Fiber length [m]
53 | setup.fiber_length = .5
54 | # Type of pulse: hyperbolic secant
55 | setup.pulse_model = gnlse.SechEnvelope(power, 0.050)
56 | # Loss coefficient [dB/m]
57 | loss = 0
58 | # Type of dyspersion operator: build from Taylor expansion
59 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
60 |
61 | # Set type of Ramman scattering function and selftepening
62 | simulation_type = {
63 | '3rd order soliton': (False, None),
64 | '3rd order soliton\nwith self-steepening': (True, None),
65 | 'Raman induced fission\nof 3rd order soliton': (True,
66 | gnlse.raman_blowwood)
67 | }
68 |
69 | count = len(simulation_type)
70 | plt.figure(figsize=(15, 7), facecolor='w', edgecolor='k')
71 | for (i, (name,
72 | (self_steepening,
73 | raman_model))) in enumerate(simulation_type.items()):
74 | setup.raman_model = raman_model
75 | setup.self_steepening = self_steepening
76 | solver = gnlse.GNLSE(setup)
77 | solution = solver.run()
78 |
79 | plt.subplot(2, count, i + 1)
80 | plt.title(name)
81 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[400, 1400])
82 |
83 | plt.subplot(2, count, i + 1 + count)
84 | gnlse.plot_delay_vs_distance(solution, time_range=[-.25, .25])
85 |
86 | plt.tight_layout()
87 | plt.show()
88 |
--------------------------------------------------------------------------------
/examples/test_Dudley.py:
--------------------------------------------------------------------------------
1 | """
2 | Example of supercontinuum generation in anomalous dispersion regime at
3 | a central wavelength of 835 nm in a 15 centimeter long fiber.
4 | Data from J. M. Dudley, G. Genty, and S. Coen, Rev. Mod. Phys., vol. 78, no. 4,
5 | pp. 1135–1184, 2006.
6 |
7 | The python code based on MATLAB code published in
8 | 'Supercontinuum Generation in Optical Fibers'
9 | by J. M. Dudley and J. R. Taylor, available at http://scgbook.info/.
10 | """
11 |
12 | import numpy as np
13 | import matplotlib.pyplot as plt
14 |
15 | import gnlse
16 |
17 |
18 | if __name__ == '__main__':
19 | setup = gnlse.GNLSESetup()
20 |
21 | # Numerical parameters
22 | setup.resolution = 2**14
23 | setup.time_window = 12.5 # ps
24 | setup.z_saves = 200
25 |
26 | # Physical parameters
27 | setup.wavelength = 835 # nm
28 | setup.fiber_length = 0.15 # m
29 | setup.nonlinearity = 0.11 # 1/W/m
30 | setup.raman_model = gnlse.raman_blowwood
31 | setup.self_steepening = True
32 |
33 | # The dispersion model is built from a Taylor expansion with coefficients
34 | # given below.
35 | loss = 0
36 | betas = np.array([
37 | -11.830e-3, 8.1038e-5, -9.5205e-8, 2.0737e-10, -5.3943e-13, 1.3486e-15,
38 | -2.5495e-18, 3.0524e-21, -1.7140e-24
39 | ])
40 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
41 |
42 | # Input pulse parameters
43 | peak_power = 10000 # W
44 | duration = 0.050 # ps
45 |
46 | # This example extends the original code with additional simulations for
47 | pulse_models = [
48 | gnlse.SechEnvelope(peak_power, duration),
49 | gnlse.GaussianEnvelope(peak_power, duration),
50 | gnlse.LorentzianEnvelope(peak_power, duration)
51 | ]
52 |
53 | count = len(pulse_models)
54 | plt.figure(figsize=(14, 8), facecolor='w', edgecolor='k')
55 | for i, pulse_model in enumerate(pulse_models):
56 | print('%s...' % pulse_model.name)
57 |
58 | setup.pulse_model = pulse_model
59 | solver = gnlse.GNLSE(setup)
60 | solution = solver.run()
61 |
62 | plt.subplot(2, count, i + 1)
63 | plt.title(pulse_model.name)
64 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[400, 1400])
65 |
66 | plt.subplot(2, count, i + 1 + count)
67 | gnlse.plot_delay_vs_distance(solution, time_range=[-0.5, 5])
68 |
69 | plt.tight_layout()
70 | plt.show()
71 |
--------------------------------------------------------------------------------
/examples/test_dispersion.py:
--------------------------------------------------------------------------------
1 | """
2 | Example: Example of supercontinuum generation in anomalous dispersion regime
3 | at a central wavelength of 835 nm in a 15 centimeter long fiber.
4 | Comparision of results obtained with two dispersion input:
5 | 1. dispersion calculated from Taylor expansion
6 | 2. dispersion calculated from effective refractive indicies
7 |
8 | The python code based on MATLAB code published in
9 | 'Supercontinuum Generation in Optical Fibers'
10 | by J. M. Dudley and J. R. Taylor, available at http://scgbook.info/.
11 | """
12 |
13 | import numpy as np
14 | import matplotlib.pyplot as plt
15 |
16 | import gnlse
17 |
18 | import os
19 |
20 | if __name__ == '__main__':
21 | setup = gnlse.GNLSESetup()
22 |
23 | # Numerical parameters
24 | setup.resolution = 2**14
25 | setup.time_window = 12.5 # ps
26 | setup.z_saves = 200
27 |
28 | # Physical parameters
29 | setup.wavelength = 835 # nm
30 | setup.fiber_length = 0.15 # m
31 | setup.nonlinearity = 0.0 # 1/W/m
32 | setup.raman_model = gnlse.raman_blowwood
33 | setup.self_steepening = True
34 |
35 | # The dispersion model is built from a Taylor expansion with coefficients
36 | # given below.
37 | loss = 0
38 | betas = np.array([-0.024948815481502, 8.875391917212998e-05,
39 | -9.247462376518329e-08, 1.508210856829677e-10])
40 |
41 | # Input pulse parameters
42 | power = 10000
43 | # pulse duration [ps]
44 | tfwhm = 0.05
45 | # hyperbolic secant
46 | setup.pulse_model = gnlse.SechEnvelope(power, tfwhm)
47 |
48 | # Type of dyspersion operator: build from interpolation of given neffs
49 | # read mat file for neffs
50 | mat_path = os.path.join(os.path.dirname(__file__), '..',
51 | 'data', 'neff_pcf.mat')
52 | mat = gnlse.read_mat(mat_path)
53 | # neffs
54 | neff = mat['neff'][:, 1]
55 | # wavelengths in nm
56 | lambdas = mat['neff'][:, 0] * 1e9
57 |
58 | # Visualization
59 | ###########################################################################
60 |
61 | # Set type of dispersion function
62 | simulation_type = {
63 | 'Results for Taylor expansion': gnlse.DispersionFiberFromTaylor(
64 | loss, betas),
65 | 'Results for interpolation': gnlse.DispersionFiberFromInterpolation(
66 | loss, neff, lambdas, setup.wavelength)
67 | }
68 |
69 | count = len(simulation_type)
70 | plt.figure(figsize=(15, 7), facecolor='w', edgecolor='k')
71 | for (i, (name, dispersion_model)) in enumerate(simulation_type.items()):
72 | setup.dispersion_model = dispersion_model
73 | solver = gnlse.GNLSE(setup)
74 | solution = solver.run()
75 |
76 | plt.subplot(2, count, i + 1)
77 | plt.title(name)
78 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[400, 1400])
79 |
80 | plt.subplot(2, count, i + 1 + count)
81 | gnlse.plot_delay_vs_distance(solution, time_range=[-.5, 5])
82 |
83 | plt.tight_layout()
84 | plt.show()
85 |
--------------------------------------------------------------------------------
/examples/test_gvd.py:
--------------------------------------------------------------------------------
1 | """
2 | Example: group velocity dispersion on distance of 4 dispersion length
3 | for gaussian pulse as in Chapter 3 of Nonlinear Fiber Optics.
4 |
5 | Interface based on MATLAB code published in
6 | 'Supercontinuum Generation in Optical Fibers'
7 | by J. M. Dudley and J. R. Taylor, available at http://scgbook.info/.
8 | """
9 |
10 | import numpy as np
11 | import gnlse
12 | import matplotlib.pyplot as plt
13 |
14 |
15 | if __name__ == '__main__':
16 | setup = gnlse.gnlse.GNLSESetup()
17 |
18 | # Numerical parameters
19 | ###########################################################################
20 | # number of grid time points
21 | setup.resolution = 2**13
22 | # time window [ps]
23 | setup.time_window = 12.5
24 | # number of distance points to save
25 | setup.z_saves = 200
26 | # relative tolerance for ode solver
27 | setup.rtol = 1e-6
28 | # absoulte tolerance for ode solver
29 | setup.atol = 1e-6
30 |
31 | # Physical parameters
32 | ###########################################################################
33 | # Central wavelength [nm]
34 | setup.wavelength = 835
35 | # Nonlinear coefficient [1/W/m]
36 | setup.nonlinearity = 0.
37 | # Dispersion: derivatives of propagation constant at central wavelength
38 | # n derivatives of betas are in [ps^n/m]
39 | betas = np.array([-11.830e-3])
40 | # Input pulse: pulse duration [ps]
41 | tFWHM = 0.050
42 | t0 = tFWHM / 2 / np.sqrt(np.log(2)) # for dispersive length calculations
43 |
44 | ###########################################################################
45 | # Dispersive length
46 | LD = t0 ** 2 / np.abs(betas[0])
47 | # Input pulse: peak power [W]
48 | power = 1 # value can be choosen arbitrarily
49 | # Fiber length [m]
50 | setup.fiber_length = 4 * LD
51 | # Type of pulse: gaussian
52 | setup.pulse_model = gnlse.GaussianEnvelope(power, tFWHM)
53 | # Loss coefficient [dB/m]
54 | loss = 0
55 | # Type of dyspersion operator: build from Taylor expansion
56 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
57 |
58 | # Type of Ramman scattering function: None (default)
59 | # Selftepening: not accounted
60 | setup.self_steepening = False
61 |
62 | # Simulation
63 | ###########################################################################
64 | solver = gnlse.gnlse.GNLSE(setup)
65 | solution = solver.run()
66 |
67 | # Visualization
68 | ###########################################################################
69 |
70 | plt.subplot(1, 2, 1)
71 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[780, 900])
72 | plt.subplot(1, 2, 2)
73 | gnlse.plot_delay_vs_distance(solution, time_range=[-.5, .5])
74 |
75 | plt.show()
76 |
--------------------------------------------------------------------------------
/examples/test_import_export.py:
--------------------------------------------------------------------------------
1 | """
2 | Runs a simple simulation, saves it to disk and loads it back for plotting.
3 | """
4 |
5 | import os
6 | import gnlse
7 |
8 | if __name__ == '__main__':
9 | setup = gnlse.GNLSESetup()
10 | setup.resolution = 2**13
11 | setup.time_window = 12.5 # ps
12 | setup.z_saves = 200
13 | setup.fiber_length = 0.15 # m
14 | setup.wavelength = 835 # nm
15 | setup.pulse_model = gnlse.GaussianEnvelope(1, 0.1)
16 |
17 | solver = gnlse.GNLSE(setup)
18 | solution = solver.run()
19 |
20 | path = 'test.mat'
21 |
22 | solution.to_file(path)
23 | solution = gnlse.Solution()
24 | solution.from_file(path)
25 |
26 | gnlse.quick_plot(solution)
27 |
28 | os.remove(path)
29 |
--------------------------------------------------------------------------------
/examples/test_nonlinearity.py:
--------------------------------------------------------------------------------
1 | """
2 | Example: Example of soliton fission for a
3 | central wavelength of 835 nm in a 15 centimeter long fiber.
4 | Comparision of results obtained with two simulation input:
5 | 1. dispersion calculated from Taylor expansion,
6 | and gamma value procided only for pump wavelength
7 | 2. dispersion calculated from Taylor expansion,
8 | and gamma calculated from effective mode areas
9 | with modification proposed by J. Lægsgaard [2].
10 |
11 |
12 | [1] "Supercontinuum Generation in Optical Fibers,"
13 | J. M. Dudley and J. R. Taylor, 2010.
14 | [2] "Mode profile dispersion in the generalized
15 | nonlinear Schrödinger equation," J. Lægsgaard,
16 | Opt. Express 15, 16110-16123, 2007.
17 | """
18 |
19 | import matplotlib.pyplot as plt
20 | import numpy as np
21 | import os
22 |
23 | import gnlse
24 |
25 | if __name__ == '__main__':
26 | setup = gnlse.GNLSESetup()
27 |
28 | # Numerical parameters
29 | setup.resolution = 2**14
30 | setup.time_window = 12.5 # ps
31 | setup.z_saves = 200
32 |
33 | # Physical parameters
34 | setup.wavelength = 835 # nm
35 | w0 = (2.0 * np.pi * gnlse.common.c) / setup.wavelength # 1/ps = THz
36 | setup.fiber_length = 0.15 # m
37 | setup.raman_model = gnlse.raman_blowwood
38 | setup.self_steepening = True
39 |
40 | # Input pulse parameters
41 | power = 1000
42 | # pulse duration [ps]
43 | tfwhm = 0.05
44 | # hyperbolic secant
45 | setup.pulse_model = gnlse.SechEnvelope(power, tfwhm)
46 |
47 | # The dispersion model is built from a Taylor expansion with coefficients
48 | # given below.
49 | loss = 0
50 | betas = np.array([-0.024948815481502, 8.875391917212998e-05,
51 | -9.247462376518329e-08, 1.508210856829677e-10])
52 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
53 | # parameters for calculating the nonlinearity
54 | n2 = 2.7e-20 # m^2/W
55 | Aeff0 = 1.78e-12 # 1/m^2
56 | gamma = n2 * w0 / gnlse.common.c / 1e-9 / Aeff0 # 1/W/m
57 |
58 | # read mat file for neffs to cover interpolation example
59 | mat_path = os.path.join(os.path.dirname(__file__), '..',
60 | 'data', 'neff_pcf.mat')
61 | mat = gnlse.read_mat(mat_path)
62 |
63 | # neffs
64 | neff = mat['neff'][:, 1]
65 | # wavelengths in nm
66 | lambdas = mat['neff'][:, 0] * 1e9
67 | # efective mode area in m^2
68 | Aeff = mat['neff'][:, 2] * 1e-12
69 |
70 | # This example extends the original code with additional simulations for
71 | nonlinearity_setups = [
72 | ["Scalar $\\gamma$",
73 | gnlse.DispersionFiberFromTaylor(loss, betas),
74 | gamma],
75 | ["Frequency dependent $\\gamma$",
76 | gnlse.DispersionFiberFromTaylor(loss, betas),
77 | gnlse.NonlinearityFromEffectiveArea(
78 | neff, Aeff, lambdas, setup.wavelength,
79 | n2=n2, neff_max=10)]
80 | ]
81 |
82 | count = len(nonlinearity_setups)
83 | plt.figure(figsize=(10, 8), facecolor='w', edgecolor='k')
84 | for i, model in enumerate(nonlinearity_setups):
85 | setup.dispersion = model[1]
86 | setup.nonlinearity = model[2]
87 | solver = gnlse.GNLSE(setup)
88 | solution = solver.run()
89 |
90 | plt.subplot(2, count, i + 1)
91 | plt.title(model[0])
92 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[700, 1000])
93 | plt.subplot(2, count, i + 1 + count)
94 | gnlse.plot_delay_vs_distance(solution, time_range=[-.5, .5])
95 |
96 | plt.tight_layout()
97 | plt.show()
98 |
--------------------------------------------------------------------------------
/examples/test_raman.py:
--------------------------------------------------------------------------------
1 | """
2 | Example of dispersive wave generation in anomalus dispersion regime at
3 | a central wavelength of 835 nm in a 15 centimeter long photonic crystal fiber.
4 |
5 | Interface based on MATLAB code published in
6 | 'Supercontinuum Generation in Optical Fibers'
7 | by J. M. Dudley and J. R. Taylor, available at http://scgbook.info/.
8 | """
9 |
10 | import numpy as np
11 | import matplotlib.pyplot as plt
12 |
13 | import gnlse
14 |
15 |
16 | if __name__ == '__main__':
17 | setup = gnlse.GNLSESetup()
18 |
19 | # Numerical parameters
20 | setup.resolution = 2**14
21 | setup.time_window = 12.5 # ps
22 | setup.z_saves = 400
23 |
24 | # Input pulse parameters
25 | peak_power = 10000 # W
26 | duration = 0.050284 # ps
27 |
28 | # Physical parameters
29 | setup.wavelength = 835 # nm
30 | setup.fiber_length = 0.15 # m
31 | setup.nonlinearity = 0.11 # 1/W/m
32 | setup.pulse_model = gnlse.SechEnvelope(peak_power, duration)
33 | setup.self_steepening = True
34 |
35 | # The dispersion model is built from a Taylor expansion with coefficients
36 | # given below.
37 | loss = 0
38 | betas = np.array([
39 | -11.830e-3, 8.1038e-5, -9.5205e-8, 2.0737e-10, -5.3943e-13, 1.3486e-15,
40 | -2.5495e-18, 3.0524e-21, -1.7140e-24
41 | ])
42 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
43 |
44 | # This example extends the original code with additional simulations for
45 | # three types of models of Raman response and no raman scattering case
46 | raman_models = {
47 | 'Blow-Wood': gnlse.raman_blowwood,
48 | 'Hollenbeck-Cantrell': gnlse.raman_holltrell,
49 | 'Lin-Agrawal': gnlse.raman_linagrawal,
50 | 'No scattering': None
51 | }
52 |
53 | count = len(raman_models)
54 | plt.figure(figsize=(20, 10), facecolor='w', edgecolor='k')
55 | for (i, (name, raman_model)) in enumerate(raman_models.items()):
56 | setup.raman_model = raman_model
57 | solver = gnlse.GNLSE(setup)
58 | solution = solver.run()
59 |
60 | plt.subplot(2, count, i + 1)
61 | plt.title(name)
62 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[500, 1250])
63 |
64 | plt.subplot(2, count, i + 1 + count)
65 | gnlse.plot_delay_vs_distance(solution, time_range=[-0.5, 4])
66 | plt.tight_layout()
67 | plt.show()
68 |
--------------------------------------------------------------------------------
/examples/test_spm+gvd.py:
--------------------------------------------------------------------------------
1 | """
2 | Example: Forming of 1st order soliton pulse (sech) from gaussian input
3 | by interaction of group velocity dispersion and self-phase modulation.
4 |
5 | Interface based on MATLAB code published in
6 | 'Supercontinuum Generation in Optical Fibers'
7 | by J. M. Dudley and J. R. Taylor, available at http://scgbook.info/.
8 | """
9 |
10 | import numpy as np
11 | import gnlse
12 | import matplotlib.pyplot as plt
13 |
14 |
15 | if __name__ == '__main__':
16 | setup = gnlse.gnlse.GNLSESetup()
17 |
18 | # Numerical parameters
19 | ###########################################################################
20 | # number of grid time points
21 | setup.resolution = 2**13
22 | # time window [ps]
23 | setup.time_window = 12.5
24 | # number of distance points to save
25 | setup.z_saves = 200
26 | # relative tolerance for ode solver
27 | setup.rtol = 1e-6
28 | # absoulte tolerance for ode solver
29 | setup.atol = 1e-6
30 |
31 | # Physical parameters
32 | ###########################################################################
33 | # Central wavelength [nm]
34 | setup.wavelength = 835
35 | # Nonlinear coefficient [1/W/m]
36 | setup.nonlinearity = 0.11
37 | # Dispersion: derivatives of propagation constant at central wavelength
38 | # n derivatives of betas are in [ps^n/m]
39 | betas = np.array([-11.830e-3])
40 | # Input pulse: pulse duration [ps]
41 | tFWHM = 0.050
42 | t0 = tFWHM / 2 / np.sqrt(np.log(2)) # for dispersive length calculation
43 |
44 | # 3rd order soliton conditions
45 | ###########################################################################
46 | # Dispersive length
47 | LD = t0 ** 2 / np.abs(betas[0])
48 | # Non-linear length for 1st order soliton
49 | LNL = LD / (1 ** 2)
50 | # Input pulse: peak power [W]
51 | power = 1 / (LNL * setup.nonlinearity)
52 | # Fiber length [m]
53 | setup.fiber_length = 10 * LD
54 | # Type of pulse: gaussian
55 | setup.pulse_model = gnlse.GaussianEnvelope(power, tFWHM)
56 | # Loss coefficient [dB/m]
57 | loss = 0
58 | # Type of dyspersion operator: build from Taylor expansion
59 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
60 |
61 | # Type of Ramman scattering function: None (default)
62 | # Selftepening: not accounted
63 | setup.self_steepening = False
64 |
65 | # Simulation
66 | ###########################################################################
67 | solver = gnlse.gnlse.GNLSE(setup)
68 | solution = solver.run()
69 |
70 | # Visualization
71 | ###########################################################################
72 | plt.figure(figsize=(15, 7))
73 |
74 | plt.subplot(1, 2, 1)
75 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[780, 900])
76 | plt.subplot(1, 2, 2)
77 | gnlse.plot_delay_vs_distance(solution, time_range=[-.5, .5])
78 |
79 | plt.show()
80 |
--------------------------------------------------------------------------------
/examples/test_spm.py:
--------------------------------------------------------------------------------
1 | """
2 | Example: self-phase modulation on 3.5*pi nonlinear length
3 | for gaussian pulse as in Chapter 4 of Nonlinear Fiber Optics.
4 |
5 | Interface based on MATLAB code published in
6 | 'Supercontinuum Generation in Optical Fibers'
7 | by J. M. Dudley and J. R. Taylor, available at http://scgbook.info/.
8 | """
9 |
10 | import numpy as np
11 | import gnlse
12 | import matplotlib.pyplot as plt
13 |
14 |
15 | if __name__ == '__main__':
16 | setup = gnlse.gnlse.GNLSESetup()
17 |
18 | # Numerical parameters
19 | ###########################################################################
20 | # number of grid time points
21 | setup.resolution = 2**13
22 | # time window [ps]
23 | setup.time_window = 12.5
24 | # number of distance points to save
25 | setup.z_saves = 200
26 | # relative tolerance for ode solver
27 | setup.rtol = 1e-6
28 | # absoulte tolerance for ode solver
29 | setup.atol = 1e-6
30 |
31 | # Physical parameters
32 | ###########################################################################
33 | # Central wavelength [nm]
34 | setup.wavelength = 835
35 | # Nonlinear coefficient [1/W/m]
36 | setup.nonlinearity = 0.11
37 | # Dispersion: derivatives of propagation constant at central wavelength
38 | # n derivatives of betas are in [ps^n/m]
39 | betas = np.array([0])
40 | # Input pulse: pulse duration [ps]
41 | tFWHM = 0.050
42 |
43 | ###########################################################################
44 | # Input pulse: peak power [W]
45 | power = 1 # value can be choosen arbitrarily
46 | # Non-linear length for given nonlinearity and power
47 | LNL = 1 / (power * setup.nonlinearity)
48 | # Fiber length [m]
49 | setup.fiber_length = 3.5 * np.pi * LNL
50 | # Type of pulse: gaussian
51 | setup.pulse_model = gnlse.GaussianEnvelope(power, tFWHM)
52 | # Loss coefficient [dB/m]
53 | loss = 0
54 | # Type of dyspersion operator: build from Taylor expansion
55 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
56 |
57 | # Type of Ramman scattering function: None (default)
58 | # Selftepening: not accounted
59 | setup.self_steepening = False
60 |
61 | # Simulation
62 | ###########################################################################
63 | solver = gnlse.gnlse.GNLSE(setup)
64 | solution = solver.run()
65 |
66 | # Visualization
67 | ###########################################################################
68 | plt.subplot(1, 2, 1)
69 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[400, 1400])
70 | plt.subplot(1, 2, 2)
71 | gnlse.plot_delay_vs_distance(solution, time_range=[-.25, .25])
72 |
73 | plt.show()
74 |
--------------------------------------------------------------------------------
/examples/test_wl_del_freq.py:
--------------------------------------------------------------------------------
1 | """
2 | This example presents potential of new plot functions.
3 | Especially:
4 | -different scales(linear and logarithmic)
5 | -different x arguments(delay, frequency, wavelength)
6 | -color map as argument of plot function
7 | -slice plot for chosen z(propagation) distances
8 | or z=0 and z=end if no specific z were chosen.
9 | Data used in this example are taken from test_Dudley.py file from examples.
10 | """
11 |
12 | import numpy as np
13 | import matplotlib.pyplot as plt
14 |
15 | import gnlse
16 |
17 | if __name__ == '__main__':
18 | setup = gnlse.GNLSESetup()
19 |
20 | # Numerical parameters
21 | setup.resolution = 2**14
22 | setup.time_window = 12.5 # ps
23 | setup.z_saves = 200
24 |
25 | # Physical parameters
26 | setup.wavelength = 835 # nm
27 | setup.fiber_length = 0.15 # m
28 | setup.nonlinearity = 0.11 # 1/W/m
29 | setup.raman_model = gnlse.raman_blowwood
30 | setup.self_steepening = True
31 |
32 | # The dispersion model is built from a Taylor expansion with coefficients
33 | # given below.
34 | loss = 0
35 | betas = np.array([
36 | -11.830e-3, 8.1038e-5, -9.5205e-8, 2.0737e-10, -5.3943e-13, 1.3486e-15,
37 | -2.5495e-18, 3.0524e-21, -1.7140e-24
38 | ])
39 | setup.dispersion_model = gnlse.DispersionFiberFromTaylor(loss, betas)
40 |
41 | # Input pulse parameters
42 | power = 10000
43 | # pulse duration [ps]
44 | tfwhm = 0.05
45 | # hyperbolic secant
46 | setup.pulse_model = gnlse.SechEnvelope(power, tfwhm)
47 | solver = gnlse.GNLSE(setup)
48 | solution = solver.run()
49 |
50 | plt.figure(figsize=(14, 8), facecolor='w', edgecolor='k')
51 |
52 | plt.subplot(4, 3, 1)
53 | gnlse.plot_delay_vs_distance(solution, time_range=[-.5, 5], cmap="jet")
54 |
55 | plt.subplot(4, 3, 2)
56 | gnlse.plot_frequency_vs_distance(solution, frequency_range=[-300, 200],
57 | cmap="plasma")
58 |
59 | plt.subplot(4, 3, 3)
60 | gnlse.plot_wavelength_vs_distance(solution, WL_range=[400, 1400])
61 |
62 | plt.subplot(4, 3, 4)
63 | gnlse.plot_delay_vs_distance_logarithmic(solution, time_range=[-.5, 5],
64 | cmap="jet")
65 |
66 | plt.subplot(4, 3, 5)
67 | gnlse.plot_frequency_vs_distance_logarithmic(solution,
68 | frequency_range=[-300, 200],
69 | cmap="plasma")
70 |
71 | plt.subplot(4, 3, 6)
72 | gnlse.plot_wavelength_vs_distance_logarithmic(solution,
73 | WL_range=[400, 1400])
74 |
75 | plt.subplot(4, 3, 7)
76 | gnlse.plot_delay_for_distance_slice(solution, time_range=[-.5, 5])
77 |
78 | plt.subplot(4, 3, 8)
79 | gnlse.plot_frequency_for_distance_slice(solution,
80 | frequency_range=[-300, 200])
81 |
82 | plt.subplot(4, 3, 9)
83 | gnlse.plot_wavelength_for_distance_slice(solution, WL_range=[400, 1400])
84 |
85 | plt.subplot(4, 3, 10)
86 | gnlse.plot_delay_for_distance_slice_logarithmic(
87 | solution, time_range=[-.5, 5])
88 |
89 | plt.subplot(4, 3, 11)
90 | gnlse.plot_frequency_for_distance_slice_logarithmic(
91 | solution, frequency_range=[-300, 200])
92 |
93 | plt.subplot(4, 3, 12)
94 | gnlse.plot_wavelength_for_distance_slice_logarithmic(solution,
95 | WL_range=[400, 1400])
96 |
97 | plt.tight_layout()
98 | plt.show()
99 |
--------------------------------------------------------------------------------
/gnlse/__init__.py:
--------------------------------------------------------------------------------
1 | from gnlse.dispersion import (DispersionFiberFromTaylor,
2 | DispersionFiberFromInterpolation)
3 | from gnlse.envelopes import (SechEnvelope, GaussianEnvelope,
4 | LorentzianEnvelope, CWEnvelope)
5 | from gnlse.gnlse import GNLSESetup, Solution, GNLSE
6 | from gnlse.import_export import read_mat, write_mat
7 | from gnlse.nonlinearity import NonlinearityFromEffectiveArea
8 | from gnlse.raman_response import (raman_blowwood, raman_holltrell,
9 | raman_linagrawal)
10 | from gnlse.visualization import (
11 | plot_delay_vs_distance,
12 | plot_delay_vs_distance_logarithmic,
13 | plot_delay_for_distance_slice,
14 | plot_delay_for_distance_slice_logarithmic,
15 | plot_frequency_vs_distance,
16 | plot_frequency_vs_distance_logarithmic,
17 | plot_frequency_for_distance_slice,
18 | plot_frequency_for_distance_slice_logarithmic,
19 | plot_wavelength_vs_distance,
20 | plot_wavelength_vs_distance_logarithmic,
21 | plot_wavelength_for_distance_slice,
22 | plot_wavelength_for_distance_slice_logarithmic,
23 | quick_plot)
24 |
25 | __all__ = [
26 | 'DispersionFiberFromTaylor', 'DispersionFiberFromInterpolation',
27 | 'SechEnvelope', 'GaussianEnvelope', 'LorentzianEnvelope', 'GNLSESetup',
28 | 'GNLSE', 'Solution', 'read_mat', 'write_mat', 'raman_blowwood',
29 | 'raman_holltrell', 'raman_linagrawal',
30 | 'plot_delay_vs_distance',
31 | 'plot_delay_vs_distance_logarithmic',
32 | 'plot_delay_for_distance_slice',
33 | 'plot_delay_for_distance_slice_logarithmic',
34 | 'plot_frequency_vs_distance',
35 | 'plot_frequency_vs_distance_logarithmic',
36 | 'plot_frequency_for_distance_slice',
37 | 'plot_frequency_for_distance_slice_logarithmic',
38 | 'plot_wavelength_vs_distance',
39 | 'plot_wavelength_vs_distance_logarithmic',
40 | 'plot_wavelength_for_distance_slice',
41 | 'plot_wavelength_for_distance_slice_logarithmic',
42 | 'quick_plot', 'NonlinearityFromEffectiveArea', 'CWEnvelope'
43 | ]
44 |
--------------------------------------------------------------------------------
/gnlse/common.py:
--------------------------------------------------------------------------------
1 | pi = 3.1415926535897932384626433
2 |
3 | c = 299792.458 # Speed of light in vacuum [nm/ps]
4 | hplanck = 6.62607015e-34 # Planck constant [J.s]
5 | hbar = hplanck / 2 / pi # Reduced Planck constant [J.s]
6 |
--------------------------------------------------------------------------------
/gnlse/dispersion.py:
--------------------------------------------------------------------------------
1 | """Dispersion operator in optical fibres.
2 |
3 | Based on delivered frequency vector and damping indexes
4 | script calculates linear dispersion operator in
5 | frequency domain.
6 |
7 | """
8 | import numpy as np
9 | from scipy import interpolate
10 |
11 | from gnlse.common import c
12 |
13 |
14 | class Dispersion(object):
15 | """
16 | Attributes
17 | -----------
18 | loss : float
19 | Loss factor [dB/m]
20 | """
21 |
22 | def __init__(self, loss):
23 | self.loss = loss
24 |
25 | def D(V):
26 | """Calculate linear dispersion operator
27 | for given frequency grid created during simulation
28 |
29 | Parameters
30 | ----------
31 | V : ndarray, (N)
32 | Frequency vector
33 |
34 | Returns
35 | -------
36 | ndarray, (N)
37 | Linear dispersion operator in frequency domain
38 | """
39 |
40 | raise NotImplementedError('Dispersion not implemented')
41 |
42 | def calc_loss(self):
43 | """Calculate damping
44 | for given frequency grid created during simulation
45 | """
46 | self.alpha = np.log(10**(self.loss / 10))
47 |
48 |
49 | class DispersionFiberFromTaylor(Dispersion):
50 | """Calculates the dispersion in frequency domain
51 |
52 | Attributes
53 | ----------
54 | loss : float
55 | Loss factor [dB/m]
56 | betas : ndarray (N)
57 | Derivatives of constant propagations at pump wavelength
58 | [ps^2/m, ..., ps^n/m]
59 | """
60 |
61 | def __init__(self, loss, betas):
62 | self.loss = loss
63 | self.betas = betas
64 |
65 | def D(self, V):
66 | # Damping
67 | self.calc_loss()
68 | # Taylor series for subsequent derivatives
69 | # of constant propagation
70 | B = sum(beta / np.math.factorial(i + 2) * V**(i + 2)
71 | for i, beta in enumerate(self.betas))
72 | L = 1j * B - self.alpha / 2
73 | return L
74 |
75 |
76 | class DispersionFiberFromInterpolation(Dispersion):
77 | """Calculates the propagation function in frequency domain, using
78 | the extrapolation method based on delivered refractive indexes
79 | and corresponding wavelengths. The returned value is a vector
80 | of dispersion operator.
81 |
82 | Attributes
83 | -----------
84 | loss : float
85 | Loss factor [dB/m]
86 | neff : ndarray (N)
87 | Effective refractive index
88 | lambdas : ndarray (N)
89 | Wavelength corresponding to refractive index
90 | central_wavelength : float
91 | Wavelength corresponding to pump wavelength in nm
92 | """
93 |
94 | def __init__(self, loss, neff, lambdas, central_wavelength):
95 | # Loss factor in dB/m
96 | self.loss = loss
97 | # refractive indices
98 | self.neff = neff
99 | # wavelengths for neffs in [nm]
100 | self.lambdas = lambdas
101 | # Central frequency in [1/ps = THz]
102 | self.w0 = (2.0 * np.pi * c) / central_wavelength
103 |
104 | def D(self, V):
105 | # Central frequency [1/ps = THz]
106 | omega = 2 * np.pi * c / self.lambdas
107 | dOmega = V[1] - V[0]
108 | Bet = self.neff * omega / c * 1e9 # [1/m]
109 |
110 | # Extrapolate betas for a frequency vector
111 | fun_interpolation = interpolate.interp1d(omega,
112 | Bet,
113 | kind='cubic',
114 | fill_value="extrapolate")
115 |
116 | B = fun_interpolation(V + self.w0)
117 | # Propagation constant at central frequency [1/m]
118 | B0 = fun_interpolation(self.w0)
119 | # Value of propagation at a lower end of interval [1/m]
120 | B0plus = fun_interpolation(self.w0 + dOmega)
121 | # Value of propagation at a higher end of interval [1/m]
122 | B0minus = fun_interpolation(self.w0 - dOmega)
123 |
124 | # Difference quotient, approximation of
125 | # derivative of a function at a point [ps/m]
126 | B1 = (B0plus - B0minus) / (2 * dOmega)
127 |
128 | # Damping
129 | self.calc_loss()
130 |
131 | # Linear dispersion operator
132 | L = 1j * (B - (B0 + B1 * V)) - self.alpha / 2
133 | return L
134 |
--------------------------------------------------------------------------------
/gnlse/envelopes.py:
--------------------------------------------------------------------------------
1 | """Amplitude envelopes of different pulses
2 |
3 | This module contains functions drawing envelopes of various pulses:
4 | hyperbolic secant, gaussian and lorentzian.
5 |
6 | """
7 |
8 | import numpy as np
9 |
10 |
11 | class Envelope(object):
12 | def A(T):
13 | raise NotImplementedError()
14 |
15 |
16 | class SechEnvelope(Envelope):
17 | """Amplitude envelope of hyperbolic secant pulse.
18 |
19 | Attributes
20 | ----------
21 | Pmax : float
22 | Peak power, [W].
23 | FWHM : float
24 | Pulse duration Full-Width Half-Maximum.
25 | """
26 |
27 | def __init__(self, Pmax, FWHM):
28 | self.name = 'Hyperbolic secant envelope'
29 | self.Pmax = Pmax
30 | self.FWHM = FWHM
31 |
32 | def A(self, T):
33 | """
34 |
35 | Parameters
36 | ----------
37 | T : ndarray, (n, )
38 | Time vector
39 |
40 | Returns
41 | -------
42 | ndarray, (n, )
43 | Amplitude envelope of hyperbolic secant pulse in time.
44 | """
45 | m = 2 * np.log(1 + np.sqrt(2))
46 | return np.sqrt(self.Pmax) * 2 / (np.exp(m * T / self.FWHM) +
47 | np.exp(-m * T / self.FWHM))
48 |
49 |
50 | class GaussianEnvelope(Envelope):
51 | """Amplitude envelope of gaussian pulse.
52 |
53 | Attributes
54 | ----------
55 | Pmax : float
56 | Peak power [W].
57 | FWHM : float
58 | Pulse duration Full-Width Half-Maximum.
59 | """
60 |
61 | def __init__(self, Pmax, FWHM):
62 | self.name = 'Gaussian envelope'
63 | self.Pmax = Pmax
64 | self.FWHM = FWHM
65 |
66 | def A(self, T):
67 | """
68 |
69 | Parameters
70 | ----------
71 | T : ndarray, (n, )
72 | Time vector.
73 |
74 | Returns
75 | -------
76 | ndarray, (n, )
77 | Amplitude envelope of gaussian pulse in time.
78 | """
79 | m = 4 * np.log(2)
80 | return np.sqrt(self.Pmax) * np.exp(-m * .5 * T**2 / self.FWHM**2)
81 |
82 |
83 | class LorentzianEnvelope(Envelope):
84 | """Amplitude envelope of lorentzian pulse.
85 |
86 | Attributes
87 | ----------
88 | Pmax : float
89 | Peak power [W].
90 | FWHM : float
91 | Pulse duration Full-Width Half-Maximum.
92 | """
93 |
94 | def __init__(self, Pmax, FWHM):
95 | self.name = 'Lorentzian envelope'
96 | self.Pmax = Pmax
97 | self.FWHM = FWHM
98 |
99 | def A(self, T):
100 | """
101 |
102 | Parameters
103 | ----------
104 | T : ndarray, (n, )
105 | Time vector.
106 |
107 | Returns
108 | -------
109 | ndarray, (n, )
110 | Amplitude envelope of lorentzian pulse in time.
111 | """
112 | m = 2 * np.sqrt(np.sqrt(2) - 1)
113 | return np.sqrt(self.Pmax) / (1 + (m * T / self.FWHM)**2)
114 |
115 |
116 | class CWEnvelope(Envelope):
117 | """Amplitude envelope of continious wave
118 | with or without some temporal noise.
119 |
120 | Attributes
121 | ----------
122 | Pmax : float
123 | Peak power [W].
124 | Pn : float, optional
125 | Peak power for noise [W].
126 | """
127 |
128 | def __init__(self, Pmax, Pn=0):
129 | self.name = 'Continious Wave'
130 | self.Pmax = Pmax
131 | self.Pn = Pn
132 |
133 | def A(self, T):
134 | """
135 |
136 | Parameters
137 | ----------
138 | T : ndarray, (n, )
139 | Time vector.
140 |
141 | Returns
142 | -------
143 | ndarray, (n, )
144 | Amplitude envelope of continious wave in time.
145 | """
146 | cw = np.fft.ifft(np.sqrt(self.Pmax) * np.ones(np.size(T)))
147 | noise = 0
148 | if self.Pn:
149 | noise = np.sqrt(self.Pn
150 | ) * np.exp(
151 | 1j * 2 * np.pi * np.random.rand(np.size(T)))
152 | return np.fft.fft(cw + noise)
153 |
--------------------------------------------------------------------------------
/gnlse/gnlse.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import scipy.integrate
3 | import pyfftw
4 | import tqdm
5 |
6 | from gnlse.common import c
7 | from gnlse.import_export import write_mat, read_mat
8 |
9 |
10 | class GNLSESetup:
11 | """
12 | Model inputs for the ``GNLSE`` class.
13 |
14 | Attributes
15 | ----------
16 | resolution : int
17 | Number of points on the computational grid. Determines time resolution
18 | and bandwidth. Avoid numbers with large prime factors.
19 | time_window : float [ps]
20 | Width of the time window.
21 | wavelength : float [nm]
22 | Central wavelength of the input pulse.
23 | fiber_length : float [m]
24 | Length of the simulated optical fiber.
25 | z_saves : int
26 | Number of snapshots to save along the fiber. Larger numbers require
27 | more memory to store the result.
28 | nonlinearity : float [1/W/m]
29 | Effective nonlinearity.
30 | pulse_model : Envelope
31 | Input pulse envelope model.
32 | dispersion_model : Dispersion, optional
33 | Fiber dispersion model or ``None`` to model a dispersionless fiber.
34 | raman_model : function, optional
35 | Raman scattering model or ``None`` if the effect is to be neglected.
36 | self_steepning : bool, optional
37 | Whether to include the effect of self-steepening. Disabled by default.
38 | rtol : float, optional
39 | Relative tolerance passed to the ODE solver.
40 | atol : float, optional
41 | Absolute tolerance passed to the ODE solver.
42 | method : str, optional
43 | Integration method passed to the ODE solver.
44 | """
45 |
46 | def __init__(self):
47 | self.resolution = None
48 | self.time_window = None
49 | self.wavelength = None
50 | self.fiber_length = None
51 |
52 | self.z_saves = 200
53 | self.nonlinearity = 0
54 | self.pulse_model = None
55 | self.dispersion_model = None
56 | self.raman_model = None
57 | self.self_steepening = False
58 |
59 | self.rtol = 1e-3
60 | self.atol = 1e-4
61 | self.method = 'RK45'
62 |
63 |
64 | class Solution:
65 | """
66 | Represents a solution to a GNLSE problem.
67 |
68 | Attributes
69 | ----------
70 | t : ndarray, (n,)
71 | Time domain grid.
72 | W : ndarray, (n,)
73 | Absolute angular frequency grid.
74 | Z : ndarray (m,)
75 | Points at which intermediate steps were saved.
76 | At : ndarray, (n, m)
77 | Intermediate steps in the time domain.
78 | AW : ndarray, (n, m)
79 | Intermediate steps in the frequency domain.
80 | """
81 |
82 | def __init__(self, t=None, W=None, w_0=None, Z=None, At=None, AW=None,
83 | Aty=None, AWy=None):
84 | self.t = t
85 | self.W = W
86 | self.w_0 = w_0
87 | self.Z = Z
88 | self.At = At
89 | self.AW = AW
90 |
91 | def to_file(self, path):
92 | """
93 | Saves a solution to a file.
94 |
95 | Parameters
96 | ----------
97 | path : str
98 | Path to file.
99 | """
100 |
101 | data = {'t': self.t, 'W': self.W, 'Z': self.Z, 'At': self.At,
102 | 'AW': self.AW}
103 | write_mat(data, path)
104 |
105 | def from_file(self, path):
106 | """
107 | Load a solution from file.
108 |
109 | Parameters
110 | ----------
111 | path : str
112 | Path to file.
113 | """
114 |
115 | data = read_mat(path)
116 | self.t = data['t']
117 | self.W = data['W']
118 | self.Z = data['Z']
119 | self.At = data['At']
120 | self.AW = data['AW']
121 |
122 |
123 | class GNLSE:
124 | """
125 | Models propagation of an optical pulse in a fiber by integrating
126 | the generalized non-linear Schrödinger equation.
127 |
128 | Attributes
129 | ----------
130 | setup : GNLSESetup
131 | Model inputs in the form of a ``GNLSESetup`` object.
132 | """
133 |
134 | def __init__(self, setup):
135 | if not isinstance(setup, GNLSESetup):
136 | raise TypeError("setup is not an instance of GNLSESetup")
137 |
138 | if setup.resolution is None:
139 | raise ValueError("'resolution' not set")
140 | if setup.time_window is None:
141 | raise ValueError("'time_window' not set")
142 | if setup.wavelength is None:
143 | raise ValueError("'wavelength' not set")
144 | if setup.fiber_length is None:
145 | raise ValueError("'fiber_length' not set")
146 | if setup.pulse_model is None:
147 | raise ValueError("'pulse_model' not set")
148 |
149 | # simulation parameters
150 | self.fiber_length = setup.fiber_length
151 | self.z_saves = setup.z_saves
152 | self.rtol = setup.rtol
153 | self.atol = setup.atol
154 | self.method = setup.method
155 | self.N = setup.resolution
156 |
157 | # Time domain grid
158 | self.t = np.linspace(-setup.time_window / 2,
159 | setup.time_window / 2,
160 | self.N)
161 |
162 | # Relative angular frequency grid
163 | self.V = 2 * np.pi * np.arange(-self.N / 2,
164 | self.N / 2
165 | ) / (self.N * (self.t[1] - self.t[0]))
166 | # Central angular frequency [10^12 rad]
167 | self.w_0 = (2.0 * np.pi * c) / setup.wavelength
168 | self.Omega = self.V + self.w_0
169 |
170 | # Absolute angular frequency grid
171 | if setup.self_steepening and np.abs(self.w_0) > np.finfo(float).eps:
172 | W = self.V + self.w_0
173 | else:
174 | W = np.full(self.V.shape, self.w_0)
175 | self.W = np.fft.fftshift(W)
176 |
177 | # Nonlinearity
178 | if hasattr(setup.nonlinearity, 'gamma'):
179 | # in case in of frequency dependent nonlinearity
180 | gamma, self.scale = setup.nonlinearity.gamma(self.V)
181 | self.gamma = gamma / self.w_0
182 | self.gamma = np.fft.fftshift(self.gamma)
183 | self.scale = np.fft.fftshift(self.scale)
184 | else:
185 | # in case in of direct introduced value
186 | self.gamma = setup.nonlinearity / self.w_0
187 | self.scale = 1
188 |
189 | # Raman scattering
190 | self.RW = None
191 | if setup.raman_model:
192 | self.fr, RT = setup.raman_model(self.t)
193 | if np.abs(self.fr) < np.finfo(float).eps:
194 | self.RW = None
195 | else:
196 | self.RW = self.N * np.fft.ifft(
197 | np.fft.fftshift(np.transpose(RT)))
198 |
199 | # Dispersion operator
200 | if setup.dispersion_model:
201 | self.D = setup.dispersion_model.D(self.V)
202 | else:
203 | self.D = np.zeros(self.V.shape)
204 |
205 | # Input pulse
206 | if hasattr(setup.pulse_model, 'A'):
207 | self.A = setup.pulse_model.A(self.t)
208 | else:
209 | self.A = setup.pulse_model
210 |
211 | def run(self):
212 | """
213 | Solve one mode GNLSE equation described by the given
214 | ``GNLSESetup`` object.
215 |
216 | Returns
217 | -------
218 | setup : Solution
219 | Simulation results in the form of a ``Solution`` object.
220 | """
221 | dt = self.t[1] - self.t[0]
222 | self.D = np.fft.fftshift(self.D)
223 | x = pyfftw.empty_aligned(self.N, dtype="complex128")
224 | X = pyfftw.empty_aligned(self.N, dtype="complex128")
225 | plan_forward = pyfftw.FFTW(x, X)
226 | plan_inverse = pyfftw.FFTW(X, x, direction="FFTW_BACKWARD")
227 |
228 | progress_bar = tqdm.tqdm(total=self.fiber_length, unit='m')
229 |
230 | def rhs(z, AW):
231 | """
232 | The right hand side of the differential equation to integrate.
233 | """
234 |
235 | progress_bar.n = round(z, 3)
236 | progress_bar.update(0)
237 |
238 | x[:] = AW * np.exp(self.D * z)
239 | At = plan_forward().copy()
240 | IT = np.abs(At)**2
241 |
242 | if self.RW is not None:
243 | X[:] = IT
244 | plan_inverse()
245 | x[:] *= self.RW
246 | plan_forward()
247 | RS = dt * self.fr * X
248 | X[:] = At * ((1 - self.fr) * IT + RS)
249 | M = plan_inverse()
250 | else:
251 | X[:] = At * IT
252 | M = plan_inverse()
253 |
254 | rv = 1j * self.gamma * self.W * M * np.exp(
255 | -self.D * z)
256 |
257 | return rv
258 |
259 | Z = np.linspace(0, self.fiber_length, self.z_saves)
260 | solution = scipy.integrate.solve_ivp(
261 | rhs,
262 | t_span=(0, self.fiber_length),
263 | y0=np.fft.ifft(self.A) * self.scale,
264 | t_eval=Z,
265 | rtol=self.rtol,
266 | atol=self.atol,
267 | method=self.method)
268 | AW = solution.y.T
269 |
270 | progress_bar.close()
271 |
272 | # Transform the results into the time domain
273 | At = np.zeros(AW.shape, dtype=AW.dtype)
274 | for i in range(len(AW[:, 0])):
275 | AW[i, :] *= np.exp(np.transpose(
276 | self.D) * Z[i]) / self.scale
277 | At[i, :] = np.fft.fft(AW[i, :])
278 | AW[i, :] = np.fft.fftshift(AW[i, :]) * self.N * dt
279 |
280 | return Solution(self.t, self.Omega, self.w_0, Z, At, AW)
281 |
--------------------------------------------------------------------------------
/gnlse/import_export.py:
--------------------------------------------------------------------------------
1 | """Import and export \\*.mat files.
2 |
3 | This module contains functions that enable to read matlab files (\\*.mat)
4 | in python as dictionary, and to export dictionary to \\*.mat.
5 |
6 | """
7 |
8 | import hdf5storage as hdf
9 |
10 |
11 | def read_mat(filename):
12 | """Imports \\*.mat file as dictionary.
13 |
14 | Parameters
15 | ----------
16 | filename : string
17 | Name of \\*.mat file ('example.mat').
18 |
19 | Returns
20 | -------
21 | mat : dict
22 | dictionary of variables in imported file
23 | keys - names of variables
24 | values - variables' values
25 |
26 | """
27 | mat = hdf.loadmat(filename, appendmat=True)
28 | return mat
29 |
30 |
31 | def write_mat(dictionary, filename):
32 | """Exports dictionary to \\*.mat file.
33 |
34 | Parameters
35 | ----------
36 | dictionary : dict
37 | A list of variables.
38 | filename : string
39 | Name of \\*.mat file ('example.mat').
40 | """
41 |
42 | hdf.savemat(filename,
43 | dictionary,
44 | appendmat=True,
45 | store_python_metadata=True,
46 | action_for_matlab_incompatible='ignore')
47 |
--------------------------------------------------------------------------------
/gnlse/nonlinearity.py:
--------------------------------------------------------------------------------
1 | """Nonlinearity coefficient in optical fibres.
2 |
3 | Based on delivered frequency vector and effictive mode areas
4 | script calculates nonlinear coefficient in
5 | frequency domain.
6 |
7 | """
8 | import numpy as np
9 | from scipy import interpolate
10 |
11 | from gnlse.common import c
12 |
13 |
14 | class Nonlinearity(object):
15 | def gamma(V):
16 | """Calculate nonlinear coefficient
17 | for given frequency grid created during simulation
18 |
19 | Parameters
20 | ----------
21 | V : ndarray, (N)
22 | Frequency vector
23 |
24 | Returns
25 | -------
26 | ndarray, (N)
27 | Nonlinear coefficient in frequency domain
28 | """
29 |
30 | raise NotImplementedError('Nonlinearity not implemented')
31 |
32 |
33 | class NonlinearityFromEffectiveArea(Nonlinearity):
34 | """Calculate the nonlinearity coefficient in
35 | frequency domain based on modified gnlse example form
36 | J. Lægsgaard, "Mode profile dispersion in the generalized
37 | nonlinear Schrödinger equation,"
38 | Opt. Express 15, 16110-16123 (2007).
39 |
40 | Attributes
41 | ----------
42 | neff : ndarray (N)
43 | Effective refractive index
44 | Aeff : ndarray (N)
45 | Effective mode area
46 | lambdas : ndarray (N)
47 | Wavelength corresponding to refractive index
48 | central_wavelength : float
49 | Wavelength corresponding to pump wavelength in nm
50 | n2 : float
51 | Nonlinear index of refraction in m^2/W
52 | """
53 |
54 | def __init__(self, neff, Aeff, lambdas, central_wavelength,
55 | n2=2.7e-20, neff_max=None):
56 | # refractive indices
57 | self.neff = neff
58 | # efective mode area in m^-2
59 | self.Aeff = Aeff
60 | # wavelengths for neffs in nm
61 | self.lambdas = lambdas
62 | # central frequency in 1/ps [THz]
63 | self.w0 = (2.0 * np.pi * c) / central_wavelength
64 | # nonlinear index of refraction in m^2/W
65 | self.n2 = n2
66 | # maximum (artificial) value of neff
67 | self.neff_max = neff_max
68 |
69 | def gamma(self, V):
70 | # Central frequency [1/ps = THz]
71 | omega = 2 * np.pi * c / self.lambdas
72 | Omega = V + self.w0
73 |
74 | # Extrapolate effective mode area for a frequency vector
75 | Aeff_interp = interpolate.interp1d(omega,
76 | self.Aeff,
77 | kind='cubic',
78 | fill_value="extrapolate")
79 | # Extrapolate effective mode area for a frequency vector
80 | neff_interp = interpolate.interp1d(omega,
81 | self.neff,
82 | kind='cubic',
83 | fill_value="extrapolate")
84 |
85 | # Refractive index
86 | neff = neff_interp(Omega)
87 | if self.neff_max is not None:
88 | neff[Omega < omega[-1]] = self.neff_max
89 | # and at central frequency
90 | n0 = neff_interp(self.w0)
91 | # Efective mode area
92 | Aeff = Aeff_interp(Omega)
93 | if self.neff_max is not None:
94 | Aeff[Omega < omega[-1]] = max(self.Aeff)
95 | # and at central frequency [1/m^2]
96 | Aeff0 = Aeff_interp(self.w0)
97 |
98 | gamma = self.n2 * self.w0 \
99 | * n0 / c / 1e-9 / neff / np.sqrt(Aeff * Aeff0)
100 | return gamma, np.power(Aeff0 / Aeff, 1. / 4)
101 |
--------------------------------------------------------------------------------
/gnlse/raman_response.py:
--------------------------------------------------------------------------------
1 | """Calculates different Raman responses , based on the
2 | chosen Raman model, the response is calculated.
3 | There are three available Raman reponse models for
4 | silica optical fibers:
5 | - based on K. J. Blow and D. Wood model,
6 | - based on Dawn Hollenbeck and Cyrus D. Cantrell model,
7 | - based on Q. Lin and Govind P. Agrawal model.
8 |
9 | Example
10 | -------
11 | By applying different index of raman response for
12 | silica fibers, different model is chosen.
13 | Function takes the time vector and calculates the
14 | Raman response based on the chosen model.
15 |
16 | """
17 |
18 | import numpy as np
19 |
20 |
21 | def raman_blowwood(T):
22 | """Raman scattering function for silica optical fibers, based on K. J. Blow
23 | and D. Wood model.
24 |
25 | Parameters
26 | ----------
27 | T : float
28 | Time vector.
29 |
30 | Returns
31 | -------
32 | fr : float
33 | Share of Raman response.
34 | RT : ndarray
35 | Vector representing Raman response.
36 |
37 | """
38 |
39 | # Raman response [arbitrary units]
40 | fr = 0.18
41 | # Adjustable parameters used to fit the actual Raman gain spectrum [ps]
42 | tau1 = 0.0122
43 | tau2 = 0.032
44 | # Raman response function
45 | ha = (tau1**2 + tau2**2) / tau1 / (tau2**2) * np.exp(-T / tau2) * np.sin(
46 | T / tau1)
47 | RT = ha
48 |
49 | RT[T < 0] = 0
50 |
51 | return fr, RT
52 |
53 |
54 | def raman_holltrell(T):
55 | """Raman scattering function for silica optical fibers, based on Dawn
56 | Hollenbeck and Cyrus D. Cantrell model.
57 |
58 | Parameters
59 | ----------
60 | T : float
61 | Time vector.
62 |
63 | Returns
64 | -------
65 | fr : float
66 | Share of Raman response.
67 | RT : ndarray
68 | Vector representing Raman response.
69 |
70 | """
71 |
72 | # Raman response [arbitrary units]
73 | fr = 0.2
74 | # The speed of light [nm/ps]
75 | c = 299792458 * 1e-3
76 |
77 | # Component position [1/cm]
78 | CP = np.array([
79 | 56.25, 100.0, 231.25, 362.5, 463.0, 497.0, 611.5, 691.67, 793.67,
80 | 835.5, 930.0, 1080.0, 1215.0
81 | ])
82 | # Peak intensity (amplitude)
83 | A = np.array([
84 | 1.0, 11.40, 36.67, 67.67, 74.0, 4.5, 6.8, 4.6, 4.2, 4.5, 2.7, 3.1, 3.0
85 | ])
86 | # Gaussian FWHM [1/cm]
87 | Gauss = np.array([
88 | 52.10, 110.42, 175.00, 162.50, 135.33, 24.5, 41.5, 155.00, 59.5, 64.3,
89 | 150.0, 91.0, 160.0
90 | ])
91 | # Lorentzian FWHM [1/cm]
92 | Lorentz = np.array([
93 | 17.37, 38.81, 58.33, 54.17, 45.11, 8.17, 13.83, 51.67, 19.83, 21.43,
94 | 50.00, 30.33, 53.33
95 | ])
96 |
97 | w = 1e-7 * 2 * np.pi * c * CP
98 | L = 1e-7 * np.pi * c * Gauss
99 | gamma = 1e-7 * np.pi * c * Lorentz
100 |
101 | # RT = A * np.exp(-gamma * T) * np.exp((-L ** 2 * T ** 2 )/ 4) * np.sin(
102 | # w * T) # rozszerzenie pośrednie
103 | # RT = A * np.exp((-(L ** 2) * T ** 2) / 4) * np.sin(w * T) # nonuniform
104 | # RT = A * np.sin(w * T) * np.exp(-gamma * T) # unform
105 |
106 | RT = np.zeros_like(T)
107 |
108 | for i in range(len(A)):
109 | RT += A[i] * np.exp(-gamma[i] * T) * np.exp(
110 | (-L[i]**2 * T**2) / 4) * np.sin(w[i] * T)
111 |
112 | RT[T < 0] = 0
113 | dt = T[1] - T[0]
114 | RT = RT / (np.sum(RT) * dt)
115 |
116 | return fr, RT
117 |
118 |
119 | def raman_linagrawal(T):
120 | """Raman scattering function for silica optical fibers, based on Q. Lin
121 | and Govind P. Agrawal model.
122 |
123 | Parameters
124 | ----------
125 | T : float
126 | Time vector.
127 |
128 | Returns
129 | -------
130 | fr : float
131 | Share of Raman response.
132 | RT : ndarray
133 | Vector representing Raman response.
134 |
135 | """
136 |
137 | # Raman response [arbitrary units]
138 | fr = 0.245
139 | # Adjustable parameters used to fit the actual Raman gain spectrum [ps]
140 | tau1 = 0.0122
141 | tau2 = 0.032
142 | taub = 0.096
143 | # Fractional contribution of the anisotropic reponse to the total Raman
144 | # response
145 | fb = 0.21
146 | fc = 0.04
147 | # Fractional contribution of the isotropic reponse to the total Raman
148 | # response
149 | fa = 1 - fb - fc
150 | # Anisotropic Raman response
151 | ha = (tau1**2 + tau2**2) / tau1 / (tau2**2) * np.exp(-T / tau2) * np.sin(
152 | T / tau1)
153 | # Izotropic Raman respons
154 | hb = (2 * taub - T) / (taub**2) * np.exp(-T / taub)
155 | # Total Raman response
156 | RT = (fa + fc) * ha + fb * hb
157 |
158 | RT[T < 0] = 0
159 |
160 | return fr, RT
161 |
162 |
163 | if __name__ == '__main__':
164 | """Calculates different Raman responses and plots them.
165 | Based on the chosen Raman model, the response is
166 | calculated and shown on the graph. There are three
167 | available Raman reponse models.
168 | """
169 | import matplotlib.pyplot as plt
170 | # Initial paremeters
171 | ###########################################################################
172 | # Number of grid points
173 | n = 2**13
174 | # Time window width [ps]
175 | twidth = 12.5
176 | # The speed of light [nm/ps]
177 | c = 299792458 * 1e-3
178 | # Central wavelength [nm]
179 | wavelength = 835
180 | # Central frequency [THz]
181 | w0 = (2 * np.pi * c) / wavelength
182 | # Time grid [ps]
183 | T = np.linspace(-twidth / 2, twidth / 2, n)
184 |
185 | # Blowwood Raman response
186 | fr, RT1 = raman_blowwood(T)
187 | RT1 = RT1 / np.max(RT1)
188 | # Linagrawal Raman response
189 | fr2, RT2 = raman_linagrawal(T)
190 | RT2 = RT2 / np.max(RT2)
191 | # Holltrell Raman response
192 | fr3, RT3 = raman_holltrell(T)
193 | RT3 = RT3 / np.max(RT3)
194 |
195 | plt.plot(T, RT1, label="Blowwod")
196 | plt.plot(T, RT2, label="Linagrawal")
197 | plt.plot(T, RT3, label="Holltrell")
198 |
199 | plt.xlim(-0.025, 1)
200 | plt.ylabel("Raman Response [AU]")
201 | plt.xlabel("Time Grid [ps]")
202 |
203 | plt.legend()
204 |
205 | plt.show()
206 |
--------------------------------------------------------------------------------
/gnlse/visualization.py:
--------------------------------------------------------------------------------
1 | """
2 | Various plotting functions for visualizing GNLSE simulations using Matplotlib.
3 | """
4 |
5 | import numpy as np
6 | import matplotlib.pyplot as plt
7 |
8 | from scipy.interpolate import interp2d
9 |
10 | from gnlse.common import c
11 |
12 |
13 | def plot_frequency_vs_distance_logarithmic(solver, ax=None, norm=None,
14 | frequency_range=None, cmap="magma"):
15 | """Plotting results in logarithmic scale in frequency domain.
16 |
17 | Parameters
18 | ----------
19 | solver : Solution
20 | Model outputs in the form of a ``Solution`` object.
21 | frequency_range : list, (2, )
22 | frequency range. Set [-150, 150] as default.
23 | ax : :class:`~matplotlib.axes.Axes`
24 | :class:`~matplotlib.axes.Axes` instance for plotting
25 | norm : float
26 | Normalization factor for output spectrum. As default maximum of
27 | square absolute of ``solver.AW`` variable is taken.
28 |
29 | Returns
30 | -------
31 | ax : :class:`~matplotlib.axes.Axes`
32 | Used :class:`~matplotlib.axes.Axes` instance.
33 | """
34 |
35 | if ax is None:
36 | ax = plt.gca()
37 |
38 | if norm is None:
39 | norm = np.max(np.abs(solver.AW)**2)
40 |
41 | lIW = np.fliplr(
42 | 10 * np.log10(np.abs(solver.AW)**2 / norm,
43 | where=(np.abs(solver.AW)**2 > 0)))
44 | frequency = (solver.W - solver.w_0) / 2 / np.pi # frequency grid
45 |
46 | if frequency_range is not None:
47 | iis = np.logical_and(frequency >= frequency_range[0],
48 | frequency <= frequency_range[1])
49 | # indices of interest
50 |
51 | frequency = frequency[iis]
52 | lIW = lIW[:, iis]
53 |
54 | ax.imshow(lIW, origin='lower', aspect='auto', cmap=cmap,
55 | extent=[np.min(frequency), np.max(frequency),
56 | 0, np.max(solver.Z)], vmin=-40)
57 | ax.set_xlabel("Frequency [THz]")
58 | ax.set_ylabel("Distance [m]")
59 | return ax
60 |
61 |
62 | def plot_frequency_vs_distance(solver, frequency_range=None,
63 | ax=None, norm=None, cmap="magma"):
64 | """Plotting results in frequency domain. Linear scale.
65 |
66 | Parameters
67 | ----------
68 | solver : Solution
69 | Model outputs in the form of a ``Solution`` object.
70 | frequency_range : list, (2, )
71 | frequency range. Set [-150, 150] as default.
72 | ax : :class:`~matplotlib.axes.Axes`
73 | :class:`~matplotlib.axes.Axes` instance for plotting
74 | norm : float
75 | Normalization factor for output spectrum. As default maximum of
76 | square absolute of ``solver.AW`` variable is taken.
77 |
78 | Returns
79 | -------
80 | ax : :class:`~matplotlib.axes.Axes`
81 | Used :class:`~matplotlib.axes.Axes` instance.
82 | """
83 |
84 | if ax is None:
85 | ax = plt.gca()
86 |
87 | if norm is None:
88 | norm = np.max(np.abs(solver.AW)**2)
89 |
90 | IW = np.fliplr(
91 | np.abs(solver.AW)**2 / norm)
92 | frequency = (solver.W - solver.w_0) / 2 / np.pi # frequency grid
93 |
94 | if frequency_range is not None:
95 | iis = np.logical_and(frequency >= frequency_range[0],
96 | frequency <= frequency_range[1])
97 | # indices of interest
98 |
99 | frequency = frequency[iis]
100 | IW = IW[:, iis]
101 |
102 | ax.imshow(IW, origin='lower', aspect='auto', cmap=cmap,
103 | extent=[np.min(frequency), np.max(frequency),
104 | 0, np.max(solver.Z)], vmin=0)
105 | ax.set_xlabel("Frequency [THz]")
106 | ax.set_ylabel("Distance [m]")
107 | return ax
108 |
109 |
110 | def plot_delay_for_distance_slice(solver, time_range=None, ax=None,
111 | z_slice=None, norm=None):
112 | """Plotting intensity in linear scale in time domain.
113 |
114 | Parameters
115 | ----------
116 | solver : Solution
117 | Model outputs in the form of a ``Solution`` object.
118 | time_range : list, (2, )
119 | Time range. Set [min(``solver.t``), max(``solver.t``)] as default.
120 | ax : :class:`~matplotlib.axes.Axes`
121 | :class:`~matplotlib.axes.Axes` instance for plotting.
122 | norm : float
123 | Normalization factor for output spectrum. As default maximum of
124 | square absolute of ``solver.At`` variable is taken.
125 |
126 | Returns
127 | -------
128 | ax : :class:`~matplotlib.axes.Axes`
129 | Used :class:`~matplotlib.axes.Axes` instance.
130 | """
131 |
132 | if ax is None:
133 | ax = plt.gca()
134 |
135 | if time_range is None:
136 | time_range = [np.min(solver.t), np.max(solver.t)]
137 |
138 | if norm is None:
139 | norm = np.max(np.abs(solver.At[0][:])**2)
140 |
141 | It = np.abs(solver.At)**2 / norm
142 |
143 | # indices of interest if no z_slice positions were given
144 | if z_slice is None:
145 | iis = [0, -1]
146 | # indices of interest nearest to given z_slice positions
147 | else:
148 | iis = [np.nonzero(
149 | np.min(np.abs(solver.Z - z)) == np.abs(solver.Z - z)
150 | )[0][0] for z in z_slice]
151 |
152 | for i in iis:
153 | label_i = "z = " + str(solver.Z[i]) + "m"
154 | ax.plot(solver.t, It[i][:], label=label_i)
155 |
156 | ax.set_xlim(time_range)
157 | ax.set_xlabel("Delay [ps]")
158 | ax.set_ylabel("Normalized Power")
159 | ax.legend()
160 | return ax
161 |
162 |
163 | def plot_wavelength_for_distance_slice(solver, WL_range=None, ax=None,
164 | z_slice=None, norm=None):
165 | """Plotting chosen slices of intensity
166 | in linear scale in wavelength domain.
167 |
168 | Parameters
169 | ----------
170 | solver : Solution
171 | Model outputs in the form of a ``Solution`` object.
172 | WL_range : list, (2, )
173 | Wavelength range. Set [400, 1350] as default.
174 | ax : :class:`~matplotlib.axes.Axes`
175 | :class:`~matplotlib.axes.Axes` instance for plotting
176 | norm : float
177 | Normalization factor for output spectrum. As default maximum of
178 | square absolute of ``solver.AW`` variable is taken.
179 |
180 | Returns
181 | -------
182 | ax : :class:`~matplotlib.axes.Axes`
183 | Used :class:`~matplotlib.axes.Axes` instance.
184 | """
185 |
186 | if ax is None:
187 | ax = plt.gca()
188 |
189 | if WL_range is None:
190 | WL_range = [np.min(c / (solver.W / 2 / np.pi)),
191 | np.max(c / (solver.W / 2 / np.pi))]
192 |
193 | if norm is None:
194 | norm = np.max(np.abs(solver.AW)**2)
195 |
196 | IW = np.fliplr(
197 | np.abs(solver.AW)**2 / norm)
198 | WL = 2 * np.pi * c / solver.W # wavelength grid
199 | WL_asc = np.flip(WL, ) # ascending order for interpolation
200 | iio = np.logical_and(WL_asc > WL_range[0],
201 | WL_asc < WL_range[1]) # indices in order
202 |
203 | WL_asc = WL_asc[iio]
204 | IW = IW[:, iio]
205 |
206 | # indices of interest if no z_slice positions were given
207 | if z_slice is None:
208 | iis = [0, -1]
209 | # indices of interest nearest to given z_slice positions
210 | else:
211 | iis = [np.nonzero(
212 | np.min(np.abs(solver.Z - z)) == np.abs(solver.Z - z)
213 | )[0][0] for z in z_slice]
214 |
215 | for i in iis:
216 | label_i = "z = " + str(solver.Z[i]) + "m"
217 | ax.plot(WL_asc, IW[i][:], label=label_i)
218 |
219 | ax.set_xlim([np.min(WL_asc), np.max(WL_asc)])
220 | ax.set_xlabel("Wavelength [nm]")
221 | ax.set_ylabel("Normalized Spectral Density")
222 | ax.legend()
223 | return ax
224 |
225 |
226 | def plot_wavelength_for_distance_slice_logarithmic(solver, WL_range=None,
227 | ax=None,
228 | z_slice=None, norm=None):
229 | """Plotting chosen slices of intensity
230 | in linear scale in wavelength domain.
231 |
232 | Parameters
233 | ----------
234 | solver : Solution
235 | Model outputs in the form of a ``Solution`` object.
236 | WL_range : list, (2, )
237 | Wavelength range. Set [400, 1350] as default.
238 | ax : :class:`~matplotlib.axes.Axes`
239 | :class:`~matplotlib.axes.Axes` instance for plotting
240 | norm : float
241 | Normalization factor for output spectrum. As default maximum of
242 | square absolute of ``solver.AW`` variable is taken.
243 |
244 | Returns
245 | -------
246 | ax : :class:`~matplotlib.axes.Axes`
247 | Used :class:`~matplotlib.axes.Axes` instance.
248 | """
249 |
250 | if ax is None:
251 | ax = plt.gca()
252 |
253 | if WL_range is None:
254 | WL_range = [np.min(c / (solver.W / 2 / np.pi)),
255 | np.max(c / (solver.W / 2 / np.pi))]
256 |
257 | if norm is None:
258 | norm = np.max(np.abs(solver.AW)**2)
259 |
260 | lIW = np.fliplr(
261 | 10 * np.log10(np.abs(solver.AW)**2 / norm,
262 | where=(np.abs(solver.AW)**2 > 0)))
263 | WL = 2 * np.pi * c / solver.W # wavelength grid
264 | WL_asc = np.flip(WL, ) # ascending order for interpolation
265 | iio = np.logical_and(WL_asc > WL_range[0],
266 | WL_asc < WL_range[1]) # indices in order
267 |
268 | WL_asc = WL_asc[iio]
269 | lIW = lIW[:, iio]
270 |
271 | # indices of interest if no z_slice positions were given
272 | if z_slice is None:
273 | iis = [0, -1]
274 | # indices of interest nearest to given z_slice positions
275 | else:
276 | iis = [np.nonzero(
277 | np.min(np.abs(solver.Z - z)) == np.abs(solver.Z - z)
278 | )[0][0] for z in z_slice]
279 |
280 | for i in iis:
281 | label_i = "z = " + str(solver.Z[i]) + "m"
282 | ax.plot(WL_asc, lIW[i][:], label=label_i)
283 |
284 | ax.set_xlim([np.min(WL_asc), np.max(WL_asc)])
285 | ax.set_ylim(-40)
286 | ax.set_xlabel("Wavelength [nm]")
287 | ax.set_ylabel("Normalized Spectral Density")
288 | ax.legend()
289 | return ax
290 |
291 |
292 | def plot_delay_for_distance_slice_logarithmic(solver, time_range=None, ax=None,
293 | z_slice=None, norm=None):
294 | """Plotting chosen slices of intensity in linear scale in time domain.
295 |
296 | Parameters
297 | ----------
298 | solver : Solution
299 | Model outputs in the form of a ``Solution`` object.
300 | time_range : list, (2, )
301 | Time range. Set [min(``solver.t``), max(``solver.t``)] as default.
302 | ax : :class:`~matplotlib.axes.Axes`
303 | :class:`~matplotlib.axes.Axes` instance for plotting.
304 | norm : float
305 | Normalization factor for output spectrum. As default maximum of
306 | square absolute of ``solver.At`` variable is taken.
307 |
308 | Returns
309 | -------
310 | ax : :class:`~matplotlib.axes.Axes`
311 | Used :class:`~matplotlib.axes.Axes` instance.
312 | """
313 |
314 | if ax is None:
315 | ax = plt.gca()
316 |
317 | if time_range is None:
318 | time_range = [np.min(solver.t), np.max(solver.t)]
319 |
320 | if norm is None:
321 | norm = np.max(np.abs(solver.At)**2)
322 |
323 | lIt = 10 * np.log10(np.abs(solver.At)**2 / norm,
324 | where=(np.abs(solver.At)**2 > 0))
325 |
326 | # indices of interest if no z_slice positions were given
327 | if z_slice is None:
328 | iis = [0, -1]
329 | # indices of interest nearest to given z_slice positions
330 | else:
331 | iis = [np.nonzero(
332 | np.min(np.abs(solver.Z - z)) == np.abs(solver.Z - z)
333 | )[0][0] for z in z_slice]
334 |
335 | for i in iis:
336 | label_i = "z = " + str(solver.Z[i]) + "m"
337 | ax.plot(solver.t, lIt[i][:], label=label_i)
338 |
339 | ax.set_xlim(time_range)
340 | ax.set_ylim(-40)
341 | ax.set_xlabel("Delay [ps]")
342 | ax.set_ylabel("Normalized Power")
343 | ax.legend()
344 | return ax
345 |
346 |
347 | def plot_frequency_for_distance_slice(solver, frequency_range=None, ax=None,
348 | z_slice=None, norm=None):
349 | """Plotting chosen slices of intensity in linear scale in frequency domain.
350 |
351 | Parameters
352 | ----------
353 | solver : Solution
354 | Model outputs in the form of a ``Solution`` object.
355 | frequency_range : list, (2, )
356 | frequency range. Set [-150, 150] as default.
357 | ax : :class:`~matplotlib.axes.Axes`
358 | :class:`~matplotlib.axes.Axes` instance for plotting
359 | norm : float
360 | Normalization factor for output spectrum. As default maximum of
361 | square absolute of ``solver.AW`` variable is taken.
362 |
363 | Returns
364 | -------
365 | ax : :class:`~matplotlib.axes.Axes`
366 | Used :class:`~matplotlib.axes.Axes` instance.
367 | """
368 |
369 | if ax is None:
370 | ax = plt.gca()
371 |
372 | if frequency_range is None:
373 | frequency_range = [np.min((solver.W - solver.w_0) / 2 / np.pi),
374 | np.max((solver.W - solver.w_0) / 2 / np.pi)]
375 |
376 | if norm is None:
377 | norm = np.max(np.abs(solver.AW)**2)
378 |
379 | IW = np.fliplr(
380 | np.abs(solver.AW)**2 / norm)
381 |
382 | # indices of interest if no z_slice positions were given
383 | if z_slice is None:
384 | iis = [0, -1] # beginning, end
385 | # indices of interest nearest to given z_slice positions
386 | else:
387 | iis = [np.nonzero(
388 | np.min(np.abs(solver.Z - z)) == np.abs(solver.Z - z)
389 | )[0][0] for z in z_slice]
390 |
391 | for i in iis:
392 | label_i = "z = " + str(solver.Z[i]) + "m"
393 | ax.plot((solver.W - solver.w_0) / 2 / np.pi, IW[i][:], label=label_i)
394 |
395 | ax.set_xlim(frequency_range)
396 | ax.set_xlabel("Frequency [Thz]")
397 | ax.set_ylabel("Normalized Spectral Density")
398 | ax.legend()
399 | return ax
400 |
401 |
402 | def plot_frequency_for_distance_slice_logarithmic(solver, frequency_range=None,
403 | ax=None, z_slice=None,
404 | norm=None):
405 | """Plotting chosen slices of intensity
406 | in logarithmic scale in frequency domain.
407 |
408 | Parameters
409 | ----------
410 | solver : Solution
411 | Model outputs in the form of a ``Solution`` object.
412 | frequency_range : list, (2, )
413 | frequency range. Set [-150, 150] as default.
414 | ax : :class:`~matplotlib.axes.Axes`
415 | :class:`~matplotlib.axes.Axes` instance for plotting
416 | norm : float
417 | Normalization factor for output spectrum. As default maximum of
418 | square absolute of ``solver.AW`` variable is taken.
419 |
420 | Returns
421 | -------
422 | ax : :class:`~matplotlib.axes.Axes`
423 | Used :class:`~matplotlib.axes.Axes` instance.
424 | """
425 |
426 | if ax is None:
427 | ax = plt.gca()
428 |
429 | if frequency_range is None:
430 | frequency_range = [np.min((solver.W - solver.w_0) / 2 / np.pi),
431 | np.max((solver.W - solver.w_0) / 2 / np.pi)]
432 |
433 | if norm is None:
434 | norm = np.max(np.abs(solver.AW)**2)
435 |
436 | lIW = np.fliplr(
437 | 10 * np.log10(np.abs(solver.AW)**2 / norm,
438 | where=(np.abs(solver.AW)**2 > 0)))
439 |
440 | # indices of interest if no z_slice positions were given
441 | if z_slice is None:
442 | iis = [0, -1] # beginning, end
443 |
444 | # indices of interest nearest to given z_slice positions
445 | else:
446 | iis = [np.nonzero(
447 | np.min(np.abs(solver.Z - z)) == np.abs(solver.Z - z)
448 | )[0][0] for z in z_slice]
449 |
450 | for i in iis:
451 | label_i = "z = " + str(solver.Z[i]) + "m"
452 | ax.plot((solver.W - solver.w_0) / 2 / np.pi, lIW[i][:], label=label_i)
453 |
454 | ax.set_xlim(frequency_range)
455 | ax.set_ylim(-40)
456 | ax.set_xlabel("Frequency [Thz]")
457 | ax.set_ylabel("Normalized Spectral Density")
458 | ax.legend()
459 | return ax
460 |
461 |
462 | def plot_delay_vs_distance_logarithmic(solver, time_range=None, ax=None,
463 | norm=None, cmap="magma"):
464 | """Plotting intensity in logarithmic scale in time domain.
465 |
466 | Parameters
467 | ----------
468 | solver : Solution
469 | Model outputs in the form of a ``Solution`` object.
470 | time_range : list, (2, )
471 | Time range. Set [min(``solver.t``), max(``solver.t``)] as default.
472 | ax : :class:`~matplotlib.axes.Axes`
473 | :class:`~matplotlib.axes.Axes` instance for plotting.
474 | norm : float
475 | Normalization factor for output spectrum. As default maximum of
476 | square absolute of ``solver.At`` variable is taken.
477 |
478 | Returns
479 | -------
480 | ax : :class:`~matplotlib.axes.Axes`
481 | Used :class:`~matplotlib.axes.Axes` instance.
482 | """
483 | if ax is None:
484 | ax = plt.gca()
485 |
486 | if time_range is None:
487 | time_range = [np.min(solver.t), np.max(solver.t)]
488 |
489 | if norm is None:
490 | norm = np.max(np.abs(solver.At)**2)
491 |
492 | lIT = 10 * np.log10(np.abs(solver.At)**2 / norm,
493 | where=(np.abs(solver.At)**2 > 0))
494 |
495 | ax.pcolormesh(solver.t, solver.Z, lIT, shading="auto", vmin=-40,
496 | cmap=cmap)
497 | ax.set_xlim(time_range)
498 | ax.set_xlabel("Delay [ps]")
499 | ax.set_ylabel("Distance [m]")
500 | return ax
501 |
502 |
503 | def plot_delay_vs_distance(solver, time_range=None, ax=None, norm=None,
504 | cmap="magma"):
505 | """Plotting normalized intensity in linear scale in time domain.
506 |
507 | Parameters
508 | ----------
509 | solver : Solution
510 | Model outputs in the form of a ``Solution`` object.
511 | time_range : list, (2, )
512 | Time range. Set [min(``solver.t``), max(``solver.t``)] as default.
513 | ax : :class:`~matplotlib.axes.Axes`
514 | :class:`~matplotlib.axes.Axes` instance for plotting.
515 | norm : float
516 | Normalization factor for output spectrum. As default maximum of
517 | square absolute of ``solver.At`` variable is taken.
518 |
519 | Returns
520 | -------
521 | ax : :class:`~matplotlib.axes.Axes`
522 | Used :class:`~matplotlib.axes.Axes` instance.
523 | """
524 | if ax is None:
525 | ax = plt.gca()
526 |
527 | if time_range is None:
528 | time_range = [np.min(solver.t), np.max(solver.t)]
529 |
530 | if norm is None:
531 | norm = np.max(np.abs(solver.At)**2)
532 |
533 | lIT = np.abs(solver.At)**2 / norm
534 |
535 | ax.pcolormesh(solver.t, solver.Z, lIT, shading="auto", vmin=0,
536 | cmap=cmap)
537 | ax.set_xlim(time_range)
538 | ax.set_xlabel("Delay [ps]")
539 | ax.set_ylabel("Distance [m]")
540 | return ax
541 |
542 |
543 | def plot_wavelength_vs_distance(solver, WL_range=None, ax=None,
544 | norm=None, cmap="magma"):
545 | """Plotting results in linear scale in wavelength domain.
546 |
547 | Parameters
548 | ----------
549 | solver : Solution
550 | Model outputs in the form of a ``Solution`` object.
551 | WL_range : list, (2, )
552 | Wavelength range. Set [400, 1350] as default.
553 | ax : :class:`~matplotlib.axes.Axes`
554 | :class:`~matplotlib.axes.Axes` instance for plotting
555 | norm : float
556 | Normalization factor for output spectrum. As default maximum of
557 | square absolute of ``solver.AW`` variable is taken.
558 |
559 | Returns
560 | -------
561 | ax : :class:`~matplotlib.axes.Axes`
562 | Used :class:`~matplotlib.axes.Axes` instance.
563 | """
564 |
565 | if ax is None:
566 | ax = plt.gca()
567 |
568 | if WL_range is None:
569 | WL_range = [np.min(c / (solver.W / 2 / np.pi)),
570 | np.max(c / (solver.W / 2 / np.pi))]
571 |
572 | if norm is None:
573 | norm = np.max(np.abs(solver.AW)**2)
574 |
575 | IW = np.fliplr(
576 | np.abs(solver.AW)**2 / norm)
577 | WL = 2 * np.pi * c / solver.W # wavelength grid
578 | WL_asc = np.flip(WL, ) # ascending order for interpolation
579 | iis = np.logical_and(WL_asc > WL_range[0],
580 | WL_asc < WL_range[1]) # indices of interest
581 |
582 | WL_asc = WL_asc[iis]
583 | IW = IW[:, iis]
584 |
585 | interpolator = interp2d(WL_asc, solver.Z, IW)
586 | newWL = np.linspace(np.min(WL_asc), np.max(WL_asc), IW.shape[1])
587 | toshow = interpolator(newWL, solver.Z)
588 |
589 | ax.imshow(toshow, origin='lower', aspect='auto', cmap=cmap,
590 | extent=[np.min(WL_asc), np.max(WL_asc), 0, np.max(solver.Z)],
591 | vmin=0)
592 | ax.set_xlabel("Wavelength [nm]")
593 | ax.set_ylabel("Distance [m]")
594 | return ax
595 |
596 |
597 | def plot_wavelength_vs_distance_logarithmic(solver, WL_range=None,
598 | ax=None, norm=None, cmap="magma"):
599 | """Plotting results in logarithmic scale in wavelength domain.
600 |
601 | Parameters
602 | ----------
603 | solver : Solution
604 | Model outputs in the form of a ``Solution`` object.
605 | WL_range : list, (2, )
606 | Wavelength range. Set [400, 1350] as default.
607 | ax : :class:`~matplotlib.axes.Axes`
608 | :class:`~matplotlib.axes.Axes` instance for plotting
609 | norm : float
610 | Normalization factor for output spectrum. As default maximum of
611 | square absolute of ``solver.AW`` variable is taken.
612 |
613 | Returns
614 | -------
615 | ax : :class:`~matplotlib.axes.Axes`
616 | Used :class:`~matplotlib.axes.Axes` instance.
617 | """
618 |
619 | if ax is None:
620 | ax = plt.gca()
621 |
622 | if WL_range is None:
623 | WL_range = [np.min(c / (solver.W / 2 / np.pi)),
624 | np.max(c / (solver.W / 2 / np.pi))]
625 |
626 | if norm is None:
627 | norm = np.max(np.abs(solver.AW)**2)
628 |
629 | lIW = np.fliplr(
630 | 10 * np.log10(np.abs(solver.AW)**2 / norm,
631 | where=(np.abs(solver.AW)**2 > 0)))
632 | WL = 2 * np.pi * c / solver.W # wavelength grid
633 | WL_asc = np.flip(WL, ) # ascending order for interpolation
634 | iis = np.logical_and(WL_asc > WL_range[0],
635 | WL_asc < WL_range[1]) # indices of interest
636 |
637 | WL_asc = WL_asc[iis]
638 | lIW = lIW[:, iis]
639 |
640 | interpolator = interp2d(WL_asc, solver.Z, lIW)
641 | newWL = np.linspace(np.min(WL_asc), np.max(WL_asc), lIW.shape[1])
642 | toshow = interpolator(newWL, solver.Z)
643 |
644 | ax.imshow(toshow, origin='lower', aspect='auto', cmap=cmap,
645 | extent=[np.min(WL_asc), np.max(WL_asc), 0, np.max(solver.Z)],
646 | vmin=-40)
647 | ax.set_xlabel("Wavelength [nm]")
648 | ax.set_ylabel("Distance [m]")
649 | return ax
650 |
651 |
652 | def quick_plot(solution):
653 | """Plotting results in time and frequency domain for default value
654 | of parameters.
655 |
656 | Parameters
657 | ----------
658 | solver : Solution
659 | Model outputs in the form of a ``Solution`` object.
660 | """
661 | plt.suptitle('GNLSE solution')
662 |
663 | plt.subplot(1, 2, 1)
664 | plot_wavelength_vs_distance(solution)
665 |
666 | plt.subplot(1, 2, 2)
667 | plot_delay_vs_distance(solution)
668 |
669 | plt.show()
670 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | matplotlib>=2.2.2
2 | numpy>=1.14.3
3 | scipy>=1.1.0
4 | pyfftw>=0.10.0
5 | hdf5storage>=0.1.15
6 | tqdm>=4.11.2
7 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import pkg_resources
2 |
3 | from setuptools import find_packages
4 | from setuptools import setup
5 |
6 | with open('requirements.txt', 'r') as fh:
7 | reqs = [str(requirement)
8 | for requirement in pkg_resources.parse_requirements(fh)]
9 |
10 | with open("README.md", "r") as fh:
11 | long_description = fh.read()
12 |
13 | setup(
14 | name='gnlse',
15 | version='2.0.0',
16 | url='https://github.com/WUST-FOG/gnlse-python',
17 | author='Redman, P., Zatorska, M., Pawlowski, A., Szulc, D., '
18 | 'Majchrowska, S., Tarnowski, K.',
19 | description='gnlse-python is a Python set of scripts for solving '
20 | 'Generalized Nonlinear Schrodringer Equation',
21 | long_description=long_description,
22 | long_description_content_type='text/markdown',
23 | packages=find_packages(),
24 | classifiers=[
25 | 'Programming Language :: Python :: 3',
26 | 'License :: OSI Approved :: MIT License',
27 | 'Operating System :: OS Independent',
28 | ],
29 | python_requires='>=3.7',
30 | install_requires=reqs,
31 | )
32 |
--------------------------------------------------------------------------------
/test-requirements.txt:
--------------------------------------------------------------------------------
1 | autopep8
2 | flake8
3 | doc8
4 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | minversion = 1.6
3 | skipsdist = True
4 | envlist = docs,examples,doc8,pep8,autopep8
5 |
6 | [testenv]
7 | basepython = python3
8 | usedevelop = True
9 | install_command = pip install {opts} {packages}
10 |
11 | [testenv:autopep8]
12 | description = Print autopep8 suggestions.
13 | envdir = {toxworkdir}/linters
14 | deps = -r test-requirements.txt
15 | commands = autopep8 --recursive --aggressive --diff --exit-code .
16 |
17 | [testenv:doc8]
18 | description = Style guide enforcement with doc8.
19 | envdir = {toxworkdir}/linters
20 | deps = -r test-requirements.txt
21 | commands = doc8 {posargs}
22 |
23 | [testenv:docs]
24 | description = Build project documentation.
25 | envdir = {toxworkdir}/sphinx
26 | deps = -r docs/requirements.txt
27 | allowlist_externals = rm
28 | commands =
29 | rm -rf docs/_build
30 | sphinx-build -W -b html docs docs/_build
31 |
32 | [testenv:examples]
33 | description = Run all python scripts from examples directory - physics check.
34 | envdir = {toxworkdir}/build
35 | deps = -r requirements.txt
36 | # Env variable MPLBACKEND=Agg prevents display of windows during tests
37 | setenv = MPLBACKEND=Agg
38 | allowlist_externals = bash
39 | commands = bash -ex -c 'for FILE in examples/*.py; do python $FILE; done'
40 |
41 | [testenv:pep8]
42 | description = Style guide enforcement with flake8.
43 | envdir = {toxworkdir}/linters
44 | deps = -r test-requirements.txt
45 | commands = flake8 {posargs}
46 |
47 | [doc8]
48 | # D000 - invalid rst format
49 | # D002 - no trailing whitespace
50 | # D004 - no carriage returns (use unix newlines)
51 | ignore = D000,D002,D004
52 | ignore-path = .git,.tox,.venv,docs/_build,*.egg-info
53 |
54 | [flake8]
55 | exclude = .git,.tox,.venv,build,docs,*.egg-info
56 |
--------------------------------------------------------------------------------