├── .gitattributes
├── .github
└── workflows
│ ├── build_test.yml
│ ├── pypi_publish.yml
│ └── pypi_test.yml
├── .readthedocs.yaml
├── LICENSE
├── README.md
├── docs
├── Makefile
├── _build
│ ├── doctrees
│ │ ├── environment.pickle
│ │ ├── index.doctree
│ │ ├── modules.doctree
│ │ └── pychi.doctree
│ └── html
│ │ ├── _modules
│ │ ├── index.html
│ │ └── pychi
│ │ │ ├── light.html
│ │ │ ├── materials.html
│ │ │ ├── models.html
│ │ │ └── solvers.html
│ │ ├── _sources
│ │ ├── index.rst.txt
│ │ ├── modules.rst.txt
│ │ └── pychi.rst.txt
│ │ ├── _static
│ │ ├── basic.css
│ │ ├── css
│ │ │ ├── badge_only.css
│ │ │ ├── fonts
│ │ │ │ ├── Roboto-Slab-Bold.woff
│ │ │ │ ├── Roboto-Slab-Bold.woff2
│ │ │ │ ├── Roboto-Slab-Regular.woff
│ │ │ │ ├── Roboto-Slab-Regular.woff2
│ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ ├── fontawesome-webfont.svg
│ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ ├── fontawesome-webfont.woff2
│ │ │ │ ├── lato-bold-italic.woff
│ │ │ │ ├── lato-bold-italic.woff2
│ │ │ │ ├── lato-bold.woff
│ │ │ │ ├── lato-bold.woff2
│ │ │ │ ├── lato-normal-italic.woff
│ │ │ │ ├── lato-normal-italic.woff2
│ │ │ │ ├── lato-normal.woff
│ │ │ │ └── lato-normal.woff2
│ │ │ └── theme.css
│ │ ├── doctools.js
│ │ ├── documentation_options.js
│ │ ├── file.png
│ │ ├── jquery-3.4.1.js
│ │ ├── jquery.js
│ │ ├── js
│ │ │ ├── badge_only.js
│ │ │ ├── html5shiv-printshiv.min.js
│ │ │ ├── html5shiv.min.js
│ │ │ └── theme.js
│ │ ├── language_data.js
│ │ ├── minus.png
│ │ ├── plus.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── underscore-1.3.1.js
│ │ └── underscore.js
│ │ ├── genindex.html
│ │ ├── index.html
│ │ ├── modules.html
│ │ ├── objects.inv
│ │ ├── py-modindex.html
│ │ ├── pychi.html
│ │ ├── search.html
│ │ └── searchindex.js
├── conf.py
├── index.rst
├── make.bat
├── modules.rst
├── pychi.rst
├── readme_link.rst
└── requirements.txt
├── examples
├── Cascaded Nonlinearities
│ ├── cascaded.png
│ ├── effective_index.npy
│ └── pychi_cascaded.py
├── LiNb
│ ├── Experimental_vs_simulation_LiNb.png
│ ├── exp_LiNb.mat
│ ├── n_eff_data_LiNb.npy
│ └── pychi_LiNb_exp_vs_sim.py
├── QPM
│ ├── effective_index.npy
│ └── pychi_QPM.py
├── SPM
│ ├── frequency_propagation.png
│ ├── pychi_spm_validation.py
│ └── time_propagation.png
├── SiN
│ ├── Experimental_vs_simulation_SiN.png
│ ├── exp_SiN.mat
│ ├── n_eff_data_SiN.npy
│ └── pychi_SiN_exp_vs_sim.py
├── effective_index.npy
└── pychi_example.py
├── pyproject.toml
├── requirements.txt
└── src
└── pychi
├── __init__.py
├── light.py
├── materials.py
├── models.py
└── solvers.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/workflows/build_test.yml:
--------------------------------------------------------------------------------
1 | # This workflow is manually triggered and makes a build test of the package.
2 |
3 | name: Build Python Package
4 |
5 | on: workflow_dispatch
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 | deploy:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v3
17 | - name: Set up Python
18 | uses: actions/setup-python@v3
19 | with:
20 | python-version: '3.x'
21 | - name: Install dependencies
22 | run: |
23 | python -m pip install --upgrade pip
24 | python -m pip install --upgrade build
25 | python -m pip install --upgrade twine
26 | - name: Edit Toml
27 | uses: sandstromviktor/toml-editor@2.0.0
28 | with:
29 | file: "pyproject.toml"
30 | key: "project.version"
31 | value: 0.0.0
32 | - name: Build package
33 | run: python -m build
34 |
--------------------------------------------------------------------------------
/.github/workflows/pypi_publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will upload a Python Package using Twine when a release is created
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3 |
4 | name: Upload Python Package
5 |
6 | #on: workflow_dispatch
7 | on:
8 | release:
9 | types: [published]
10 |
11 | permissions:
12 | contents: read
13 |
14 | jobs:
15 | deploy:
16 |
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - uses: actions/checkout@v3
21 | - name: Set up Python
22 | uses: actions/setup-python@v3
23 | with:
24 | python-version: '3.x'
25 | - name: Install dependencies
26 | run: |
27 | python -m pip install --upgrade pip
28 | python -m pip install --upgrade build
29 | python -m pip install --upgrade twine
30 | - name: Get version
31 | id: get_version
32 | run: echo "VERSION=$(echo $GITHUB_REF | cut -d / -f 3)" >> $GITHUB_OUTPUT
33 | - name: Edit Toml
34 | uses: sandstromviktor/toml-editor@2.0.0
35 | with:
36 | file: "pyproject.toml"
37 | key: "project.version"
38 | value: ${{ steps.get_version.outputs.VERSION }}
39 | - name: Build package
40 | run: python -m build
41 | - name: Publish package
42 | run: python -m twine upload dist/* --u __token__ --p ${{ secrets.PYPI_API_TOKEN }}
43 |
--------------------------------------------------------------------------------
/.github/workflows/pypi_test.yml:
--------------------------------------------------------------------------------
1 | # This workflow will upload a Python Package when triggered. Test file for the automatic release action.
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3 |
4 | name: Upload Python Package
5 |
6 | on: workflow_dispatch
7 | #on:
8 | # release:
9 | # types: [published]
10 |
11 | permissions:
12 | contents: read
13 |
14 | jobs:
15 | deploy:
16 |
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - uses: actions/checkout@v3
21 | - name: Set up Python
22 | uses: actions/setup-python@v3
23 | with:
24 | python-version: '3.x'
25 | - name: Install dependencies
26 | run: |
27 | python -m pip install --upgrade pip
28 | python -m pip install --upgrade build
29 | python -m pip install --upgrade twine
30 | - name: Get version
31 | id: get_version
32 | run: echo "VERSION=$(echo $GITHUB_REF | cut -d / -f 3)" >> $GITHUB_OUTPUT
33 | - name: Edit Toml
34 | uses: sandstromviktor/toml-editor@2.0.0
35 | with:
36 | file: "pyproject.toml"
37 | key: "project.version"
38 | #value: ${{ steps.get_version.outputs.VERSION }}
39 | value: 0.0.13
40 | - name: Build package
41 | run: python -m build
42 | - name: Publish package
43 | run: python -m twine upload dist/* --u __token__ --p ${{ secrets.PYPI_API_TOKEN }}
44 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # .readthedocs.yaml
2 | # Read the Docs configuration file
3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4 |
5 | # Required
6 | version: 2
7 |
8 | # Set the version of Python and other tools you might need
9 | build:
10 | os: ubuntu-22.04
11 | tools:
12 | python: "3.11"
13 | # You can also specify other tool versions:
14 | # nodejs: "19"
15 | # rust: "1.64"
16 | # golang: "1.19"
17 |
18 | # Build documentation in the docs/ directory with Sphinx
19 | sphinx:
20 | configuration: docs/conf.py
21 |
22 | # If using Sphinx, optionally build your docs in additional formats such as PDF
23 | # formats:
24 | # - pdf
25 |
26 | # Optionally declare the Python requirements required to build your docs
27 | python:
28 | install:
29 | - requirements: docs/requirements.txt
30 |
31 |
32 | submodules:
33 | include: all
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Ultrafast Microphotonics Group, DESY
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pychi
2 |
3 | A Python package for simulating the propagation of optical pulses in nonlinear materials.
4 |
5 | ## Capabilities
6 |
7 | *pychi* is aimed at simulating the propagation of short pulses in nonlinear media and capturing as much physics as possible. It is based on a unidirectional propagation model, which stays valid even for sub-cycle optical pulses. In particular, this propagation model accounts for
8 | - Full frequency dependence of the effective refractive index
9 | - Quadratic nonlinear interactions (sum- and difference-frequency generation)
10 | - Cubic nonlinear interactions (triple sum-frequency generation, self-phase modulation, conjugated Kerr term)
11 | - Raman scattering
12 | - Self-steepening
13 | - Frequency-dependence of the nonlinear coefficients
14 | - z-dependence of the effective refractive index and nonlinear coefficients (permitting poling to be simulated)
15 |
16 | The package is built to be as user-friendly as possible, providing a relatively high-level interface for the user while still allowing for physically intricate simulation cases. It leverages a custom-made order 5 solver, although more classical solvers (such as the RK4IP) have also been implemented for completeness and versatility.
17 |
18 | ## Installation
19 |
20 | First, make sure pip is up-to-date using
21 | ```
22 | pip install --upgrade pip
23 | ```
24 |
25 | On Windows, install the package using
26 | ```
27 | pip install pychi
28 | ```
29 |
30 | On Mac, one might have to first run
31 | ```
32 | conda install -c conda-forge pyfftw
33 | ```
34 | due to some OS specificities in pyFFTW installation.
35 |
36 | Then, one should be able to install pychi normally using
37 | ```
38 | pip install pychi
39 | ```
40 |
41 |
42 | ## Documentation
43 |
44 | The documentation is available and best viewed under
45 | https://pychi.readthedocs.io/en/latest/
46 | This documentation has been automatically generated using SPHINX, and is still a work in progress. Do not hesitate to contact us for any needed clarifications and examples.
47 |
48 | ## Example
49 |
50 | Here is a typical example of the use of pychi to simulate the propagation of a short optical pulse in a nonlinear waveguide exhibiting both cubic and quadratic nonlinearities.
51 |
52 | ```python
53 | # -*- coding: utf-8 -*-
54 | """
55 | Created on Mon Feb 28 15:31:47 2022
56 | The waveguide/fiber parameters are first provided, and a Waveguide instance
57 | is created. Then, the pulse parameters are used to create a Light object.
58 | A physical model is then chosen, taking into account different nonlinear
59 | interactions based on the user choice. Finally, a solver is instantiated
60 | and computes the propagation of the pulse in the waveguide with the chosen
61 | nonlinear interactions.
62 | @author: voumardt
63 | """
64 | import matplotlib.pyplot as plt
65 | import numpy as np
66 | from scipy.constants import c
67 |
68 | import pychi
69 |
70 |
71 | """
72 | User parameters
73 | """
74 | ### Simulation
75 | t_pts = 2**15
76 |
77 | ### Light
78 | pulse_duration = 100e-15
79 | pulse_wavelength = 1.56e-06
80 | pulse_energy = 1e-9
81 |
82 | ### Waveguide
83 | wg_length = 0.001
84 | wg_chi_2 = 1.1e-12
85 | wg_chi_3 = 3.4e-21
86 | wg_a_eff = 1e-12
87 | wg_freq, wg_n_eff = np.load('effective_index.npy')
88 | # wg_n_eff is the effective dispersion of the waveguide considered, sampled on the grid wg_freq
89 |
90 |
91 | """
92 | Nonlinear propagation
93 | """
94 | ### Prepare waveguide
95 | waveguide = pychi.materials.Waveguide(wg_freq, wg_n_eff, wg_chi_2, wg_chi_3,
96 | wg_a_eff, wg_length, t_pts=t_pts)
97 | # Additional options:
98 | # wg_n_eff can be a 2 dimensional array, with first dimension the wavelength dependence
99 | # and second dimension the z dependence.
100 | #
101 | # chi2 and chi3 can be callables, returning a z dependent value. Alternatively, they
102 | # can be defined as one dimensional arrays describing their z dependence, or
103 | # two dimensional arrays describing their z and frequency dependence. They
104 | # can also be callables of (z, freq).
105 | #
106 | # One can use waveguide.set_gamma(gamma) or waveguide.set_n2(n2) to provide a
107 | # nonlinear coefficient or nonlinear refractive index and overwrite chi3.
108 | #
109 | # Check documentation for more options and details.
110 |
111 |
112 | ### Prepare input pulse
113 | pulse = pychi.light.Sech(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
114 | # Other available pulse shapes:
115 | # pulse = pychi.light.Gaussian(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
116 | # pulse = pychi.light.Cw(waveguide, pulse_average_power, pulse_wavelength)
117 | # pulse = pychi.light.Arbitrary(waveguide, pulse_frequency_axis, pulse_electric_field, pulse_energy)
118 |
119 |
120 | ### Prepare model
121 | model = pychi.models.SpmChi2Chi3(waveguide, pulse)
122 | # Other models available:
123 | # model = pychi.models.Spm(waveguide, pulse)
124 | # model = pychi.models.Chi2(waveguide, pulse)
125 | # model = pychi.models.Chi3(waveguide, pulse)
126 | # model = pychi.models.SpmChi2(waveguide, pulse)
127 | # model = pychi.models.SpmChi3(waveguide, pulse)
128 | # model = pychi.models.Chi2Chi3(waveguide, pulse)
129 |
130 |
131 | ### Prepare solver, solve
132 | solver = pychi.solvers.Solver(model)
133 | solver.solve()
134 |
135 |
136 | """
137 | Plots
138 | """
139 | pulse.plot_propagation()
140 | # Results can also be accessed via pulse.z_save, pulse.freq, pulse.spectrum, pulse.waveform
141 | # The refractive index and GVD can be seen with waveguide.plot_refractive_index()
142 |
143 |
144 | ```
145 |
146 | Typical propagation results using the above script would look as follows:
147 | 
148 |
149 | Check the examples folder for some specific cases and validation against experimental data.
150 |
151 | ## Contacts
152 |
153 | pychi has been developped at DESY by the Ultrafast Microphotonics group. If you use it for publications, please cite the associated paper
154 | https://doi.org/10.1063/5.0135252
155 |
156 | If you have any questions, remarks, contributions, do not hesitate to contact us at:
157 | pychi@desy.de
158 | or here on GitHub.
159 |
--------------------------------------------------------------------------------
/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/_build/doctrees/environment.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/doctrees/environment.pickle
--------------------------------------------------------------------------------
/docs/_build/doctrees/index.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/doctrees/index.doctree
--------------------------------------------------------------------------------
/docs/_build/doctrees/modules.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/doctrees/modules.doctree
--------------------------------------------------------------------------------
/docs/_build/doctrees/pychi.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/doctrees/pychi.doctree
--------------------------------------------------------------------------------
/docs/_build/html/_modules/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Overview: module code — pychi 0.0.1 documentation
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 | - »
55 | - Overview: module code
56 | -
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
All modules for which code is available
65 |
70 |
71 |
72 |
73 |
87 |
88 |
89 |
90 |
91 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/docs/_build/html/_sources/index.rst.txt:
--------------------------------------------------------------------------------
1 | .. pychi documentation master file, created by
2 | sphinx-quickstart on Fri Mar 3 10:39:56 2023.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to pychi's documentation!
7 | =================================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 | :caption: Contents:
12 |
13 | modules
14 |
15 | Indices and tables
16 | ==================
17 |
18 | * :ref:`genindex`
19 | * :ref:`modindex`
20 | * :ref:`search`
21 |
--------------------------------------------------------------------------------
/docs/_build/html/_sources/modules.rst.txt:
--------------------------------------------------------------------------------
1 | pychi package
2 | ===
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | pychi
8 |
--------------------------------------------------------------------------------
/docs/_build/html/_sources/pychi.rst.txt:
--------------------------------------------------------------------------------
1 | pychi package
2 | =============
3 |
4 | pychi.light module
5 | ------------------
6 |
7 | .. automodule:: pychi.light
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
12 | pychi.materials module
13 | ----------------------
14 |
15 | .. automodule:: pychi.materials
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | pychi.models module
21 | -------------------
22 |
23 | .. automodule:: pychi.models
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | pychi.solvers module
29 | --------------------
30 |
31 | .. automodule:: pychi.solvers
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 |
37 | Module contents
38 | ---------------
39 |
40 | .. automodule:: pychi
41 | :members:
42 | :undoc-members:
43 | :show-inheritance:
44 |
--------------------------------------------------------------------------------
/docs/_build/html/_static/basic.css:
--------------------------------------------------------------------------------
1 | /*
2 | * basic.css
3 | * ~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- basic theme.
6 | *
7 | * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /* -- main layout ----------------------------------------------------------- */
13 |
14 | div.clearer {
15 | clear: both;
16 | }
17 |
18 | /* -- relbar ---------------------------------------------------------------- */
19 |
20 | div.related {
21 | width: 100%;
22 | font-size: 90%;
23 | }
24 |
25 | div.related h3 {
26 | display: none;
27 | }
28 |
29 | div.related ul {
30 | margin: 0;
31 | padding: 0 0 0 10px;
32 | list-style: none;
33 | }
34 |
35 | div.related li {
36 | display: inline;
37 | }
38 |
39 | div.related li.right {
40 | float: right;
41 | margin-right: 5px;
42 | }
43 |
44 | /* -- sidebar --------------------------------------------------------------- */
45 |
46 | div.sphinxsidebarwrapper {
47 | padding: 10px 5px 0 10px;
48 | }
49 |
50 | div.sphinxsidebar {
51 | float: left;
52 | width: 230px;
53 | margin-left: -100%;
54 | font-size: 90%;
55 | word-wrap: break-word;
56 | overflow-wrap : break-word;
57 | }
58 |
59 | div.sphinxsidebar ul {
60 | list-style: none;
61 | }
62 |
63 | div.sphinxsidebar ul ul,
64 | div.sphinxsidebar ul.want-points {
65 | margin-left: 20px;
66 | list-style: square;
67 | }
68 |
69 | div.sphinxsidebar ul ul {
70 | margin-top: 0;
71 | margin-bottom: 0;
72 | }
73 |
74 | div.sphinxsidebar form {
75 | margin-top: 10px;
76 | }
77 |
78 | div.sphinxsidebar input {
79 | border: 1px solid #98dbcc;
80 | font-family: sans-serif;
81 | font-size: 1em;
82 | }
83 |
84 | div.sphinxsidebar #searchbox form.search {
85 | overflow: hidden;
86 | }
87 |
88 | div.sphinxsidebar #searchbox input[type="text"] {
89 | float: left;
90 | width: 80%;
91 | padding: 0.25em;
92 | box-sizing: border-box;
93 | }
94 |
95 | div.sphinxsidebar #searchbox input[type="submit"] {
96 | float: left;
97 | width: 20%;
98 | border-left: none;
99 | padding: 0.25em;
100 | box-sizing: border-box;
101 | }
102 |
103 |
104 | img {
105 | border: 0;
106 | max-width: 100%;
107 | }
108 |
109 | /* -- search page ----------------------------------------------------------- */
110 |
111 | ul.search {
112 | margin: 10px 0 0 20px;
113 | padding: 0;
114 | }
115 |
116 | ul.search li {
117 | padding: 5px 0 5px 20px;
118 | background-image: url(file.png);
119 | background-repeat: no-repeat;
120 | background-position: 0 7px;
121 | }
122 |
123 | ul.search li a {
124 | font-weight: bold;
125 | }
126 |
127 | ul.search li div.context {
128 | color: #888;
129 | margin: 2px 0 0 30px;
130 | text-align: left;
131 | }
132 |
133 | ul.keywordmatches li.goodmatch a {
134 | font-weight: bold;
135 | }
136 |
137 | /* -- index page ------------------------------------------------------------ */
138 |
139 | table.contentstable {
140 | width: 90%;
141 | margin-left: auto;
142 | margin-right: auto;
143 | }
144 |
145 | table.contentstable p.biglink {
146 | line-height: 150%;
147 | }
148 |
149 | a.biglink {
150 | font-size: 1.3em;
151 | }
152 |
153 | span.linkdescr {
154 | font-style: italic;
155 | padding-top: 5px;
156 | font-size: 90%;
157 | }
158 |
159 | /* -- general index --------------------------------------------------------- */
160 |
161 | table.indextable {
162 | width: 100%;
163 | }
164 |
165 | table.indextable td {
166 | text-align: left;
167 | vertical-align: top;
168 | }
169 |
170 | table.indextable ul {
171 | margin-top: 0;
172 | margin-bottom: 0;
173 | list-style-type: none;
174 | }
175 |
176 | table.indextable > tbody > tr > td > ul {
177 | padding-left: 0em;
178 | }
179 |
180 | table.indextable tr.pcap {
181 | height: 10px;
182 | }
183 |
184 | table.indextable tr.cap {
185 | margin-top: 10px;
186 | background-color: #f2f2f2;
187 | }
188 |
189 | img.toggler {
190 | margin-right: 3px;
191 | margin-top: 3px;
192 | cursor: pointer;
193 | }
194 |
195 | div.modindex-jumpbox {
196 | border-top: 1px solid #ddd;
197 | border-bottom: 1px solid #ddd;
198 | margin: 1em 0 1em 0;
199 | padding: 0.4em;
200 | }
201 |
202 | div.genindex-jumpbox {
203 | border-top: 1px solid #ddd;
204 | border-bottom: 1px solid #ddd;
205 | margin: 1em 0 1em 0;
206 | padding: 0.4em;
207 | }
208 |
209 | /* -- domain module index --------------------------------------------------- */
210 |
211 | table.modindextable td {
212 | padding: 2px;
213 | border-collapse: collapse;
214 | }
215 |
216 | /* -- general body styles --------------------------------------------------- */
217 |
218 | div.body {
219 | min-width: 450px;
220 | max-width: 800px;
221 | }
222 |
223 | div.body p, div.body dd, div.body li, div.body blockquote {
224 | -moz-hyphens: auto;
225 | -ms-hyphens: auto;
226 | -webkit-hyphens: auto;
227 | hyphens: auto;
228 | }
229 |
230 | a.headerlink {
231 | visibility: hidden;
232 | }
233 |
234 | a.brackets:before,
235 | span.brackets > a:before{
236 | content: "[";
237 | }
238 |
239 | a.brackets:after,
240 | span.brackets > a:after {
241 | content: "]";
242 | }
243 |
244 | h1:hover > a.headerlink,
245 | h2:hover > a.headerlink,
246 | h3:hover > a.headerlink,
247 | h4:hover > a.headerlink,
248 | h5:hover > a.headerlink,
249 | h6:hover > a.headerlink,
250 | dt:hover > a.headerlink,
251 | caption:hover > a.headerlink,
252 | p.caption:hover > a.headerlink,
253 | div.code-block-caption:hover > a.headerlink {
254 | visibility: visible;
255 | }
256 |
257 | div.body p.caption {
258 | text-align: inherit;
259 | }
260 |
261 | div.body td {
262 | text-align: left;
263 | }
264 |
265 | .first {
266 | margin-top: 0 !important;
267 | }
268 |
269 | p.rubric {
270 | margin-top: 30px;
271 | font-weight: bold;
272 | }
273 |
274 | img.align-left, .figure.align-left, object.align-left {
275 | clear: left;
276 | float: left;
277 | margin-right: 1em;
278 | }
279 |
280 | img.align-right, .figure.align-right, object.align-right {
281 | clear: right;
282 | float: right;
283 | margin-left: 1em;
284 | }
285 |
286 | img.align-center, .figure.align-center, object.align-center {
287 | display: block;
288 | margin-left: auto;
289 | margin-right: auto;
290 | }
291 |
292 | img.align-default, .figure.align-default {
293 | display: block;
294 | margin-left: auto;
295 | margin-right: auto;
296 | }
297 |
298 | .align-left {
299 | text-align: left;
300 | }
301 |
302 | .align-center {
303 | text-align: center;
304 | }
305 |
306 | .align-default {
307 | text-align: center;
308 | }
309 |
310 | .align-right {
311 | text-align: right;
312 | }
313 |
314 | /* -- sidebars -------------------------------------------------------------- */
315 |
316 | div.sidebar {
317 | margin: 0 0 0.5em 1em;
318 | border: 1px solid #ddb;
319 | padding: 7px 7px 0 7px;
320 | background-color: #ffe;
321 | width: 40%;
322 | float: right;
323 | }
324 |
325 | p.sidebar-title {
326 | font-weight: bold;
327 | }
328 |
329 | /* -- topics ---------------------------------------------------------------- */
330 |
331 | div.topic {
332 | border: 1px solid #ccc;
333 | padding: 7px 7px 0 7px;
334 | margin: 10px 0 10px 0;
335 | }
336 |
337 | p.topic-title {
338 | font-size: 1.1em;
339 | font-weight: bold;
340 | margin-top: 10px;
341 | }
342 |
343 | /* -- admonitions ----------------------------------------------------------- */
344 |
345 | div.admonition {
346 | margin-top: 10px;
347 | margin-bottom: 10px;
348 | padding: 7px;
349 | }
350 |
351 | div.admonition dt {
352 | font-weight: bold;
353 | }
354 |
355 | div.admonition dl {
356 | margin-bottom: 0;
357 | }
358 |
359 | p.admonition-title {
360 | margin: 0px 10px 5px 0px;
361 | font-weight: bold;
362 | }
363 |
364 | div.body p.centered {
365 | text-align: center;
366 | margin-top: 25px;
367 | }
368 |
369 | /* -- tables ---------------------------------------------------------------- */
370 |
371 | table.docutils {
372 | border: 0;
373 | border-collapse: collapse;
374 | }
375 |
376 | table.align-center {
377 | margin-left: auto;
378 | margin-right: auto;
379 | }
380 |
381 | table.align-default {
382 | margin-left: auto;
383 | margin-right: auto;
384 | }
385 |
386 | table caption span.caption-number {
387 | font-style: italic;
388 | }
389 |
390 | table caption span.caption-text {
391 | }
392 |
393 | table.docutils td, table.docutils th {
394 | padding: 1px 8px 1px 5px;
395 | border-top: 0;
396 | border-left: 0;
397 | border-right: 0;
398 | border-bottom: 1px solid #aaa;
399 | }
400 |
401 | table.footnote td, table.footnote th {
402 | border: 0 !important;
403 | }
404 |
405 | th {
406 | text-align: left;
407 | padding-right: 5px;
408 | }
409 |
410 | table.citation {
411 | border-left: solid 1px gray;
412 | margin-left: 1px;
413 | }
414 |
415 | table.citation td {
416 | border-bottom: none;
417 | }
418 |
419 | th > p:first-child,
420 | td > p:first-child {
421 | margin-top: 0px;
422 | }
423 |
424 | th > p:last-child,
425 | td > p:last-child {
426 | margin-bottom: 0px;
427 | }
428 |
429 | /* -- figures --------------------------------------------------------------- */
430 |
431 | div.figure {
432 | margin: 0.5em;
433 | padding: 0.5em;
434 | }
435 |
436 | div.figure p.caption {
437 | padding: 0.3em;
438 | }
439 |
440 | div.figure p.caption span.caption-number {
441 | font-style: italic;
442 | }
443 |
444 | div.figure p.caption span.caption-text {
445 | }
446 |
447 | /* -- field list styles ----------------------------------------------------- */
448 |
449 | table.field-list td, table.field-list th {
450 | border: 0 !important;
451 | }
452 |
453 | .field-list ul {
454 | margin: 0;
455 | padding-left: 1em;
456 | }
457 |
458 | .field-list p {
459 | margin: 0;
460 | }
461 |
462 | .field-name {
463 | -moz-hyphens: manual;
464 | -ms-hyphens: manual;
465 | -webkit-hyphens: manual;
466 | hyphens: manual;
467 | }
468 |
469 | /* -- hlist styles ---------------------------------------------------------- */
470 |
471 | table.hlist td {
472 | vertical-align: top;
473 | }
474 |
475 |
476 | /* -- other body styles ----------------------------------------------------- */
477 |
478 | ol.arabic {
479 | list-style: decimal;
480 | }
481 |
482 | ol.loweralpha {
483 | list-style: lower-alpha;
484 | }
485 |
486 | ol.upperalpha {
487 | list-style: upper-alpha;
488 | }
489 |
490 | ol.lowerroman {
491 | list-style: lower-roman;
492 | }
493 |
494 | ol.upperroman {
495 | list-style: upper-roman;
496 | }
497 |
498 | li > p:first-child {
499 | margin-top: 0px;
500 | }
501 |
502 | li > p:last-child {
503 | margin-bottom: 0px;
504 | }
505 |
506 | dl.footnote > dt,
507 | dl.citation > dt {
508 | float: left;
509 | }
510 |
511 | dl.footnote > dd,
512 | dl.citation > dd {
513 | margin-bottom: 0em;
514 | }
515 |
516 | dl.footnote > dd:after,
517 | dl.citation > dd:after {
518 | content: "";
519 | clear: both;
520 | }
521 |
522 | dl.field-list {
523 | display: grid;
524 | grid-template-columns: fit-content(30%) auto;
525 | }
526 |
527 | dl.field-list > dt {
528 | font-weight: bold;
529 | word-break: break-word;
530 | padding-left: 0.5em;
531 | padding-right: 5px;
532 | }
533 |
534 | dl.field-list > dt:after {
535 | content: ":";
536 | }
537 |
538 | dl.field-list > dd {
539 | padding-left: 0.5em;
540 | margin-top: 0em;
541 | margin-left: 0em;
542 | margin-bottom: 0em;
543 | }
544 |
545 | dl {
546 | margin-bottom: 15px;
547 | }
548 |
549 | dd > p:first-child {
550 | margin-top: 0px;
551 | }
552 |
553 | dd ul, dd table {
554 | margin-bottom: 10px;
555 | }
556 |
557 | dd {
558 | margin-top: 3px;
559 | margin-bottom: 10px;
560 | margin-left: 30px;
561 | }
562 |
563 | dt:target, span.highlighted {
564 | background-color: #fbe54e;
565 | }
566 |
567 | rect.highlighted {
568 | fill: #fbe54e;
569 | }
570 |
571 | dl.glossary dt {
572 | font-weight: bold;
573 | font-size: 1.1em;
574 | }
575 |
576 | .optional {
577 | font-size: 1.3em;
578 | }
579 |
580 | .sig-paren {
581 | font-size: larger;
582 | }
583 |
584 | .versionmodified {
585 | font-style: italic;
586 | }
587 |
588 | .system-message {
589 | background-color: #fda;
590 | padding: 5px;
591 | border: 3px solid red;
592 | }
593 |
594 | .footnote:target {
595 | background-color: #ffa;
596 | }
597 |
598 | .line-block {
599 | display: block;
600 | margin-top: 1em;
601 | margin-bottom: 1em;
602 | }
603 |
604 | .line-block .line-block {
605 | margin-top: 0;
606 | margin-bottom: 0;
607 | margin-left: 1.5em;
608 | }
609 |
610 | .guilabel, .menuselection {
611 | font-family: sans-serif;
612 | }
613 |
614 | .accelerator {
615 | text-decoration: underline;
616 | }
617 |
618 | .classifier {
619 | font-style: oblique;
620 | }
621 |
622 | .classifier:before {
623 | font-style: normal;
624 | margin: 0.5em;
625 | content: ":";
626 | }
627 |
628 | abbr, acronym {
629 | border-bottom: dotted 1px;
630 | cursor: help;
631 | }
632 |
633 | /* -- code displays --------------------------------------------------------- */
634 |
635 | pre {
636 | overflow: auto;
637 | overflow-y: hidden; /* fixes display issues on Chrome browsers */
638 | }
639 |
640 | span.pre {
641 | -moz-hyphens: none;
642 | -ms-hyphens: none;
643 | -webkit-hyphens: none;
644 | hyphens: none;
645 | }
646 |
647 | td.linenos pre {
648 | padding: 5px 0px;
649 | border: 0;
650 | background-color: transparent;
651 | color: #aaa;
652 | }
653 |
654 | table.highlighttable {
655 | margin-left: 0.5em;
656 | }
657 |
658 | table.highlighttable td {
659 | padding: 0 0.5em 0 0.5em;
660 | }
661 |
662 | div.code-block-caption {
663 | padding: 2px 5px;
664 | font-size: small;
665 | }
666 |
667 | div.code-block-caption code {
668 | background-color: transparent;
669 | }
670 |
671 | div.code-block-caption + div > div.highlight > pre {
672 | margin-top: 0;
673 | }
674 |
675 | div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */
676 | user-select: none;
677 | }
678 |
679 | div.code-block-caption span.caption-number {
680 | padding: 0.1em 0.3em;
681 | font-style: italic;
682 | }
683 |
684 | div.code-block-caption span.caption-text {
685 | }
686 |
687 | div.literal-block-wrapper {
688 | padding: 1em 1em 0;
689 | }
690 |
691 | div.literal-block-wrapper div.highlight {
692 | margin: 0;
693 | }
694 |
695 | code.descname {
696 | background-color: transparent;
697 | font-weight: bold;
698 | font-size: 1.2em;
699 | }
700 |
701 | code.descclassname {
702 | background-color: transparent;
703 | }
704 |
705 | code.xref, a code {
706 | background-color: transparent;
707 | font-weight: bold;
708 | }
709 |
710 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
711 | background-color: transparent;
712 | }
713 |
714 | .viewcode-link {
715 | float: right;
716 | }
717 |
718 | .viewcode-back {
719 | float: right;
720 | font-family: sans-serif;
721 | }
722 |
723 | div.viewcode-block:target {
724 | margin: -1px -10px;
725 | padding: 0 10px;
726 | }
727 |
728 | /* -- math display ---------------------------------------------------------- */
729 |
730 | img.math {
731 | vertical-align: middle;
732 | }
733 |
734 | div.body div.math p {
735 | text-align: center;
736 | }
737 |
738 | span.eqno {
739 | float: right;
740 | }
741 |
742 | span.eqno a.headerlink {
743 | position: relative;
744 | left: 0px;
745 | z-index: 1;
746 | }
747 |
748 | div.math:hover a.headerlink {
749 | visibility: visible;
750 | }
751 |
752 | /* -- printout stylesheet --------------------------------------------------- */
753 |
754 | @media print {
755 | div.document,
756 | div.documentwrapper,
757 | div.bodywrapper {
758 | margin: 0 !important;
759 | width: 100%;
760 | }
761 |
762 | div.sphinxsidebar,
763 | div.related,
764 | div.footer,
765 | #top-link {
766 | display: none;
767 | }
768 | }
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/badge_only.css:
--------------------------------------------------------------------------------
1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/lato-bold-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/lato-bold-italic.woff
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/lato-bold.woff
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/lato-bold.woff2
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/lato-normal-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/lato-normal-italic.woff
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/lato-normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/lato-normal.woff
--------------------------------------------------------------------------------
/docs/_build/html/_static/css/fonts/lato-normal.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/css/fonts/lato-normal.woff2
--------------------------------------------------------------------------------
/docs/_build/html/_static/doctools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * doctools.js
3 | * ~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for all documentation.
6 | *
7 | * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /**
13 | * select a different prefix for underscore
14 | */
15 | $u = _.noConflict();
16 |
17 | /**
18 | * make the code below compatible with browsers without
19 | * an installed firebug like debugger
20 | if (!window.console || !console.firebug) {
21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
23 | "profile", "profileEnd"];
24 | window.console = {};
25 | for (var i = 0; i < names.length; ++i)
26 | window.console[names[i]] = function() {};
27 | }
28 | */
29 |
30 | /**
31 | * small helper function to urldecode strings
32 | */
33 | jQuery.urldecode = function(x) {
34 | return decodeURIComponent(x).replace(/\+/g, ' ');
35 | };
36 |
37 | /**
38 | * small helper function to urlencode strings
39 | */
40 | jQuery.urlencode = encodeURIComponent;
41 |
42 | /**
43 | * This function returns the parsed url parameters of the
44 | * current request. Multiple values per key are supported,
45 | * it will always return arrays of strings for the value parts.
46 | */
47 | jQuery.getQueryParameters = function(s) {
48 | if (typeof s === 'undefined')
49 | s = document.location.search;
50 | var parts = s.substr(s.indexOf('?') + 1).split('&');
51 | var result = {};
52 | for (var i = 0; i < parts.length; i++) {
53 | var tmp = parts[i].split('=', 2);
54 | var key = jQuery.urldecode(tmp[0]);
55 | var value = jQuery.urldecode(tmp[1]);
56 | if (key in result)
57 | result[key].push(value);
58 | else
59 | result[key] = [value];
60 | }
61 | return result;
62 | };
63 |
64 | /**
65 | * highlight a given string on a jquery object by wrapping it in
66 | * span elements with the given class name.
67 | */
68 | jQuery.fn.highlightText = function(text, className) {
69 | function highlight(node, addItems) {
70 | if (node.nodeType === 3) {
71 | var val = node.nodeValue;
72 | var pos = val.toLowerCase().indexOf(text);
73 | if (pos >= 0 &&
74 | !jQuery(node.parentNode).hasClass(className) &&
75 | !jQuery(node.parentNode).hasClass("nohighlight")) {
76 | var span;
77 | var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
78 | if (isInSVG) {
79 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
80 | } else {
81 | span = document.createElement("span");
82 | span.className = className;
83 | }
84 | span.appendChild(document.createTextNode(val.substr(pos, text.length)));
85 | node.parentNode.insertBefore(span, node.parentNode.insertBefore(
86 | document.createTextNode(val.substr(pos + text.length)),
87 | node.nextSibling));
88 | node.nodeValue = val.substr(0, pos);
89 | if (isInSVG) {
90 | var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
91 | var bbox = node.parentElement.getBBox();
92 | rect.x.baseVal.value = bbox.x;
93 | rect.y.baseVal.value = bbox.y;
94 | rect.width.baseVal.value = bbox.width;
95 | rect.height.baseVal.value = bbox.height;
96 | rect.setAttribute('class', className);
97 | addItems.push({
98 | "parent": node.parentNode,
99 | "target": rect});
100 | }
101 | }
102 | }
103 | else if (!jQuery(node).is("button, select, textarea")) {
104 | jQuery.each(node.childNodes, function() {
105 | highlight(this, addItems);
106 | });
107 | }
108 | }
109 | var addItems = [];
110 | var result = this.each(function() {
111 | highlight(this, addItems);
112 | });
113 | for (var i = 0; i < addItems.length; ++i) {
114 | jQuery(addItems[i].parent).before(addItems[i].target);
115 | }
116 | return result;
117 | };
118 |
119 | /*
120 | * backward compatibility for jQuery.browser
121 | * This will be supported until firefox bug is fixed.
122 | */
123 | if (!jQuery.browser) {
124 | jQuery.uaMatch = function(ua) {
125 | ua = ua.toLowerCase();
126 |
127 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
128 | /(webkit)[ \/]([\w.]+)/.exec(ua) ||
129 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
130 | /(msie) ([\w.]+)/.exec(ua) ||
131 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
132 | [];
133 |
134 | return {
135 | browser: match[ 1 ] || "",
136 | version: match[ 2 ] || "0"
137 | };
138 | };
139 | jQuery.browser = {};
140 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
141 | }
142 |
143 | /**
144 | * Small JavaScript module for the documentation.
145 | */
146 | var Documentation = {
147 |
148 | init : function() {
149 | this.fixFirefoxAnchorBug();
150 | this.highlightSearchWords();
151 | this.initIndexTable();
152 | if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) {
153 | this.initOnKeyListeners();
154 | }
155 | },
156 |
157 | /**
158 | * i18n support
159 | */
160 | TRANSLATIONS : {},
161 | PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },
162 | LOCALE : 'unknown',
163 |
164 | // gettext and ngettext don't access this so that the functions
165 | // can safely bound to a different name (_ = Documentation.gettext)
166 | gettext : function(string) {
167 | var translated = Documentation.TRANSLATIONS[string];
168 | if (typeof translated === 'undefined')
169 | return string;
170 | return (typeof translated === 'string') ? translated : translated[0];
171 | },
172 |
173 | ngettext : function(singular, plural, n) {
174 | var translated = Documentation.TRANSLATIONS[singular];
175 | if (typeof translated === 'undefined')
176 | return (n == 1) ? singular : plural;
177 | return translated[Documentation.PLURALEXPR(n)];
178 | },
179 |
180 | addTranslations : function(catalog) {
181 | for (var key in catalog.messages)
182 | this.TRANSLATIONS[key] = catalog.messages[key];
183 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
184 | this.LOCALE = catalog.locale;
185 | },
186 |
187 | /**
188 | * add context elements like header anchor links
189 | */
190 | addContextElements : function() {
191 | $('div[id] > :header:first').each(function() {
192 | $('').
193 | attr('href', '#' + this.id).
194 | attr('title', _('Permalink to this headline')).
195 | appendTo(this);
196 | });
197 | $('dt[id]').each(function() {
198 | $('').
199 | attr('href', '#' + this.id).
200 | attr('title', _('Permalink to this definition')).
201 | appendTo(this);
202 | });
203 | },
204 |
205 | /**
206 | * workaround a firefox stupidity
207 | * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
208 | */
209 | fixFirefoxAnchorBug : function() {
210 | if (document.location.hash && $.browser.mozilla)
211 | window.setTimeout(function() {
212 | document.location.href += '';
213 | }, 10);
214 | },
215 |
216 | /**
217 | * highlight the search words provided in the url in the text
218 | */
219 | highlightSearchWords : function() {
220 | var params = $.getQueryParameters();
221 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
222 | if (terms.length) {
223 | var body = $('div.body');
224 | if (!body.length) {
225 | body = $('body');
226 | }
227 | window.setTimeout(function() {
228 | $.each(terms, function() {
229 | body.highlightText(this.toLowerCase(), 'highlighted');
230 | });
231 | }, 10);
232 | $('' + _('Hide Search Matches') + '
')
234 | .appendTo($('#searchbox'));
235 | }
236 | },
237 |
238 | /**
239 | * init the domain index toggle buttons
240 | */
241 | initIndexTable : function() {
242 | var togglers = $('img.toggler').click(function() {
243 | var src = $(this).attr('src');
244 | var idnum = $(this).attr('id').substr(7);
245 | $('tr.cg-' + idnum).toggle();
246 | if (src.substr(-9) === 'minus.png')
247 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
248 | else
249 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
250 | }).css('display', '');
251 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
252 | togglers.click();
253 | }
254 | },
255 |
256 | /**
257 | * helper function to hide the search marks again
258 | */
259 | hideSearchWords : function() {
260 | $('#searchbox .highlight-link').fadeOut(300);
261 | $('span.highlighted').removeClass('highlighted');
262 | },
263 |
264 | /**
265 | * make the url absolute
266 | */
267 | makeURL : function(relativeURL) {
268 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
269 | },
270 |
271 | /**
272 | * get the current relative url
273 | */
274 | getCurrentURL : function() {
275 | var path = document.location.pathname;
276 | var parts = path.split(/\//);
277 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
278 | if (this === '..')
279 | parts.pop();
280 | });
281 | var url = parts.join('/');
282 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
283 | },
284 |
285 | initOnKeyListeners: function() {
286 | $(document).keydown(function(event) {
287 | var activeElementType = document.activeElement.tagName;
288 | // don't navigate when in search box or textarea
289 | if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT'
290 | && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
291 | switch (event.keyCode) {
292 | case 37: // left
293 | var prevHref = $('link[rel="prev"]').prop('href');
294 | if (prevHref) {
295 | window.location.href = prevHref;
296 | return false;
297 | }
298 | case 39: // right
299 | var nextHref = $('link[rel="next"]').prop('href');
300 | if (nextHref) {
301 | window.location.href = nextHref;
302 | return false;
303 | }
304 | }
305 | }
306 | });
307 | }
308 | };
309 |
310 | // quick alias for translations
311 | _ = Documentation.gettext;
312 |
313 | $(document).ready(function() {
314 | Documentation.init();
315 | });
316 |
--------------------------------------------------------------------------------
/docs/_build/html/_static/documentation_options.js:
--------------------------------------------------------------------------------
1 | var DOCUMENTATION_OPTIONS = {
2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 | VERSION: '0.0.1',
4 | LANGUAGE: 'None',
5 | COLLAPSE_INDEX: false,
6 | BUILDER: 'html',
7 | FILE_SUFFIX: '.html',
8 | HAS_SOURCE: true,
9 | SOURCELINK_SUFFIX: '.txt',
10 | NAVIGATION_WITH_KEYS: false
11 | };
--------------------------------------------------------------------------------
/docs/_build/html/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/file.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/js/badge_only.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
--------------------------------------------------------------------------------
/docs/_build/html/_static/js/html5shiv-printshiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/docs/_build/html/_static/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/docs/_build/html/_static/js/theme.js:
--------------------------------------------------------------------------------
1 | !function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap(""),n("table.docutils.footnote").wrap(""),n("table.docutils.citation").wrap(""),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0
62 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
63 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
64 | var s_v = "^(" + C + ")?" + v; // vowel in stem
65 |
66 | this.stemWord = function (w) {
67 | var stem;
68 | var suffix;
69 | var firstch;
70 | var origword = w;
71 |
72 | if (w.length < 3)
73 | return w;
74 |
75 | var re;
76 | var re2;
77 | var re3;
78 | var re4;
79 |
80 | firstch = w.substr(0,1);
81 | if (firstch == "y")
82 | w = firstch.toUpperCase() + w.substr(1);
83 |
84 | // Step 1a
85 | re = /^(.+?)(ss|i)es$/;
86 | re2 = /^(.+?)([^s])s$/;
87 |
88 | if (re.test(w))
89 | w = w.replace(re,"$1$2");
90 | else if (re2.test(w))
91 | w = w.replace(re2,"$1$2");
92 |
93 | // Step 1b
94 | re = /^(.+?)eed$/;
95 | re2 = /^(.+?)(ed|ing)$/;
96 | if (re.test(w)) {
97 | var fp = re.exec(w);
98 | re = new RegExp(mgr0);
99 | if (re.test(fp[1])) {
100 | re = /.$/;
101 | w = w.replace(re,"");
102 | }
103 | }
104 | else if (re2.test(w)) {
105 | var fp = re2.exec(w);
106 | stem = fp[1];
107 | re2 = new RegExp(s_v);
108 | if (re2.test(stem)) {
109 | w = stem;
110 | re2 = /(at|bl|iz)$/;
111 | re3 = new RegExp("([^aeiouylsz])\\1$");
112 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
113 | if (re2.test(w))
114 | w = w + "e";
115 | else if (re3.test(w)) {
116 | re = /.$/;
117 | w = w.replace(re,"");
118 | }
119 | else if (re4.test(w))
120 | w = w + "e";
121 | }
122 | }
123 |
124 | // Step 1c
125 | re = /^(.+?)y$/;
126 | if (re.test(w)) {
127 | var fp = re.exec(w);
128 | stem = fp[1];
129 | re = new RegExp(s_v);
130 | if (re.test(stem))
131 | w = stem + "i";
132 | }
133 |
134 | // Step 2
135 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
136 | if (re.test(w)) {
137 | var fp = re.exec(w);
138 | stem = fp[1];
139 | suffix = fp[2];
140 | re = new RegExp(mgr0);
141 | if (re.test(stem))
142 | w = stem + step2list[suffix];
143 | }
144 |
145 | // Step 3
146 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
147 | if (re.test(w)) {
148 | var fp = re.exec(w);
149 | stem = fp[1];
150 | suffix = fp[2];
151 | re = new RegExp(mgr0);
152 | if (re.test(stem))
153 | w = stem + step3list[suffix];
154 | }
155 |
156 | // Step 4
157 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
158 | re2 = /^(.+?)(s|t)(ion)$/;
159 | if (re.test(w)) {
160 | var fp = re.exec(w);
161 | stem = fp[1];
162 | re = new RegExp(mgr1);
163 | if (re.test(stem))
164 | w = stem;
165 | }
166 | else if (re2.test(w)) {
167 | var fp = re2.exec(w);
168 | stem = fp[1] + fp[2];
169 | re2 = new RegExp(mgr1);
170 | if (re2.test(stem))
171 | w = stem;
172 | }
173 |
174 | // Step 5
175 | re = /^(.+?)e$/;
176 | if (re.test(w)) {
177 | var fp = re.exec(w);
178 | stem = fp[1];
179 | re = new RegExp(mgr1);
180 | re2 = new RegExp(meq1);
181 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
182 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
183 | w = stem;
184 | }
185 | re = /ll$/;
186 | re2 = new RegExp(mgr1);
187 | if (re.test(w) && re2.test(w)) {
188 | re = /.$/;
189 | w = w.replace(re,"");
190 | }
191 |
192 | // and turn initial Y back to y
193 | if (firstch == "y")
194 | w = firstch.toLowerCase() + w.substr(1);
195 | return w;
196 | }
197 | }
198 |
199 |
200 |
201 |
202 |
203 | var splitChars = (function() {
204 | var result = {};
205 | var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
206 | 1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
207 | 2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
208 | 2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
209 | 3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
210 | 3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
211 | 4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
212 | 8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
213 | 11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
214 | 43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
215 | var i, j, start, end;
216 | for (i = 0; i < singles.length; i++) {
217 | result[singles[i]] = true;
218 | }
219 | var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
220 | [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
221 | [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
222 | [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
223 | [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
224 | [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
225 | [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
226 | [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
227 | [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
228 | [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
229 | [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
230 | [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
231 | [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
232 | [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
233 | [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
234 | [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
235 | [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
236 | [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
237 | [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
238 | [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
239 | [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
240 | [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
241 | [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
242 | [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
243 | [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
244 | [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
245 | [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
246 | [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
247 | [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
248 | [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
249 | [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
250 | [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
251 | [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
252 | [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
253 | [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
254 | [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
255 | [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
256 | [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
257 | [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
258 | [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
259 | [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
260 | [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
261 | [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
262 | [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
263 | [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
264 | [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
265 | [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
266 | [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
267 | [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
268 | for (i = 0; i < ranges.length; i++) {
269 | start = ranges[i][0];
270 | end = ranges[i][1];
271 | for (j = start; j <= end; j++) {
272 | result[j] = true;
273 | }
274 | }
275 | return result;
276 | })();
277 |
278 | function splitQuery(query) {
279 | var result = [];
280 | var start = -1;
281 | for (var i = 0; i < query.length; i++) {
282 | if (splitChars[query.charCodeAt(i)]) {
283 | if (start !== -1) {
284 | result.push(query.slice(start, i));
285 | start = -1;
286 | }
287 | } else if (start === -1) {
288 | start = i;
289 | }
290 | }
291 | if (start !== -1) {
292 | result.push(query.slice(start));
293 | }
294 | return result;
295 | }
296 |
297 |
298 |
--------------------------------------------------------------------------------
/docs/_build/html/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/minus.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/_static/plus.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/pygments.css:
--------------------------------------------------------------------------------
1 | pre { line-height: 125%; }
2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
6 | .highlight .hll { background-color: #ffffcc }
7 | .highlight { background: #f8f8f8; }
8 | .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
9 | .highlight .err { border: 1px solid #FF0000 } /* Error */
10 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */
11 | .highlight .o { color: #666666 } /* Operator */
12 | .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
13 | .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
14 | .highlight .cp { color: #9C6500 } /* Comment.Preproc */
15 | .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
16 | .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
17 | .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
18 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
19 | .highlight .ge { font-style: italic } /* Generic.Emph */
20 | .highlight .gr { color: #E40000 } /* Generic.Error */
21 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
22 | .highlight .gi { color: #008400 } /* Generic.Inserted */
23 | .highlight .go { color: #717171 } /* Generic.Output */
24 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
25 | .highlight .gs { font-weight: bold } /* Generic.Strong */
26 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
27 | .highlight .gt { color: #0044DD } /* Generic.Traceback */
28 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
29 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
30 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
31 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */
32 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
33 | .highlight .kt { color: #B00040 } /* Keyword.Type */
34 | .highlight .m { color: #666666 } /* Literal.Number */
35 | .highlight .s { color: #BA2121 } /* Literal.String */
36 | .highlight .na { color: #687822 } /* Name.Attribute */
37 | .highlight .nb { color: #008000 } /* Name.Builtin */
38 | .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
39 | .highlight .no { color: #880000 } /* Name.Constant */
40 | .highlight .nd { color: #AA22FF } /* Name.Decorator */
41 | .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
42 | .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
43 | .highlight .nf { color: #0000FF } /* Name.Function */
44 | .highlight .nl { color: #767600 } /* Name.Label */
45 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
46 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
47 | .highlight .nv { color: #19177C } /* Name.Variable */
48 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
49 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
50 | .highlight .mb { color: #666666 } /* Literal.Number.Bin */
51 | .highlight .mf { color: #666666 } /* Literal.Number.Float */
52 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */
53 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */
54 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */
55 | .highlight .sa { color: #BA2121 } /* Literal.String.Affix */
56 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
57 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */
58 | .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
59 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
60 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */
61 | .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
62 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
63 | .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
64 | .highlight .sx { color: #008000 } /* Literal.String.Other */
65 | .highlight .sr { color: #A45A77 } /* Literal.String.Regex */
66 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */
67 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */
68 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
69 | .highlight .fm { color: #0000FF } /* Name.Function.Magic */
70 | .highlight .vc { color: #19177C } /* Name.Variable.Class */
71 | .highlight .vg { color: #19177C } /* Name.Variable.Global */
72 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */
73 | .highlight .vm { color: #19177C } /* Name.Variable.Magic */
74 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/docs/_build/html/_static/searchtools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * searchtools.js
3 | * ~~~~~~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for the full-text search.
6 | *
7 | * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | if (!Scorer) {
13 | /**
14 | * Simple result scoring code.
15 | */
16 | var Scorer = {
17 | // Implement the following function to further tweak the score for each result
18 | // The function takes a result array [filename, title, anchor, descr, score]
19 | // and returns the new score.
20 | /*
21 | score: function(result) {
22 | return result[4];
23 | },
24 | */
25 |
26 | // query matches the full name of an object
27 | objNameMatch: 11,
28 | // or matches in the last dotted part of the object name
29 | objPartialMatch: 6,
30 | // Additive scores depending on the priority of the object
31 | objPrio: {0: 15, // used to be importantResults
32 | 1: 5, // used to be objectResults
33 | 2: -5}, // used to be unimportantResults
34 | // Used when the priority is not in the mapping.
35 | objPrioDefault: 0,
36 |
37 | // query found in title
38 | title: 15,
39 | partialTitle: 7,
40 | // query found in terms
41 | term: 5,
42 | partialTerm: 2
43 | };
44 | }
45 |
46 | if (!splitQuery) {
47 | function splitQuery(query) {
48 | return query.split(/\s+/);
49 | }
50 | }
51 |
52 | /**
53 | * Search Module
54 | */
55 | var Search = {
56 |
57 | _index : null,
58 | _queued_query : null,
59 | _pulse_status : -1,
60 |
61 | htmlToText : function(htmlString) {
62 | var htmlElement = document.createElement('span');
63 | htmlElement.innerHTML = htmlString;
64 | $(htmlElement).find('.headerlink').remove();
65 | docContent = $(htmlElement).find('[role=main]')[0];
66 | return docContent.textContent || docContent.innerText;
67 | },
68 |
69 | init : function() {
70 | var params = $.getQueryParameters();
71 | if (params.q) {
72 | var query = params.q[0];
73 | $('input[name="q"]')[0].value = query;
74 | this.performSearch(query);
75 | }
76 | },
77 |
78 | loadIndex : function(url) {
79 | $.ajax({type: "GET", url: url, data: null,
80 | dataType: "script", cache: true,
81 | complete: function(jqxhr, textstatus) {
82 | if (textstatus != "success") {
83 | document.getElementById("searchindexloader").src = url;
84 | }
85 | }});
86 | },
87 |
88 | setIndex : function(index) {
89 | var q;
90 | this._index = index;
91 | if ((q = this._queued_query) !== null) {
92 | this._queued_query = null;
93 | Search.query(q);
94 | }
95 | },
96 |
97 | hasIndex : function() {
98 | return this._index !== null;
99 | },
100 |
101 | deferQuery : function(query) {
102 | this._queued_query = query;
103 | },
104 |
105 | stopPulse : function() {
106 | this._pulse_status = 0;
107 | },
108 |
109 | startPulse : function() {
110 | if (this._pulse_status >= 0)
111 | return;
112 | function pulse() {
113 | var i;
114 | Search._pulse_status = (Search._pulse_status + 1) % 4;
115 | var dotString = '';
116 | for (i = 0; i < Search._pulse_status; i++)
117 | dotString += '.';
118 | Search.dots.text(dotString);
119 | if (Search._pulse_status > -1)
120 | window.setTimeout(pulse, 500);
121 | }
122 | pulse();
123 | },
124 |
125 | /**
126 | * perform a search for something (or wait until index is loaded)
127 | */
128 | performSearch : function(query) {
129 | // create the required interface elements
130 | this.out = $('#search-results');
131 | this.title = $('' + _('Searching') + '
').appendTo(this.out);
132 | this.dots = $('').appendTo(this.title);
133 | this.status = $('
').appendTo(this.out);
134 | this.output = $('').appendTo(this.out);
135 |
136 | $('#search-progress').text(_('Preparing search...'));
137 | this.startPulse();
138 |
139 | // index already loaded, the browser was quick!
140 | if (this.hasIndex())
141 | this.query(query);
142 | else
143 | this.deferQuery(query);
144 | },
145 |
146 | /**
147 | * execute search (requires search index to be loaded)
148 | */
149 | query : function(query) {
150 | var i;
151 |
152 | // stem the searchterms and add them to the correct list
153 | var stemmer = new Stemmer();
154 | var searchterms = [];
155 | var excluded = [];
156 | var hlterms = [];
157 | var tmp = splitQuery(query);
158 | var objectterms = [];
159 | for (i = 0; i < tmp.length; i++) {
160 | if (tmp[i] !== "") {
161 | objectterms.push(tmp[i].toLowerCase());
162 | }
163 |
164 | if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
165 | tmp[i] === "") {
166 | // skip this "word"
167 | continue;
168 | }
169 | // stem the word
170 | var word = stemmer.stemWord(tmp[i].toLowerCase());
171 | // prevent stemmer from cutting word smaller than two chars
172 | if(word.length < 3 && tmp[i].length >= 3) {
173 | word = tmp[i];
174 | }
175 | var toAppend;
176 | // select the correct list
177 | if (word[0] == '-') {
178 | toAppend = excluded;
179 | word = word.substr(1);
180 | }
181 | else {
182 | toAppend = searchterms;
183 | hlterms.push(tmp[i].toLowerCase());
184 | }
185 | // only add if not already in the list
186 | if (!$u.contains(toAppend, word))
187 | toAppend.push(word);
188 | }
189 | var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
190 |
191 | // console.debug('SEARCH: searching for:');
192 | // console.info('required: ', searchterms);
193 | // console.info('excluded: ', excluded);
194 |
195 | // prepare search
196 | var terms = this._index.terms;
197 | var titleterms = this._index.titleterms;
198 |
199 | // array of [filename, title, anchor, descr, score]
200 | var results = [];
201 | $('#search-progress').empty();
202 |
203 | // lookup as object
204 | for (i = 0; i < objectterms.length; i++) {
205 | var others = [].concat(objectterms.slice(0, i),
206 | objectterms.slice(i+1, objectterms.length));
207 | results = results.concat(this.performObjectSearch(objectterms[i], others));
208 | }
209 |
210 | // lookup as search terms in fulltext
211 | results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
212 |
213 | // let the scorer override scores with a custom scoring function
214 | if (Scorer.score) {
215 | for (i = 0; i < results.length; i++)
216 | results[i][4] = Scorer.score(results[i]);
217 | }
218 |
219 | // now sort the results by score (in opposite order of appearance, since the
220 | // display function below uses pop() to retrieve items) and then
221 | // alphabetically
222 | results.sort(function(a, b) {
223 | var left = a[4];
224 | var right = b[4];
225 | if (left > right) {
226 | return 1;
227 | } else if (left < right) {
228 | return -1;
229 | } else {
230 | // same score: sort alphabetically
231 | left = a[1].toLowerCase();
232 | right = b[1].toLowerCase();
233 | return (left > right) ? -1 : ((left < right) ? 1 : 0);
234 | }
235 | });
236 |
237 | // for debugging
238 | //Search.lastresults = results.slice(); // a copy
239 | //console.info('search results:', Search.lastresults);
240 |
241 | // print the results
242 | var resultCount = results.length;
243 | function displayNextItem() {
244 | // results left, load the summary and display it
245 | if (results.length) {
246 | var item = results.pop();
247 | var listItem = $('');
248 | if (DOCUMENTATION_OPTIONS.BUILDER === 'dirhtml') {
249 | // dirhtml builder
250 | var dirname = item[0] + '/';
251 | if (dirname.match(/\/index\/$/)) {
252 | dirname = dirname.substring(0, dirname.length-6);
253 | } else if (dirname == 'index/') {
254 | dirname = '';
255 | }
256 | listItem.append($('').attr('href',
257 | DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
258 | highlightstring + item[2]).html(item[1]));
259 | } else {
260 | // normal html builders
261 | listItem.append($('').attr('href',
262 | item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
263 | highlightstring + item[2]).html(item[1]));
264 | }
265 | if (item[3]) {
266 | listItem.append($(' (' + item[3] + ')'));
267 | Search.output.append(listItem);
268 | listItem.slideDown(5, function() {
269 | displayNextItem();
270 | });
271 | } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
272 | $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX,
273 | dataType: "text",
274 | complete: function(jqxhr, textstatus) {
275 | var data = jqxhr.responseText;
276 | if (data !== '' && data !== undefined) {
277 | listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
278 | }
279 | Search.output.append(listItem);
280 | listItem.slideDown(5, function() {
281 | displayNextItem();
282 | });
283 | }});
284 | } else {
285 | // no source available, just display title
286 | Search.output.append(listItem);
287 | listItem.slideDown(5, function() {
288 | displayNextItem();
289 | });
290 | }
291 | }
292 | // search finished, update title and status message
293 | else {
294 | Search.stopPulse();
295 | Search.title.text(_('Search Results'));
296 | if (!resultCount)
297 | Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
298 | else
299 | Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
300 | Search.status.fadeIn(500);
301 | }
302 | }
303 | displayNextItem();
304 | },
305 |
306 | /**
307 | * search for object names
308 | */
309 | performObjectSearch : function(object, otherterms) {
310 | var filenames = this._index.filenames;
311 | var docnames = this._index.docnames;
312 | var objects = this._index.objects;
313 | var objnames = this._index.objnames;
314 | var titles = this._index.titles;
315 |
316 | var i;
317 | var results = [];
318 |
319 | for (var prefix in objects) {
320 | for (var name in objects[prefix]) {
321 | var fullname = (prefix ? prefix + '.' : '') + name;
322 | var fullnameLower = fullname.toLowerCase()
323 | if (fullnameLower.indexOf(object) > -1) {
324 | var score = 0;
325 | var parts = fullnameLower.split('.');
326 | // check for different match types: exact matches of full name or
327 | // "last name" (i.e. last dotted part)
328 | if (fullnameLower == object || parts[parts.length - 1] == object) {
329 | score += Scorer.objNameMatch;
330 | // matches in last name
331 | } else if (parts[parts.length - 1].indexOf(object) > -1) {
332 | score += Scorer.objPartialMatch;
333 | }
334 | var match = objects[prefix][name];
335 | var objname = objnames[match[1]][2];
336 | var title = titles[match[0]];
337 | // If more than one term searched for, we require other words to be
338 | // found in the name/title/description
339 | if (otherterms.length > 0) {
340 | var haystack = (prefix + ' ' + name + ' ' +
341 | objname + ' ' + title).toLowerCase();
342 | var allfound = true;
343 | for (i = 0; i < otherterms.length; i++) {
344 | if (haystack.indexOf(otherterms[i]) == -1) {
345 | allfound = false;
346 | break;
347 | }
348 | }
349 | if (!allfound) {
350 | continue;
351 | }
352 | }
353 | var descr = objname + _(', in ') + title;
354 |
355 | var anchor = match[3];
356 | if (anchor === '')
357 | anchor = fullname;
358 | else if (anchor == '-')
359 | anchor = objnames[match[1]][1] + '-' + fullname;
360 | // add custom score for some objects according to scorer
361 | if (Scorer.objPrio.hasOwnProperty(match[2])) {
362 | score += Scorer.objPrio[match[2]];
363 | } else {
364 | score += Scorer.objPrioDefault;
365 | }
366 | results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
367 | }
368 | }
369 | }
370 |
371 | return results;
372 | },
373 |
374 | /**
375 | * search for full-text terms in the index
376 | */
377 | performTermsSearch : function(searchterms, excluded, terms, titleterms) {
378 | var docnames = this._index.docnames;
379 | var filenames = this._index.filenames;
380 | var titles = this._index.titles;
381 |
382 | var i, j, file;
383 | var fileMap = {};
384 | var scoreMap = {};
385 | var results = [];
386 |
387 | // perform the search on the required terms
388 | for (i = 0; i < searchterms.length; i++) {
389 | var word = searchterms[i];
390 | var files = [];
391 | var _o = [
392 | {files: terms[word], score: Scorer.term},
393 | {files: titleterms[word], score: Scorer.title}
394 | ];
395 | // add support for partial matches
396 | if (word.length > 2) {
397 | for (var w in terms) {
398 | if (w.match(word) && !terms[word]) {
399 | _o.push({files: terms[w], score: Scorer.partialTerm})
400 | }
401 | }
402 | for (var w in titleterms) {
403 | if (w.match(word) && !titleterms[word]) {
404 | _o.push({files: titleterms[w], score: Scorer.partialTitle})
405 | }
406 | }
407 | }
408 |
409 | // no match but word was a required one
410 | if ($u.every(_o, function(o){return o.files === undefined;})) {
411 | break;
412 | }
413 | // found search word in contents
414 | $u.each(_o, function(o) {
415 | var _files = o.files;
416 | if (_files === undefined)
417 | return
418 |
419 | if (_files.length === undefined)
420 | _files = [_files];
421 | files = files.concat(_files);
422 |
423 | // set score for the word in each file to Scorer.term
424 | for (j = 0; j < _files.length; j++) {
425 | file = _files[j];
426 | if (!(file in scoreMap))
427 | scoreMap[file] = {};
428 | scoreMap[file][word] = o.score;
429 | }
430 | });
431 |
432 | // create the mapping
433 | for (j = 0; j < files.length; j++) {
434 | file = files[j];
435 | if (file in fileMap && fileMap[file].indexOf(word) === -1)
436 | fileMap[file].push(word);
437 | else
438 | fileMap[file] = [word];
439 | }
440 | }
441 |
442 | // now check if the files don't contain excluded terms
443 | for (file in fileMap) {
444 | var valid = true;
445 |
446 | // check if all requirements are matched
447 | var filteredTermCount = // as search terms with length < 3 are discarded: ignore
448 | searchterms.filter(function(term){return term.length > 2}).length
449 | if (
450 | fileMap[file].length != searchterms.length &&
451 | fileMap[file].length != filteredTermCount
452 | ) continue;
453 |
454 | // ensure that none of the excluded terms is in the search result
455 | for (i = 0; i < excluded.length; i++) {
456 | if (terms[excluded[i]] == file ||
457 | titleterms[excluded[i]] == file ||
458 | $u.contains(terms[excluded[i]] || [], file) ||
459 | $u.contains(titleterms[excluded[i]] || [], file)) {
460 | valid = false;
461 | break;
462 | }
463 | }
464 |
465 | // if we have still a valid result we can add it to the result list
466 | if (valid) {
467 | // select one (max) score for the file.
468 | // for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
469 | var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
470 | results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
471 | }
472 | }
473 | return results;
474 | },
475 |
476 | /**
477 | * helper function to return a node containing the
478 | * search summary for a given text. keywords is a list
479 | * of stemmed words, hlwords is the list of normal, unstemmed
480 | * words. the first one is used to find the occurrence, the
481 | * latter for highlighting it.
482 | */
483 | makeSearchSummary : function(htmlText, keywords, hlwords) {
484 | var text = Search.htmlToText(htmlText);
485 | var textLower = text.toLowerCase();
486 | var start = 0;
487 | $.each(keywords, function() {
488 | var i = textLower.indexOf(this.toLowerCase());
489 | if (i > -1)
490 | start = i;
491 | });
492 | start = Math.max(start - 120, 0);
493 | var excerpt = ((start > 0) ? '...' : '') +
494 | $.trim(text.substr(start, 240)) +
495 | ((start + 240 - text.length) ? '...' : '');
496 | var rv = $('').text(excerpt);
497 | $.each(hlwords, function() {
498 | rv = rv.highlightText(this, 'highlighted');
499 | });
500 | return rv;
501 | }
502 | };
503 |
504 | $(document).ready(function() {
505 | Search.init();
506 | });
507 |
--------------------------------------------------------------------------------
/docs/_build/html/_static/underscore.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.3.1
2 | // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Underscore is freely distributable under the MIT license.
4 | // Portions of Underscore are inspired or borrowed from Prototype,
5 | // Oliver Steele's Functional, and John Resig's Micro-Templating.
6 | // For all details and documentation:
7 | // http://documentcloud.github.com/underscore
8 | (function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
9 | c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
10 | h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
11 | b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a==
12 | null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
13 | function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
14 | e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
15 | function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
17 | c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};
24 | b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
25 | 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
26 | b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
27 | b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),
28 | function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
29 | u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
30 | function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
31 | true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
32 |
--------------------------------------------------------------------------------
/docs/_build/html/genindex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Index — pychi 0.0.1 documentation
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
45 |
46 |
50 |
51 |
52 |
53 |
54 |
55 | - »
56 | - Index
57 | -
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
Index
67 |
68 |
69 |
A
70 | |
C
71 | |
D
72 | |
G
73 | |
K
74 | |
L
75 | |
M
76 | |
N
77 | |
P
78 | |
R
79 | |
S
80 | |
W
81 |
82 |
83 |
A
84 |
94 |
95 |
C
96 |
116 |
117 |
D
118 |
124 |
125 |
G
126 |
132 |
133 |
K
134 |
140 |
141 |
L
142 |
148 |
149 |
M
150 |
156 |
157 |
N
158 |
196 |
197 |
P
198 |
218 |
219 |
R
220 |
226 |
227 |
S
228 |
256 |
257 |
W
258 |
264 |
265 |
266 |
267 |
268 |
269 |
283 |
284 |
285 |
286 |
287 |
292 |
293 |
294 |
--------------------------------------------------------------------------------
/docs/_build/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Welcome to pychi’s documentation! — pychi 0.0.1 documentation
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
45 |
46 |
50 |
51 |
52 |
53 |
54 |
55 | - »
56 | - Welcome to pychi’s documentation!
57 | -
58 | View page source
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
Welcome to pychi’s documentation!
68 |
82 |
83 |
84 |
Indices and tables
85 |
90 |
91 |
92 |
93 |
94 |
95 |
111 |
112 |
113 |
114 |
115 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/docs/_build/html/modules.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <no title> — pychi 0.0.1 documentation
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
51 |
52 |
53 |
54 |
64 |
65 |
66 |
67 |
pychi package
68 | ===
69 |
82 |
83 |
84 |
85 |
86 |
103 |
104 |
105 |
106 |
107 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/docs/_build/html/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/docs/_build/html/objects.inv
--------------------------------------------------------------------------------
/docs/_build/html/py-modindex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Python Module Index — pychi 0.0.1 documentation
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
47 |
48 |
52 |
53 |
54 |
55 |
56 |
57 | - »
58 | - Python Module Index
59 | -
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
Python Module Index
69 |
70 |
73 |
74 |
105 |
106 |
107 |
108 |
109 |
123 |
124 |
125 |
126 |
127 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/docs/_build/html/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Search — pychi 0.0.1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
47 |
48 |
52 |
53 |
54 |
55 |
56 |
57 | - »
58 | - Search
59 | -
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
96 |
97 |
98 |
99 |
100 |
105 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/docs/_build/html/searchindex.js:
--------------------------------------------------------------------------------
1 | Search.setIndex({docnames:["index","modules","pychi"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.index":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["index.rst","modules.rst","pychi.rst"],objects:{"":{pychi:[2,0,0,"-"]},"pychi.light":{Arbitrary:[2,1,1,""],Cw:[2,1,1,""],Gaussian:[2,1,1,""],Light:[2,1,1,""],Sech:[2,1,1,""]},"pychi.light.Light":{add_shot_noise:[2,2,1,""],plot_propagation:[2,2,1,""],set_result_as_start:[2,2,1,""]},"pychi.materials":{Waveguide:[2,1,1,""]},"pychi.materials.Waveguide":{chi_2:[2,2,1,""],chi_3:[2,2,1,""],compute_betas:[2,2,1,""],k:[2,2,1,""],n_eff:[2,2,1,""],plot_refractive_index:[2,2,1,""],rhs_prefactor:[2,2,1,""],set_betas:[2,2,1,""],set_gamma:[2,2,1,""],set_n2:[2,2,1,""]},"pychi.models":{Chi2:[2,1,1,""],Chi2Chi3:[2,1,1,""],Chi3:[2,1,1,""],Model:[2,1,1,""],Spm:[2,1,1,""],SpmChi2:[2,1,1,""],SpmChi2Chi3:[2,1,1,""],SpmChi3:[2,1,1,""],numbaconj:[2,3,1,""],numbacopy:[2,3,1,""],numbaexp:[2,3,1,""]},"pychi.models.Chi2":{nonlinear_term:[2,2,1,""]},"pychi.models.Chi2Chi3":{nonlinear_term:[2,2,1,""]},"pychi.models.Chi3":{nonlinear_term:[2,2,1,""]},"pychi.models.Model":{dispersion_step:[2,2,1,""],nonlinear_term:[2,2,1,""]},"pychi.models.Spm":{nonlinear_term:[2,2,1,""]},"pychi.models.SpmChi2":{nonlinear_term:[2,2,1,""]},"pychi.models.SpmChi2Chi3":{nonlinear_term:[2,2,1,""]},"pychi.models.SpmChi3":{nonlinear_term:[2,2,1,""]},"pychi.solvers":{Solver:[2,1,1,""],numbaexp:[2,3,1,""],numbanorm:[2,3,1,""]},"pychi.solvers.Solver":{solve:[2,2,1,""]},pychi:{light:[2,0,0,"-"],materials:[2,0,0,"-"],models:[2,0,0,"-"],solvers:[2,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute"},terms:{"22e":2,"class":2,"default":2,"final":2,"float":2,"function":2,"int":2,"new":2,"return":2,"schr\u00f6dinger":2,Not:2,The:2,accomod:2,accordingli:2,adapt:2,adaptive_factor:2,add:2,add_shot_nois:2,adding:2,affect:2,all:2,allow:2,analyt:2,arbitrari:2,area:2,arrai:2,aug:2,author:2,avail:2,average_pow:2,avoid:2,axes:2,axi:2,base:2,beta:2,built:2,center:2,chi2:2,chi2chi3:2,chi3:2,chi:2,chi_2:2,chi_3:2,child:2,coeffici:2,coher:2,complex:2,comput:2,compute_beta:2,conjug:2,contain:2,content:[0,1],conveni:2,copi:2,creat:2,curv:2,data:2,dedic:2,delai:2,deriv:2,differ:2,dispers:2,dispersion_step:2,domain:2,effect:2,effective_area:2,electr:2,envelop:2,equat:2,evolut:2,exponenti:2,feb:2,field:2,field_f:2,field_t_in:2,first:2,frequenc:2,fri:2,from:2,gamma:2,gaussian:2,gener:2,give:2,given:2,happen:2,harmon:2,here:2,highest:2,implement:2,index:[0,2],inform:2,initi:2,input:2,instanti:2,instead:2,integr:2,interact:2,length:2,light:[0,1],local_error:2,materi:[0,1],max_dz:2,method:2,model:[0,1],modul:[0,1],n_eff:2,nois:2,none:2,nonlinear:2,nonlinear_term:2,note:2,numba:2,numbaconj:2,numbacopi:2,numbaexp:2,numbanorm:2,number:2,object:2,onli:2,optim:2,option:2,order:2,output:2,over:2,overwrit:2,packag:[0,1],page:0,paramet:2,parent:2,phase:2,physic:2,plot:2,plot_propag:2,plot_refractive_index:2,propag:2,properti:2,provid:2,puls:2,pulse_dur:2,pulse_electric_field:2,pulse_energi:2,pulse_frequency_axi:2,pulse_wavelength:2,pychi:1,quantiti:2,raman:2,raman_fract:2,raman_tau_1:2,raman_tau_2:2,random:2,refract:2,relat:2,reproduc:2,result:2,rhs_prefactor:2,save:2,savenam:2,search:0,sech:2,seed:2,self:2,set:2,set_beta:2,set_gamma:2,set_n2:2,set_result_as_start:2,setup:2,shape:2,shot:2,should:2,simul:2,size:2,solv:2,solver:[0,1],sourc:2,specifi:2,spectral:2,spm:2,spmchi2:2,spmchi2chi3:2,spmchi3:2,src:[],standard:2,step:2,store:2,studi:2,submodul:[0,1],suitabl:2,sum:2,support:2,t_pt:2,term:2,thi:2,thibault:2,thu:2,time:2,tripl:2,type:2,use:2,used:2,useful:2,user:2,util:2,valu:2,vector:2,versu:2,voumardt:2,waveform:2,waveguid:2,wavelength:2,which:2,z_pt:2},titles:["Welcome to pychi\u2019s documentation!","<no title>","pychi package"],titleterms:{content:2,document:0,indic:0,light:2,materi:2,model:2,modul:2,packag:2,pychi:[0,2],solver:2,src:[],submodul:2,tabl:0,welcom:0}})
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 | #
13 | import os
14 | import sys
15 |
16 | sys.path.insert(0, os.path.abspath('../src'))
17 |
18 |
19 | # -- Project information -----------------------------------------------------
20 |
21 | project = 'pychi'
22 | copyright = '2023, Thibault Voumard'
23 | author = 'Thibault Voumard'
24 |
25 | # The full version, including alpha/beta/rc tags
26 | release = '0.0.12'
27 |
28 |
29 | # -- General configuration ---------------------------------------------------
30 |
31 | # Add any Sphinx extension module names here, as strings. They can be
32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
33 | # ones.
34 | extensions = [
35 | 'sphinx.ext.autodoc',
36 | 'sphinx.ext.viewcode',
37 | 'sphinx.ext.napoleon',
38 | 'sphinx_rtd_theme',
39 | 'myst_parser'
40 | ]
41 |
42 | # Add any paths that contain templates here, relative to this directory.
43 | templates_path = ['_templates']
44 |
45 | # List of patterns, relative to source directory, that match files and
46 | # directories to ignore when looking for source files.
47 | # This pattern also affects html_static_path and html_extra_path.
48 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
49 |
50 |
51 | # -- Options for HTML output -------------------------------------------------
52 |
53 | # Tell Sphinx to document private methods
54 | #autodoc_default_options = {
55 | # "members": True,
56 | # "undoc-members": True,
57 | # "private-members": True
58 | #}
59 |
60 | autodoc_mock_imports = ["matplotlib", "scipy", "numpy", "pyfftw", "numba"]
61 |
62 | # The theme to use for HTML and HTML Help pages. See the documentation for
63 | # a list of builtin themes.
64 | #
65 | html_theme = 'sphinx_rtd_theme'
66 |
67 | # Add any paths that contain custom static files (such as style sheets) here,
68 | # relative to this directory. They are copied after the builtin static files,
69 | # so a file named "default.css" will overwrite the builtin "default.css".
70 | html_static_path = []
71 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. pychi documentation master file, created by
2 | sphinx-quickstart on Fri Mar 3 10:39:56 2023.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to pychi's documentation!
7 | =================================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 | :caption: Contents:
12 |
13 | readme_link
14 | pychi
15 |
--------------------------------------------------------------------------------
/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/modules.rst:
--------------------------------------------------------------------------------
1 | pychi package
2 | ===
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | pychi
8 |
--------------------------------------------------------------------------------
/docs/pychi.rst:
--------------------------------------------------------------------------------
1 | pychi package
2 | =============
3 |
4 | pychi.light module
5 | ------------------
6 |
7 | .. automodule:: pychi.light
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
12 | pychi.materials module
13 | ----------------------
14 |
15 | .. automodule:: pychi.materials
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | pychi.models module
21 | -------------------
22 |
23 | .. automodule:: pychi.models
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | pychi.solvers module
29 | --------------------
30 |
31 | .. automodule:: pychi.solvers
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 |
--------------------------------------------------------------------------------
/docs/readme_link.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../README.md
2 | :parser: myst_parser.sphinx_
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | myst-parser
2 | sphinx_rtd_theme
3 |
--------------------------------------------------------------------------------
/examples/Cascaded Nonlinearities/cascaded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/Cascaded Nonlinearities/cascaded.png
--------------------------------------------------------------------------------
/examples/Cascaded Nonlinearities/effective_index.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/Cascaded Nonlinearities/effective_index.npy
--------------------------------------------------------------------------------
/examples/Cascaded Nonlinearities/pychi_cascaded.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Feb 28 15:31:47 2022
4 |
5 | The waveguide/fiber parameters are first provided, and a Waveguide instance
6 | is created. Then, the pulse parameters are used to create a Light object.
7 | A physical model is then chosen, taking into account different nonlinear
8 | interactions based on the user choice. Finally, a solver is instantiated
9 | and computes the propagation of the pulse in the waveguide with the chosen
10 | nonlinear interactions.
11 |
12 | @author: voumardt
13 | """
14 | import matplotlib.pyplot as plt
15 | import numpy as np
16 | import os
17 | from scipy.constants import c
18 |
19 | import sys
20 | sys.path.append(os.getcwd() + '../../../')
21 |
22 | from src import *
23 |
24 |
25 | """
26 | User parameters
27 | """
28 | ### Simulation
29 | t_pts = 2**17
30 |
31 | ### Light
32 | pulse_duration = 100e-15
33 | pulse_wavelength = 1.56e-06
34 | pulse_energy = 1.6e-9
35 |
36 | ### Waveguide
37 | wg_length = 0.001
38 | wg_chi_2 = 1.1e-12
39 | wg_chi_3 = 3.4e-21
40 | wg_a_eff = 1e-12
41 | wg_freq, wg_n_eff = np.load('effective_index.npy')
42 |
43 |
44 | """
45 | Nonlinear propagation
46 | """
47 | ### Prepare waveguide
48 | waveguide = materials.Waveguide(wg_freq, wg_n_eff, wg_chi_2, wg_chi_3,
49 | wg_a_eff, wg_length, t_pts=t_pts)
50 |
51 | ### Prepare input pulse
52 | pulse = light.Sech(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
53 |
54 | ### Prepare model
55 | model = models.SpmChi2Chi3(waveguide, pulse)
56 |
57 | ### Prepare solver, solve
58 | solver = solvers.Solver(model)
59 | solver.solve()
60 |
61 |
62 | """
63 | Plots
64 | """
65 | pulse.plot_propagation('cascaded.png')
66 |
67 |
--------------------------------------------------------------------------------
/examples/LiNb/Experimental_vs_simulation_LiNb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/LiNb/Experimental_vs_simulation_LiNb.png
--------------------------------------------------------------------------------
/examples/LiNb/exp_LiNb.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/LiNb/exp_LiNb.mat
--------------------------------------------------------------------------------
/examples/LiNb/n_eff_data_LiNb.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/LiNb/n_eff_data_LiNb.npy
--------------------------------------------------------------------------------
/examples/LiNb/pychi_LiNb_exp_vs_sim.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Feb 28 15:31:47 2022
4 |
5 | @author: voumardt
6 | """
7 | import matplotlib.pyplot as plt
8 | import numpy as np
9 | import os
10 | import pandas
11 | from scipy.constants import c
12 | from scipy.io import loadmat
13 |
14 | import sys
15 | sys.path.append(os.getcwd() + '../../../')
16 |
17 | from src import *
18 |
19 |
20 | """
21 | User parameters
22 | """
23 | ### Simulation
24 | t_pts = 2**16
25 |
26 | ### Light
27 | pulse_duration = 80e-15
28 | pulse_wavelength = 1.58e-06
29 | pulse_energy = 1.056e-11
30 |
31 | ### Waveguide
32 | wg_length = 0.006
33 | wg_chi_2 = 20e-12
34 | wg_chi_3 = 2.5e-21 # Raman lasing and soliton mode-locking in lithium niobate microresonators
35 | wg_a_eff = 1e-12
36 | wg_freq, wg_n_eff = np.load('n_eff_data_LiNb.npy')
37 |
38 |
39 | """
40 | Nonlinear propagation
41 | """
42 | waveguide = materials.Waveguide(wg_freq, wg_n_eff, wg_chi_2, wg_chi_3,
43 | wg_a_eff, wg_length, t_pts=t_pts)
44 | pulse = light.Sech(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
45 | model = models.SpmChi2(waveguide, pulse)
46 | solver = solvers.Solver(model)
47 | solver.solve()
48 |
49 |
50 | """
51 | Plots
52 | """
53 | pulse.plot_propagation()
54 |
55 | # Load experimental results
56 | exp_data = loadmat('exp_LiNb.mat')
57 | exp_wl = exp_data['wavelength'][0]
58 | exp_int = exp_data['intensity'][0]
59 |
60 | # Compare experimental results and simulation
61 | plt.figure()
62 | plt.plot(pulse.wl, 10*np.log10(pulse.spectrum_wl[-1]/np.amax(pulse.spectrum_wl[-1]))-3)
63 | plt.plot(exp_wl, exp_int - np.amax(exp_int))
64 | plt.xlim(3.5e-7, 1.75e-6)
65 | plt.ylim(-75, 5)
66 | plt.title('Experimental vs simulation - LiNb')
67 | plt.xlabel('Wavelength [m]')
68 | plt.ylabel('Intensity [dB]')
69 | plt.legend(('Simulation', 'Experiment'))
70 | plt.savefig('Experimental_vs_simulation_LiNb.png')
71 |
--------------------------------------------------------------------------------
/examples/QPM/effective_index.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/QPM/effective_index.npy
--------------------------------------------------------------------------------
/examples/QPM/pychi_QPM.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Feb 28 15:31:47 2022
4 |
5 | The waveguide/fiber parameters are first provided, and a Waveguide instance
6 | is created. Then, the pulse parameters are used to create a Light object.
7 | A physical model is then chosen, taking into account different nonlinear
8 | interactions based on the user choice. Finally, a solver is instantiated
9 | and computes the propagation of the pulse in the waveguide with the chosen
10 | nonlinear interactions. This particular examples shows how to define a poling
11 | and breakpoints forcing computation at some desired distances.
12 |
13 | @author: voumardt
14 | """
15 | import matplotlib.pyplot as plt
16 | import numpy as np
17 | import os
18 |
19 | import sys
20 | sys.path.append(os.getcwd() + '../../../')
21 |
22 | from src import *
23 |
24 |
25 | """
26 | User parameters
27 | """
28 | ### Simulation
29 | t_pts = 2**15
30 |
31 | ### Light
32 | pulse_duration = 100e-15
33 | pulse_wavelength = 1.56e-06
34 | pulse_energy = 1e-9
35 |
36 | ### Waveguide
37 | wg_length = 0.001
38 | const_wg_chi_2 = 1.1e-12
39 |
40 | # poling period
41 | qpm_length = 3.3e-5/2
42 |
43 | wg_chi_3 = 3.4e-21
44 | wg_a_eff = 1e-12
45 | wg_freq, wg_n_eff = np.load('effective_index.npy')
46 |
47 | # Define the nonlinearity as a function of z
48 | def wg_chi_2(z):
49 | return (-1)**(np.floor(z/qpm_length)%2)*const_wg_chi_2
50 |
51 | # Define breakpoints to force computation whenever the poling changes sign
52 | breakpoints = np.arange(wg_length//qpm_length)*qpm_length + 1e-10
53 |
54 | """
55 | Nonlinear propagation
56 | """
57 | waveguide = materials.Waveguide(wg_freq, wg_n_eff, wg_chi_2, wg_chi_3,
58 | wg_a_eff, wg_length, t_pts=t_pts)
59 | pulse = light.Sech(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
60 | model = models.Chi2(waveguide, pulse)
61 | solver = solvers.Solver(model, method='ERK4IP', breakpoints=breakpoints)
62 | solver.solve()
63 |
64 |
65 | """
66 | Plots
67 | """
68 | pulse.plot_propagation()
69 |
--------------------------------------------------------------------------------
/examples/SPM/frequency_propagation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/SPM/frequency_propagation.png
--------------------------------------------------------------------------------
/examples/SPM/pychi_spm_validation.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Feb 28 15:31:47 2022
4 |
5 | @author: voumardt
6 | """
7 | import matplotlib.pyplot as plt
8 | import numpy as np
9 | from scipy.constants import c
10 | eps_0 = 8.8541878128e-12
11 | import math
12 | import os
13 |
14 | import sys
15 | sys.path.append(os.getcwd() + '../../../')
16 |
17 | from src import *
18 |
19 |
20 | """
21 | User parameters
22 |
23 | Parameters taken from 'Supercontinuum generation in photonic crystal fiber',
24 | John M. Dudley, Goëry Genty, and Stéphane Coen, DOI: https://doi.org/10.1103/RevModPhys.78.1135
25 | to reproduce figure 3 therein.
26 | """
27 | ### Simulation
28 | t_pts = 2**14
29 |
30 | ### Light
31 | pulse_duration = 50e-15
32 | pulse_wavelength = 0.835e-06
33 | pulse_peak_power = 1e4
34 | pulse_energy = pulse_peak_power*pulse_duration/np.log(1+2**0.5)
35 |
36 | ### Waveguide
37 | wg_length = 0.15
38 | wg_chi_2 = 0
39 | wg_a_eff = 1e-12
40 | wg_n = 1.45
41 | gamma = 0.11
42 | wg_chi_3 = 4*wg_n**2*c*eps_0*gamma*pulse_wavelength*wg_a_eff/6/np.pi
43 | wg_omega = np.linspace(c/1670e-9*2*np.pi, c/417.5e-9*2*np.pi, t_pts)
44 | betas = [wg_n*2*np.pi/pulse_wavelength, wg_n/c, -1.183e-26, 8.1038e-41,
45 | -9.5205e-56, 2.0737e-70, -5.3943e-85, 1.3486e-99, -2.5495e-114,
46 | 3.0524e-129, -1.7140e-144]
47 |
48 | ### Compute refractive index
49 | wg_freq = wg_omega/2/np.pi
50 | def compute_n_eff(wg_omega, pulse_wavelength, betas):
51 | k = np.zeros(t_pts, dtype='float64')
52 | for i, beta in enumerate(betas):
53 | k += beta*(wg_omega - 2*np.pi*c/pulse_wavelength)**i/math.factorial(i)
54 | n_eff = k*c/wg_omega
55 | return n_eff
56 | wg_n_eff = compute_n_eff(wg_omega, pulse_wavelength, betas)
57 |
58 |
59 | """
60 | Nonlinear propagation
61 | """
62 | ### Prepare waveguide
63 | waveguide = materials.Waveguide(wg_freq, wg_n_eff, wg_chi_2, wg_chi_3,
64 | wg_a_eff, wg_length, t_pts=t_pts)
65 |
66 | ### Prepare input pulse
67 | pulse = light.Sech(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
68 |
69 | ### Prepare model
70 | model = models.Spm(waveguide, pulse)
71 |
72 | ### Prepare solver
73 | solver = solvers.Solver(model)
74 |
75 | ### Solve
76 | solver.solve()
77 |
78 |
79 | """
80 | Plots
81 | """
82 | z_pos = pulse.z_save
83 | wl = pulse.wl
84 | spec_wl = pulse.spectrum_wl[:, (wl>450e-9)&(wl<1300e-9)]
85 | wl = wl[(wl>450e-9)&(wl<1300e-9)]
86 | spec_wl_db = 20*np.log10(np.abs(spec_wl) + 1e-20)
87 |
88 |
89 | plt.figure()
90 | plt.subplot(121)
91 | plt.imshow(spec_wl_db[::-1], cmap='jet', aspect='auto', vmin=np.amax(spec_wl_db) - 40,
92 | extent=(np.amin(wl)*1e9, np.amax(wl)*1e9, 0, np.amax(z_pos)))
93 | plt.xlabel('Wavelength [nm]')
94 | plt.ylabel('Distance [m]')
95 |
96 | waveform = 10*np.log10(np.abs(pulse.waveform)**2 + 1e-20) - np.amax(10*np.log10(np.abs(pulse.waveform)**2 + 1e-20))
97 | time = waveguide.time
98 | waveform = waveform[:, (time<5e-12)&(time>-2e-12)]
99 | time = time[(time<5e-12)&(time>-2e-12)]
100 |
101 | plt.subplot(122)
102 | plt.imshow(waveform[::-1], cmap='jet', aspect='auto', vmin = np.amax(waveform) - 40,
103 | extent=(np.amin(time)*1e12, np.amax(time)*1e12, 0, np.amax(z_pos)))
104 | plt.xlabel('Time [ps]')
105 | plt.ylabel('Distance [m]')
106 | plt.colorbar(label='Intensity [dB]')
107 | plt.tight_layout()
108 | plt.savefig('propagation.png')
109 |
--------------------------------------------------------------------------------
/examples/SPM/time_propagation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/SPM/time_propagation.png
--------------------------------------------------------------------------------
/examples/SiN/Experimental_vs_simulation_SiN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/SiN/Experimental_vs_simulation_SiN.png
--------------------------------------------------------------------------------
/examples/SiN/exp_SiN.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/SiN/exp_SiN.mat
--------------------------------------------------------------------------------
/examples/SiN/n_eff_data_SiN.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/SiN/n_eff_data_SiN.npy
--------------------------------------------------------------------------------
/examples/SiN/pychi_SiN_exp_vs_sim.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Feb 28 15:31:47 2022
4 |
5 | @author: voumardt
6 | """
7 | import matplotlib.pyplot as plt
8 | import numpy as np
9 | import os
10 | import pandas
11 | from scipy.constants import c
12 | from scipy.io import loadmat
13 |
14 | import sys
15 | sys.path.append(os.getcwd() + '../../../')
16 |
17 | from src import *
18 |
19 |
20 | """
21 | User parameters
22 | """
23 | ### Simulation
24 | t_pts = 2**17
25 |
26 | ### Light
27 | pulse_duration = 80e-15
28 | pulse_wavelength = 1.56e-6
29 | pulse_energy = 1e-10
30 |
31 | ### Waveguide
32 | wg_length = 0.0058
33 | wg_chi_2 = 0
34 | wg_chi_3 = 2.8e-21
35 | wg_a_eff = 3e-13
36 | wg_freq, wg_n_eff = np.load('n_eff_data_SiN.npy')
37 |
38 |
39 | """
40 | Nonlinear propagation
41 | """
42 | waveguide = materials.Waveguide(wg_freq, wg_n_eff, wg_chi_2, wg_chi_3,
43 | wg_a_eff, wg_length, t_pts=t_pts)
44 | pulse = light.Sech(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
45 | model = models.SpmChi3(waveguide, pulse)
46 | solver = solvers.Solver(model)
47 | solver.solve()
48 |
49 |
50 | """
51 | Plots
52 | """
53 | pulse.plot_propagation()
54 |
55 | # Load experimental results
56 | exp_data = loadmat('exp_SiN.mat')
57 | exp_wl = exp_data['wavelength'][0]
58 | exp_int = exp_data['intensity'][0]
59 |
60 | # Compare experimental results and simulation
61 | plt.figure()
62 | plt.plot(pulse.wl, 10*np.log10(pulse.spectrum_wl[-1]/np.amax(pulse.spectrum_wl[-1]))-15)
63 | plt.plot(exp_wl, exp_int - np.amax(exp_int))
64 | plt.xlim(3.5e-7, 1.75e-6)
65 | plt.ylim(-75, 5)
66 | plt.title('Experimental vs simulation - SiN')
67 | plt.xlabel('Wavelength [m]')
68 | plt.ylabel('Intensity [dB]')
69 | plt.legend(('Simulation', 'Experiment'))
70 | plt.savefig('Experimental_vs_simulation_SiN.png')
71 |
--------------------------------------------------------------------------------
/examples/effective_index.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pychi-code/pychi/11d3ab1b731b31cc86ee0e8edff8f1ff6c0aed4f/examples/effective_index.npy
--------------------------------------------------------------------------------
/examples/pychi_example.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Feb 28 15:31:47 2022
4 |
5 | The waveguide/fiber parameters are first provided, and a Waveguide instance
6 | is created. Then, the pulse parameters are used to create a Light object.
7 | A physical model is then chosen, taking into account different nonlinear
8 | interactions based on the user choice. Finally, a solver is instantiated
9 | and computes the propagation of the pulse in the waveguide with the chosen
10 | nonlinear interactions.
11 |
12 | @author: voumardt
13 | """
14 | import matplotlib.pyplot as plt
15 | import numpy as np
16 | from scipy.constants import c
17 |
18 | from src import *
19 |
20 |
21 | """
22 | User parameters
23 | """
24 | ### Simulation
25 | t_pts = 2**15
26 |
27 | ### Light
28 | pulse_duration = 100e-15
29 | pulse_wavelength = 1.56e-06
30 | pulse_energy = 1e-9
31 |
32 | ### Waveguide
33 | wg_length = 0.001
34 | wg_chi_2 = 1.1e-12
35 | wg_chi_3 = 3.4e-21
36 | wg_a_eff = 1e-12
37 | wg_freq, wg_n_eff = np.load('effective_index.npy')
38 |
39 |
40 | """
41 | Nonlinear propagation
42 | """
43 | ### Prepare waveguide
44 | waveguide = materials.Waveguide(wg_freq, wg_n_eff, wg_chi_2, wg_chi_3,
45 | wg_a_eff, wg_length, t_pts=t_pts)
46 | # Additional options:
47 | # One can provide beta coefficients (strongly discouraged) overwriting the refractive
48 | # index using waveguide.set_betas(betas, wavelength)
49 | #
50 | # wg_n_eff can be a 2 dimensional array, with first dimension the wavelength dependence
51 | # and second dimension the z dependence.
52 | #
53 | # chi2 and chi3 can be callables, returning a z dependent value. Alternatively, they
54 | # can be defined as one dimensional arrays describing their z dependence, or
55 | # two dimensional arrays describing their z and frequency dependence.
56 | #
57 | # One can use waveguide.set_gamma(gamma) or waveguide.set_n2(n2) to provide
58 | # nonlinear coefficient or nonlinear refractive index and overwrite chi3.
59 | #
60 | # Check documentation for more options and details.
61 |
62 |
63 | ### Prepare input pulse
64 | pulse = light.Sech(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
65 | # Other available pulse shapes:
66 | # pulse = light.Gaussian(waveguide, pulse_duration, pulse_energy, pulse_wavelength)
67 | # pulse = light.Cw(waveguide, pulse_average_power, pulse_wavelength)
68 | # pulse = light.Arbitrary(waveguide, pulse_frequency_axis, pulse_electric_field, pulse_energy)
69 |
70 |
71 | ### Prepare model
72 | model = models.SpmChi2Chi3(waveguide, pulse)
73 | # Other models available:
74 | # model = models.Spm(waveguide, pulse)
75 | # model = models.Chi2(waveguide, pulse)
76 | # model = models.Chi3(waveguide, pulse)
77 | # model = models.SpmChi2(waveguide, pulse)
78 | # model = models.SpmChi3(waveguide, pulse)
79 | # model = models.Chi2Chi3(waveguide, pulse)
80 |
81 |
82 | ### Prepare solver, solve
83 | solver = solvers.Solver(model)
84 | solver.solve()
85 |
86 |
87 | """
88 | Plots
89 | """
90 | pulse.plot_propagation()
91 | # Results can also be accessed via pulse.z_save, pulse.freq, pulse.spectrum, pulse.waveform
92 | # The refractive index and GVD can be seen with waveguide.plot_refractive_index()
93 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [tool.setuptools]
6 | package-dir = {"" = "src"}
7 |
8 | [project]
9 | name = "pychi"
10 | version = ""
11 | authors = [
12 | { name="Ultrafast Microphotonics Group - DESY", email="pychi@desy.de" },
13 | ]
14 | description = "Simulation package for the propagation of optical pulses in nonlinear media"
15 | readme = "README.md"
16 | requires-python = ">=3.7"
17 | classifiers = [
18 | "Programming Language :: Python :: 3",
19 | "License :: OSI Approved :: MIT License",
20 | "Operating System :: OS Independent",
21 | ]
22 |
23 | dependencies = [
24 | "matplotlib>=3.1.3",
25 | "numpy>=1.21.6",
26 | "scipy>=1.4.1",
27 | "numba>=0.56.0",
28 | "pyFFTW>=0.12.0",
29 | ]
30 |
31 |
32 | [project.urls]
33 | "Homepage" = "https://github.com/pychi-code/pychi"
34 | "Documentation" = "https://pychi.readthedocs.io/en/latest/index.html"
35 | "PyPI" = "https://pypi.org/project/pychi/"
36 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | matplotlib>=3.1.3
2 | numpy>=1.21.6
3 | scipy>=1.4.1
4 | numba>=0.56.0
5 | pyFFTW>=0.12.0
6 |
--------------------------------------------------------------------------------
/src/pychi/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Thu Feb 17 12:32:49 2022
4 |
5 | @author: voumardt
6 | """
7 | __version__ = '0.0.5'
8 |
9 | from . import light
10 | from . import materials
11 | from . import models
12 | from . import solvers
13 |
--------------------------------------------------------------------------------
/src/pychi/light.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Fri Aug 13 12:01:48 2021
4 |
5 | @author: Thibault
6 |
7 | This module contains the classes used to instantiate light. Different
8 | standard pulse shapes are built-in, and a class is dedicated to accomodating
9 | user-provided light with arbitrary spectral shape. Note that the electric
10 | field is stored as an analytical envelope, thus is a complex quantity.
11 | """
12 | import matplotlib.pyplot as plt
13 | import numpy as np
14 | from scipy.constants import c, h
15 | from scipy.interpolate import interp1d
16 | eps_0 = 8.8541878128e-12
17 |
18 |
19 | class Light():
20 | """
21 | Parent light class. Implement support for adding pulses,
22 | saving the results of a propagation and plotting these
23 | results. Not suitable for light instantiation.
24 | """
25 | def __init__(self, waveguide, field_t_in):
26 | """
27 | Light is here defined by a time axis coming from a
28 | waveguide object, and a temporal waveform.
29 |
30 | Parameters
31 | ----------
32 | waveguide : Waveguide
33 | Waveguide object containing the material properties.
34 | field_t_in : array
35 | Array containing the complex temporal waveform of the
36 | initial analytical electric field.
37 | """
38 | self.waveguide = waveguide
39 | self.field_t_in = field_t_in
40 |
41 | def __add__(self, light):
42 | """
43 | Addition operator overload. Allow one to add pulses easily.
44 |
45 | Parameters
46 | ----------
47 | light : Light object
48 | Light with field to be added.
49 |
50 | Returns
51 | -------
52 | Light
53 | New Light object with field added.
54 | """
55 | tot_field = self.field_t_in + light.field_t_in
56 | return Light(self.waveguide, tot_field)
57 |
58 | def _set_propagation(self, z_save, freq, spectrum, waveform):
59 | """
60 | Store propagation results. Called from the solver module
61 | after finishing propagation.
62 | """
63 | self.z_save = z_save
64 | self.freq = freq
65 | self.spectrum = spectrum
66 | self.waveform = waveform
67 | self.wl, self.spectrum_wl = self._compute_equidistant_wl_spectrum()
68 |
69 | def _compute_equidistant_wl_spectrum(self):
70 | """
71 | Compute a properly normalized field representation in the wavelength
72 | domain with equidistantly spaced sampling points.
73 |
74 | Returns
75 | -------
76 | array
77 | Field in the wavelength domain.
78 | """
79 | wl = c/self.freq
80 | wl_ener = np.abs(self.freq*self.spectrum/np.sqrt(c))**2*wl
81 | wl_ener_interp = interp1d(wl, wl_ener, kind='linear')
82 | wl_eq = np.linspace(np.amin(wl), np.amax(wl), len(self.field_t_in))
83 | ener_wl_eq = wl_ener_interp(wl_eq)
84 | return wl_eq, np.sqrt(ener_wl_eq/wl_eq)
85 |
86 | def _set_dB(self):
87 | """
88 | Return a function to compute the dB representation of a field
89 | normalized to the input light spectrum.
90 | """
91 | if self.spectrum is not None:
92 | return lambda field: 20*np.log10(np.abs(field) + 1e-20) - np.amax(20*np.log10(np.abs(self.spectrum[0]) + 1e-20))
93 | else:
94 | pass
95 |
96 | def add_group_delay_dispersion(self, d2):
97 | """
98 | Add group delay dispersion (chirp) to the light field.
99 |
100 | Parameters
101 | ----------
102 | d2 : float
103 | Group delay dispersion
104 | """
105 | field_angle = np.angle(self.field_t_in)
106 | field_angle *= d2/2*self.waveguide.rel_omega**2
107 | self.field_t_in = np.abs(self.field_t_in)*np.exp(1j*field_angle)
108 |
109 | def add_shot_noise(self, seed=None):
110 | """
111 | Add shot noise to the pulse, useful for coherence study.
112 |
113 | Parameters
114 | ----------
115 | seed : int
116 | Seed for the random number generator for reproducibility.
117 | """
118 | if seed is not None:
119 | np.random.seed(seed)
120 |
121 | field_angle = np.angle(self.field_t_in)
122 |
123 | e_to_n_fac = eps_0*self.waveguide.n_eff_inter(c/self.pulse_wavelength)
124 | e_to_n_fac *= self.pulse_wavelength*self.waveguide.eff_area
125 | e_to_n_fac *= self.waveguide.delta_t/2/h
126 |
127 | photons_per_bin = e_to_n_fac*np.abs(self.field_t_in)**2
128 | photons_per_bin = np.random.poisson(photons_per_bin)
129 |
130 | noisy_field = np.sqrt(photons_per_bin/e_to_n_fac).astype(np.complex128)
131 | noisy_field *= np.exp(1j*field_angle)
132 | self.field_t_in = noisy_field
133 |
134 | def plot_propagation(self, savename=None):
135 | """
136 | Plot propagation results.
137 | """
138 | if self.spectrum is not None:
139 | self.dB = self._set_dB()
140 | ### Overall figure
141 | fig = plt.figure(figsize=(10,10))
142 | ax0 = plt.subplot2grid((3,2), (0, 0), rowspan=1)
143 | ax1 = plt.subplot2grid((3,2), (0, 1), rowspan=1)
144 | ax2 = plt.subplot2grid((3,2), (1, 0), rowspan=2, sharex=ax0)
145 | ax3 = plt.subplot2grid((3,2), (1, 1), rowspan=2, sharex=ax1)
146 |
147 | # Input and output spectrum
148 | ax0.plot(self.freq, self.dB(self.spectrum)[0], color='b')
149 | ax0.plot(self.freq, self.dB(self.spectrum)[-1], color='r')
150 | ax0.set_ylabel('Intensity [dB]')
151 | ax0.set_ylim(-100, 5)
152 |
153 | # Input and output pulse
154 | ax1.plot(self.waveguide.time, np.abs(self.waveform)[-1], color='r')
155 | ax1.plot(self.waveguide.time, np.abs(self.waveform)[0], color='b')
156 |
157 | # Spectrum color map
158 | extent = (np.amin(self.freq[self.freq>0]), np.max(self.freq), 0, self.waveguide.length)
159 | ax2.imshow(self.dB(self.spectrum[:, self.freq>0]), extent=extent, vmin=np.amax(self.dB(self.spectrum)) - 100.0,
160 | vmax=np.amax(self.dB(self.spectrum)), aspect='auto', origin='lower')
161 | ax2.set_xlabel('Frequency [Hz]')
162 | ax2.set_ylabel('Propagation distance [m]')
163 |
164 | # Pulse color map
165 | extent = (np.min(self.waveguide.time), np.max(self.waveguide.time), 0, self.waveguide.length)
166 | plt_waveform = np.abs(self.waveform)
167 | ax3.imshow(plt_waveform, extent=extent, vmin=np.amin(plt_waveform[-1]),
168 | vmax=np.amax(plt_waveform), aspect='auto', origin='lower')
169 | ax3.set_xlabel('Time [s]')
170 |
171 | plt.suptitle('Propagation results')
172 | fig.tight_layout()
173 | plt.show()
174 | if savename is not None:
175 | plt.savefig(savename)
176 |
177 | ### Spectrogram
178 | plt.figure(22222)
179 | specgram, _, _, _ = plt.specgram(self.waveform[-1],
180 | Fs=np.amax(self.freq)-np.amin(self.freq),
181 | Fc=(np.amax(self.freq)+np.amin(self.freq))/2,
182 | xextent=(np.amin(self.waveguide.time), np.amax(self.waveguide.time)),
183 | mode='magnitude',
184 | scale='dB',
185 | sides='twosided')
186 | plt.close(22222)
187 | plt.figure()
188 | ax0 = plt.subplot(221)
189 | plt.specgram(self.waveform[-1],
190 | Fs=np.amax(self.freq)-np.amin(self.freq),
191 | Fc=(np.amax(self.freq)+np.amin(self.freq))/2,
192 | xextent=(np.amin(self.waveguide.time), np.amax(self.waveguide.time)),
193 | mode='magnitude',
194 | scale='dB',
195 | vmax=20*np.log10(np.amax(specgram)),
196 | vmin=20*np.log10(np.amax(specgram))-100,
197 | sides='twosided')
198 | plt.ylabel('Frequency [Hz]')
199 |
200 | plt.subplot(222, sharey=ax0)
201 | plt.plot(20*np.log10(np.abs(self.spectrum[-1])) - np.amax(20*np.log10(np.abs(self.spectrum[-1]))), self.freq)
202 | plt.xlabel('Intensity [dB]')
203 | plt.xlim(5, -100)
204 | plt.ylim((np.amin(self.freq), np.amax(self.freq)))
205 |
206 | plt.subplot(223, sharex=ax0)
207 | plt.plot(self.waveguide.time, np.abs(self.waveform[-1])**2)
208 | plt.xlabel('Time [s]')
209 | plt.ylabel('Intensity [a.u.]')
210 | plt.xlim((np.amin(self.waveguide.time), np.amax(self.waveguide.time)))
211 | plt.tight_layout()
212 | if savename is not None:
213 | plt.savefig('spec_' + savename)
214 |
215 | else:
216 | pass
217 |
218 | def set_result_as_start(self, waveguide=None):
219 | """
220 | Set output field from propagation as initial field for a new
221 | propagation.
222 |
223 | Returns
224 | -------
225 | Light
226 | New Light object with final propagation result as input field.
227 | """
228 | if waveguide is None:
229 | waveguide = self.waveguide
230 | if self.spectrum is not None:
231 | field_t_in = self.waveform[-1]
232 | return Light(waveguide, field_t_in)
233 | else:
234 | pass
235 |
236 |
237 | class Sech(Light):
238 | """
239 | Class for a sech pulse.
240 | """
241 | def __init__(self, waveguide, pulse_duration, pulse_energy,
242 | pulse_wavelength, delay=0):
243 | """
244 | Construct a sech pulse.
245 |
246 | Parameters
247 | ----------
248 | waveguide : Waveguide
249 | Waveguide object containing the material properties.
250 | pulse_duration : float
251 | Pulse FWHM duration.
252 | pulse_energy : float
253 | Energy per pulse.
254 | pulse_wavelength : float
255 | Central wavelength of the pulse.
256 | delay: float, defaults to 0.
257 | Time offset of the pulse.
258 | """
259 | self.pulse_duration = pulse_duration
260 | self.pulse_energy = pulse_energy
261 | self.pulse_wavelength = pulse_wavelength
262 | self.waveguide = waveguide
263 | self.delay = delay
264 | self.field_t_in = self._compute_field()
265 |
266 | def _compute_field(self):
267 | """
268 | Instantiate electric field as a sech pulse.
269 |
270 | Returns
271 | -------
272 | array
273 | Analytical envelope of the electric field.
274 | """
275 | pulse_peak_power = 0.8813736*self.pulse_energy/self.pulse_duration
276 | field_t_in = np.sqrt(pulse_peak_power)/np.cosh(1.7627472*(self.waveguide.time - self.delay)/self.pulse_duration)\
277 | *np.exp(1j*(2*np.pi*c/self.pulse_wavelength - self.waveguide.center_omega)*(self.waveguide.time - self.delay))
278 | field_t_in /= np.sqrt(self.waveguide.n_eff_inter(c/self.pulse_wavelength)*eps_0*c*self.waveguide.eff_area/2)
279 | return field_t_in
280 |
281 |
282 | class Gaussian(Light):
283 | """
284 | Class for a Gaussian pulse.
285 | """
286 | def __init__(self, waveguide, pulse_duration, pulse_energy,
287 | pulse_wavelength, delay=0):
288 | """
289 | Construct a Gaussian pulse.
290 |
291 | Parameters
292 | ----------
293 | waveguide : Waveguide
294 | Waveguide object containing the material properties.
295 | pulse_duration : float
296 | Pulse FWHM duration.
297 | pulse_energy : float
298 | Energy per pulse.
299 | pulse_wavelength : float
300 | Central wavelength of the pulse.
301 | delay: float, defaults to 0.
302 | Time offset of the pulse.
303 | """
304 | self.pulse_duration = pulse_duration
305 | self.pulse_energy = pulse_energy
306 | self.pulse_wavelength = pulse_wavelength
307 | self.waveguide = waveguide
308 | self.delay = delay
309 | self.field_t_in = self._compute_field()
310 |
311 | def _compute_field(self):
312 | """
313 | Instantiate electric field as a gaussian pulse.
314 |
315 | Returns
316 | -------
317 | array
318 | Analytical envelope of the electric field.
319 | """
320 | amplitude = 2*self.pulse_energy*np.sqrt(8*np.log(2)/np.pi)
321 | amplitude /= self.waveguide.n_eff_inter(c/self.pulse_wavelength)
322 | amplitude /= eps_0*c*self.pulse_duration*self.waveguide.eff_area
323 | field_t_in = np.sqrt(amplitude)*np.exp(-4*np.log(2)*(self.waveguide.time - self.delay)**2/self.pulse_duration**2)\
324 | *np.exp(1j*(2*np.pi*c/self.pulse_wavelength - self.waveguide.center_omega)*(self.waveguide.time - self.delay))
325 | return field_t_in
326 |
327 |
328 | class Cw(Light):
329 | """
330 | Class for CW light.
331 | """
332 | def __init__(self, waveguide, average_power, wavelength):
333 | """
334 | Construct CW light.
335 |
336 | Parameters
337 | ----------
338 | waveguide : Waveguide
339 | Waveguide object containing the material properties.
340 | pulse_average_power : float
341 | Average power of the CW light.
342 | pulse_wavelength : float
343 | Central wavelength of the light.
344 | """
345 | self.pulse_average_power = average_power
346 | self.pulse_wavelength = wavelength
347 | self.waveguide = waveguide
348 | self.field_t_in = self._compute_field()
349 |
350 | def _compute_field(self):
351 | """
352 | Instantiate electric field as a continuous wave.
353 |
354 | Returns
355 | -------
356 | array
357 | Analytical envelope of the electric field.
358 | """
359 | field_t_in = np.exp(1j*(2*np.pi*c/self.pulse_wavelength - self.waveguide.center_omega)*self.waveguide.time)
360 | field_t_in *= np.sqrt(2*self.pulse_average_power/self.waveguide.n_eff_inter(c/self.pulse_wavelength)/eps_0/c/self.waveguide.eff_area)
361 | return field_t_in
362 |
363 |
364 | class Arbitrary(Light):
365 | """
366 | Class for arbitrary light waveform, specified in frequency domain.
367 | """
368 | def __init__(self, waveguide, pulse_frequency_axis, pulse_electric_field,
369 | pulse_energy):
370 | """
371 | Construct an arbitrary waveform from its frequency domain field.
372 |
373 | Parameters
374 | ----------
375 | waveguide : Waveguide
376 | Waveguide object containing the material properties.
377 | pulse_frequency_axis : array
378 | Frequency axis associated to the field.
379 | pulse_electric_field : array
380 | Analytical envelope representation of electric field in the frequency domain.
381 | pulse_energy : float
382 | Energy per pulse, used to normalize the field amplitude.
383 | """
384 | self.pulse_energy = pulse_energy
385 | self.data_freq = pulse_frequency_axis
386 | self.data_field = pulse_electric_field
387 | self.pulse_wavelength = self._compute_center_wavelength()
388 | self.waveguide = waveguide
389 | self.field_t_in = self._compute_field()
390 |
391 | def _compute_center_wavelength(self):
392 | """
393 | Compute the carrier wavelength of the pulse.
394 | """
395 | pw = np.sum(np.abs(self.data_field)*self.data_freq)
396 | pw /= np.sum(np.abs(self.data_field))
397 | return c/pw
398 |
399 | def _compute_field(self):
400 | """
401 | Instantiate input light as a user-specified waveform.
402 |
403 | Returns
404 | -------
405 | array
406 | Analytical envelope of the electric field.
407 | """
408 | field_interp = interp1d(self.data_freq, self.data_field, kind='cubic',
409 | bounds_error=False, fill_value=0.0)
410 | field_f_in = field_interp(self.waveguide.freq)
411 | field_t_in = np.fft.fftshift(np.fft.ifft(np.fft.ifftshift(field_f_in)))
412 | temp = np.sum(np.abs(field_t_in)**2)*self.waveguide.delta_t
413 | field_t_in *= np.sqrt(2*self.pulse_energy/(temp*self.waveguide.n_eff_inter(c/self.pulse_wavelength)*eps_0*c*self.waveguide.eff_area))
414 | return field_t_in
415 |
416 |
--------------------------------------------------------------------------------
/src/pychi/materials.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from inspect import signature
3 | from math import factorial
4 | import matplotlib.pyplot as plt
5 | import numpy as np
6 | from scipy.interpolate import interp1d
7 | from scipy.constants import c
8 | eps_0 = 8.8541878128e-12
9 |
10 | class Waveguide():
11 | """
12 | Waveguide class. Contains all material related information, i.e. the
13 | refractive index curve versus frequency, the Raman parameters, the
14 | nonlinear coefficients, the effective area and length. This object
15 | should be the first object instantiated, as the time/frequency axes of
16 | the simulation are derived here from the available refractive
17 | index data.
18 |
19 | Parameters
20 | ----------
21 | frequency : array
22 | Frequency axis on which the effective refractive index is given.
23 | n_eff : float, vector, array or callable
24 | Effective refractive index of the material.
25 | chi_2 : float, vector, array or callable
26 | Order 2 material nonlinearity.
27 | chi_3 : float, vector, array or callable
28 | Order 3 material nonlinearity.
29 | effective_area : float
30 | Effective area at the pump wavelength.
31 | length : float
32 | Length of the material.
33 | raman_fraction : float
34 | Fractional contribution of the Raman effect to the Kerr effect.
35 | The default is 0.18.
36 | raman_tau_1 : float
37 | Raman effect primary time scale. The default is 0.0122e-12.
38 | raman_tau_2 : float
39 | Raman effect secondary time scale. The default is 0.032e-12.
40 | t_pts : float, optional
41 | Number of points in the time and frequency axes, will be rounded
42 | to nearest higher power of 2. The default is 2**14.
43 | """
44 | def __init__(self, frequency, n_eff, chi_2, chi_3,
45 | effective_area, length, raman_fraction=0.18,
46 | raman_tau_1=0.0122e-12, raman_tau_2=0.032e-12,
47 | t_pts=2**14):
48 | self.z = 0
49 | self.t_pts = int(2**np.ceil(np.log2(t_pts)))
50 | self.length = length
51 | self.data_freq = frequency
52 | self.center_freq, self.freq = self._compute_frequency_axis()
53 | self.center_omega, self.omega, self.rel_omega = self._compute_omega_axis()
54 | self.time, self.delta_t = self._compute_time_axis()
55 |
56 | self.n_eff = n_eff
57 |
58 | self.chi_2 = chi_2
59 | self.chi_3 = chi_3
60 | self.eff_area = effective_area
61 |
62 | # Standard Raman response for fibers
63 | self.raman_fraction = raman_fraction
64 | self.raman_tau_1 = raman_tau_1
65 | self.raman_tau_2 = raman_tau_2
66 | self.raman_effect = self._compute_raman_effect()
67 |
68 | @property
69 | def n_eff(self):
70 | """Get the effective refractive index at position z."""
71 | return self._n_eff(self.z)
72 |
73 | @n_eff.setter
74 | def n_eff(self, n_eff):
75 | """
76 | Set the effective refractive index. Change any float, vector or
77 | array provided by the user into a z-callable function. A version
78 | interpolated in frequency is also kept for other operations.
79 | Beta coefficients are computed at this stage - they are
80 | solely used for plotting purpose.
81 | """
82 | self._n_eff = self._make_callable(n_eff)
83 | self.n_eff_inter = self._interpolate_n_eff()
84 | self.betas = self.compute_betas()
85 |
86 | @property
87 | def chi_2(self):
88 | """Get the quadratic nonlinear coefficient at position z."""
89 | return self._chi_2(self.z)
90 |
91 | @chi_2.setter
92 | def chi_2(self, chi_2):
93 | """
94 | Set the quadractic nonlinear coefficient. Change any float,
95 | vector or array provided by the user into a z-callable
96 | function.
97 | """
98 | self._chi_2 = self._make_callable(chi_2)
99 |
100 | @property
101 | def chi_3(self):
102 | """Get the cubic nonlinear coefficient at position z."""
103 | return self._chi_3(self.z)
104 |
105 | @chi_3.setter
106 | def chi_3(self, chi_3):
107 | """
108 | Set the quadractic nonlinear coefficient. Change any float,
109 | vector or array provided by the user into a z-callable
110 | function.
111 | """
112 | self._chi_3 = self._make_callable(chi_3)
113 |
114 | @property
115 | def k(self):
116 | """Get the wavevectors at position z."""
117 | return np.fft.fftshift(self.n_eff*self.omega/c)
118 |
119 | @property
120 | def rhs_prefactor(self):
121 | """Get the GNLSE right-hand-side prefactor at position z."""
122 | return -1j*np.fft.fftshift(self.omega/(2*self.n_eff*c))
123 |
124 | def _make_callable(self, var):
125 | """
126 | Transform an input vector, array, float or callable into a z-callable,
127 | allowing the user to provide z-dependant quantities.
128 |
129 | Note that a provided callable should have as arguments exactly at most
130 | 'z' and 'freq', e.g. var(z, freq), var(freq, z), var(z) or var(freq).
131 | A bit wonky, but couldn't figure out a better way to do that. Another
132 | alternative would be to implement derived classes with overwritten
133 | properties, which is not very elegant either. Actually found out that
134 | singledispatch from functools is probably the way to go here.
135 |
136 | Note that a provided array should have first dimension coinciding with
137 | the frequency axis given along the refractive index data. The second
138 | dimension is assumed to be evenly distributed along the whole length
139 | of the waveguide.
140 |
141 | Note that if a vector is provided it will be assumed that it describes
142 | a z dependent quantity, unless it has the same dimension as the
143 | frequency axis. Wavelength dependent only quantities can also be
144 | provided through callables.
145 |
146 | Parameters
147 | ----------
148 | var : float, vector, array or callable
149 | Some simulation parameter.
150 |
151 | Returns
152 | -------
153 | function
154 | A z-callable version of the provided variable.
155 | """
156 | # Case when the argument is callable
157 | if callable(var):
158 | return self._parse_callable(var)
159 | # Case when the argument is an array or a vector
160 | elif hasattr(var, '__len__'):
161 | return self._parse_array(var)
162 | # Otherwise (float)
163 | else:
164 | return lambda _: var
165 |
166 | def _parse_array(self, var):
167 | """
168 | Parse the correct arguments for a callable parameter.
169 |
170 | Parameters
171 | ----------
172 | var : array
173 | A one or two dimensional array representing z and/or frequency
174 | dependence of a parameter.
175 |
176 | Returns
177 | -------
178 | function
179 | A z-callable function.
180 | """
181 | # Case of an array
182 | if len(np.shape(var)) == 2:
183 | arr_inter = interp1d(self.data_freq, var.T, kind='cubic',
184 | bounds_error=False, fill_value='extrapolate')
185 | arr = arr_inter(self.freq).T
186 | z = np.linspace(0, self.length, np.shape(arr)[-1])
187 | arr_inter = interp1d(z, arr, kind='cubic', bounds_error=False,
188 | fill_value='extrapolate')
189 | return arr_inter
190 | # Case of a vector
191 | elif len(np.shape(var)) == 1:
192 | if len(var) == len(self.data_freq):
193 | arr_inter = interp1d(self.data_freq, var, kind='cubic',
194 | bounds_error=False, fill_value='extrapolate')
195 | arr = arr_inter(self.freq)
196 | return lambda _: arr
197 | else:
198 | z = np.linspace(0, self.length, len(var))
199 | var_inter = interp1d(z, var, kind='cubic', bounds_error=False,
200 | fill_value='extrapolate')
201 | return var_inter
202 | else:
203 | raise ValueError
204 |
205 | def _parse_callable(self, var):
206 | """
207 | Parse the correct arguments for a callable parameter.
208 |
209 | Parameters
210 | ----------
211 | var : callable
212 | A z or frequency (or both) dependent callable.
213 |
214 | Returns
215 | -------
216 | function
217 | A z-callable function.
218 | """
219 | # Get funtion signature
220 | z_flag = False
221 | freq_flag = False
222 | order_flag = False
223 | args = signature(var).parameters
224 | for arg in args:
225 | if arg == 'z':
226 | z_flag = True
227 | if arg == 'freq':
228 | freq_flag = True
229 | if z_flag:
230 | order_flag = True
231 |
232 | # Reorder arguments and evaluate the frequency axis
233 | if z_flag:
234 | if freq_flag:
235 | if order_flag:
236 | return lambda _: var(_, self.freq)
237 | else:
238 | return lambda _: var(self.freq, _)
239 | else:
240 | return var
241 | else:
242 | if freq_flag:
243 | return lambda _: var(self.freq)
244 | else:
245 | return lambda _: var
246 |
247 | def _compute_frequency_axis(self):
248 | """
249 | Define a frequency axis covering exactly the data range available.
250 | """
251 | min_freq = np.amin(self.data_freq)
252 | max_freq = np.amax(self.data_freq)
253 | center_freq = min_freq/2 + max_freq/2
254 | freq = np.linspace(min_freq, max_freq, self.t_pts)
255 | return center_freq, freq
256 |
257 | def _compute_omega_axis(self):
258 | """
259 | Compute the angular frequency axis associated to the frequency axis
260 | """
261 | center_omega = 2*np.pi*self.center_freq
262 | omega = 2*np.pi*self.freq
263 | rel_omega = omega - center_omega
264 | return center_omega, omega, rel_omega
265 |
266 | def _compute_time_axis(self):
267 | """
268 | Compute the time axis associated to the frequency axis
269 | """
270 | time = np.fft.fftshift(np.fft.fftfreq(self.t_pts, np.mean(np.diff(self.freq))))
271 | delta_t = np.mean(np.diff(time))
272 | return time, delta_t
273 |
274 | def _interpolate_n_eff(self):
275 | """
276 | Interpolate the refractive index data on the simulation frequency axis
277 | """
278 | n_eff_inter = interp1d(self.freq, self.n_eff, kind='cubic',
279 | bounds_error=False, fill_value='extrapolate')
280 | return n_eff_inter
281 |
282 | def _compute_raman_effect(self):
283 | """
284 | Compute the Raman term for the simulation frequency axis
285 | """
286 | raman_time = (self.raman_tau_1**2 + self.raman_tau_2**2)
287 | raman_time = raman_time/self.raman_tau_1/self.raman_tau_2**2
288 | raman_time *= np.exp(-np.abs(self.time)/self.raman_tau_2)*np.sin(self.time/self.raman_tau_1)
289 | raman_time[self.time < 0] = 0
290 | raman_effect = np.conjugate(self.t_pts*np.fft.ifft(np.fft.fftshift(raman_time)))
291 | raman_effect *= self.delta_t*self.raman_fraction
292 | return raman_effect
293 |
294 | def compute_betas(self, wavelength=None, order=6):
295 | """
296 | Compute beta coefficients at a given wavelength and order.
297 |
298 | Parameters
299 | ----------
300 | wavelength : float, optional
301 | Wavelength at which the beta coefficients are computed. The default is
302 | the center of the simulation axis.
303 | order : int, optional
304 | Highest order of the beta coefficients to be computed. The default is 6.
305 |
306 | Returns
307 | -------
308 | beta : array
309 | Beta coefficients of the material at the given wavelength.
310 | """
311 | if wavelength is None:
312 | center_omega = self.center_omega
313 | else:
314 | center_omega = 2*np.pi*c/wavelength
315 |
316 | om = 2*np.pi*self.freq
317 | dk = np.real(self.n_eff)*om/c
318 | b_inter = interp1d(om, dk, kind='cubic')
319 | beta = np.zeros(order+1)
320 | beta[0] = b_inter(center_omega)
321 | for i in np.arange(order):
322 | dk = np.diff(dk)
323 | dom = np.diff(om)
324 | om = om[:-1] + dom/2
325 | der = dk/dom
326 | der_inter = interp1d(om, der, kind='cubic')
327 | beta[i+1] = der_inter(center_omega)
328 | dk = der
329 | return beta
330 |
331 | def set_betas(self, betas, wavelength):
332 | """
333 | Convenience only. Allow the use to provide the beta coefficients
334 | instead of n_eff. Should be avoided.
335 | """
336 | rel_om = self.omega - 2*np.pi*c/wavelength
337 | n = np.ones(self.t_pts)*betas[0]
338 | factorial = 1
339 | for i, b in enumerate(betas[1:]):
340 | factorial *= (i+1)
341 | n += b*rel_om**(i+1)/factorial
342 | n *= c/self.omega
343 | self.n_eff = n
344 |
345 | def set_n2(self, n2, wavelength=None):
346 | """
347 | Convenience only. Allow the user to give the nonlinear index instead
348 | of chi3. Overwrite the initialized chi3 value accordingly.
349 |
350 | Parameters
351 | ----------
352 | n2 : float
353 | Nonlinear index.
354 | """
355 | if wavelength is None:
356 | freq = self.center_freq
357 | else:
358 | freq = c/wavelength
359 | self.chi_3 = 4*n2*eps_0*c*self.n_eff_inter(freq)**2/3
360 |
361 | def set_gamma(self, gamma, wavelength=None):
362 | """
363 | Convenience only. Allow the user to give the nonlinear coefficient instead
364 | of chi3. Overwrite the initialized chi3 value accordingly.
365 |
366 | Parameters
367 | ----------
368 | gamma : float
369 | Nonlinear coefficient.
370 | """
371 | if wavelength is None:
372 | freq = self.center_freq
373 | else:
374 | freq = c/wavelength
375 | self.chi_3 = 2*self.n_eff_inter(freq)**2*c**2*eps_0*gamma*self.eff_area/3/np.pi/freq
376 |
377 | def plot_refractive_index(self, savename=None):
378 | """
379 | Plot refractive index
380 | """
381 | k = self.n_eff*2*np.pi*self.freq/c
382 | inverse_group_velocity = np.gradient(k, 2*np.pi*self.freq)
383 | group_velocity_dispersion = np.gradient(inverse_group_velocity, 2*np.pi*self.freq)
384 |
385 | fig, axs = plt.subplots(3)
386 | axs[0].plot(self.freq, self.n_eff)
387 | axs[0].set_ylabel('Refractive index')
388 | axs[1].plot(self.freq, inverse_group_velocity)
389 | axs[1].set_ylabel('IGV [s/m]')
390 | axs[2].plot(self.freq, group_velocity_dispersion)
391 | axs[2].set_ylabel('GVD [s^2/m]')
392 | axs[2].set_xlabel('Frequency [Hz]')
393 | fig.tight_layout()
394 |
--------------------------------------------------------------------------------
/src/pychi/solvers.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Fri Feb 18 17:54:20 2022
4 |
5 | @author: voumardt
6 | """
7 | import matplotlib.pyplot as plt
8 | import numba
9 | import numpy as np
10 | from scipy.constants import c
11 | import time as timing
12 |
13 |
14 | class Solver():
15 | def __init__(self, model, z_pts=500, local_error=0.00001, adaptive_factor=1.1,
16 | max_dz=None, method=None, breakpoints=[]):
17 | """
18 | Solver class. Provides a stepper which performs integration of the PDE
19 | as well as error control and results saving.
20 |
21 | Parameters
22 | ----------
23 | model : Model object
24 | Physical model of the problem to be integrated.
25 | z_pts : int, optional
26 | Number of results to keep along the propagation axis. The default is 500.
27 | local_error : float, optional
28 | Tolerated local error. The default is 0.00001.
29 | adaptive_factor : float, optional
30 | Adaptive factor for the step size control. Bigger values lead to
31 | more aggressive step size control. The default is 1.1.
32 | max_dz : float, optional
33 | Maximum step size allowed. Particularly useful when simulating
34 | quasi-phase matched structures. The default is None.
35 | method: string
36 | Method used for integration. Can be RK4IP, ERK4IP or DP5IP.
37 | Default is DP5IP.
38 | breakpoints: array
39 | This array contains z coordinates where the solver will be forced
40 | to compute a result. Useful for poled structures, to avoid having
41 | a step larger than the poling. The default is an empty array.
42 | """
43 | self.model = model
44 | self.z_pts = z_pts
45 | self.local_error = local_error
46 | self.adaptive_factor = adaptive_factor
47 | self.max_dz = max_dz
48 | self.z_save = np.linspace(0, self.model.waveguide.length, self.z_pts)
49 | self.method_name = self._set_method_name(method)
50 | self.breakpoints = breakpoints
51 | self.stepsize_save = []
52 |
53 | def _set_method_name(self, method):
54 | """
55 | Helper function to choose an appropriate solver. If a method is not
56 | provided by the user, it will look into the model used to see if
57 | there is a recommended solver. Otherwise, defaults to the model that
58 | should be mostly used, i.e. DP5IP.
59 |
60 | Parameters
61 | ----------
62 | method : string
63 | Name of the solver.
64 |
65 | Returns
66 | -------
67 | string
68 | Name of the solver.
69 | """
70 | if method is None:
71 | if hasattr(self.model, '_recommended_solver'):
72 | return self.model._recommended_solver
73 | else:
74 | return 'DP5IP'
75 | else:
76 | return method
77 |
78 | def _compute_error(self, field_1, field_2):
79 | """
80 | Error estimation for adaptive step size
81 |
82 | Parameters
83 | ----------
84 | field_1 : array
85 | Reference field.
86 | field_2 : array
87 | Test field.
88 |
89 | Returns
90 | -------
91 | float
92 | Error estimate between the two fields.
93 | """
94 | return numbanorm(field_1 - field_2)/numbanorm(field_1)
95 |
96 | def _dormand_prince_step(self, field, dz):
97 | """
98 | Dormand Prince order 5(4) adaptive scheme in the interaction picture. This
99 | new stepper uses the interaction picture in an embedded scheme of order 5.
100 | Tests have shown it to be up to four times faster than RK4IP.
101 |
102 | Parameters
103 | ----------
104 | field : array
105 | Current field.
106 | dz : float
107 | Current step size.
108 |
109 | Returns
110 | -------
111 | array
112 | New field estimate.
113 |
114 | float
115 | Error estimate.
116 | """
117 | if self._k_7 is None:
118 | k_1 = dz*self.model.dispersion_step(self.model.nonlinear_term(field), dz)
119 | else:
120 | k_1 = self.model.dispersion_step(self._k_7, dz)
121 | a_int = self.model.dispersion_step(field, dz)
122 | k_2 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(a_int + k_1/5, -4*dz/5)), 4*dz/5)
123 | k_3 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(a_int + 3*k_1/40 + 9*k_2/40, -7*dz/10)), 7*dz/10)
124 | k_4 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(a_int + 44*k_1/45 - 56*k_2/15 + 32*k_3/9, -dz/5)), dz/5)
125 | k_5 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(a_int + 19372*k_1/6561 - 25360*k_2/2187 + 64448*k_3/6561 - 212*k_4/729, -dz/9)), dz/9)
126 | k_6 = dz*self.model.nonlinear_term(a_int + 9017*k_1/3168 - 355*k_2/33 + 46732*k_3/5247 + 49*k_4/176 - 5103*k_5/18656)
127 | sol_5 = a_int + 35*k_1/384 + 500*k_3/1113 + 125*k_4/192 - 2187*k_5/6784 + 11*k_6/84
128 | self._k_7 = dz*self.model.nonlinear_term(sol_5)
129 | sol_4 = a_int + 5179*k_1/57600 + 7571*k_3/16695 + 393*k_4/640 - 92097*k_5/339200 + 187*k_6/2100 + self._k_7/40
130 | error = self._compute_error(sol_5, sol_4)
131 | return sol_5, error
132 |
133 | def _rk546m(self, field, dz):
134 | """
135 | Some other Dormand-Prince method that has one less step but does not
136 | leverage the interaction picture and does not have the FSAL property.
137 | Usually worse than the other dormand-prince method.
138 | References:
139 | DOI: 10.1016/0771-050X(80)90013-3
140 |
141 | Parameters
142 | ----------
143 | field : array
144 | Current field.
145 | dz : float
146 | Current step size.
147 |
148 | Returns
149 | -------
150 | array
151 | New field estimate.
152 |
153 | float
154 | Error estimate.
155 | """
156 | k_1 = dz*self.model.nonlinear_term(field)
157 | k_2 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(field + k_1/5, dz/5)), -dz/5)
158 | k_3 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(field + 3*k_1/40 + 9*k_2/40, 3*dz/10)), -3*dz/10)
159 | k_4 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(field + 3*k_1/10 - 9*k_2/10 + 6*k_3/5, 3*dz/5)), -3*dz/5)
160 | k_5 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(field + 226*k_1/729 - 25*k_2/27 + 880*k_3/729 + 55*k_4/729, 2*dz/3)), -2*dz/3)
161 | k_6 = dz*self.model.dispersion_step(self.model.nonlinear_term(self.model.dispersion_step(field - 181*k_1/270 + 5*k_2/2 - 266*k_3/297 - 91*k_4/27 + 189*k_5/55, dz)), -dz)
162 | sol_5 = self.model.dispersion_step(field + 19*k_1/216 + 1000*k_3/2079 - 125*k_4/216 + 81*k_5/88 + 5*k_6/56, dz)
163 | sol_4 = self.model.dispersion_step(field + 31*k_1/540 + 190*k_3/297 - 145*k_4/108 + 351*k_5/220 + k_6/20, dz)
164 | error = self._compute_error(sol_5, sol_4)
165 | return sol_5, error
166 |
167 | def _adams_bashforth54_step(self, field, dz):
168 | """To be implemented"""
169 | pass
170 |
171 | def _rk4ip_single_step(self, field, dz):
172 | """
173 | Runge-Kutta order 4 step in the interaction picture (RK4IP)
174 |
175 | Parameters
176 | ----------
177 | field : array
178 | Current field.
179 | dz : float
180 | Current step size.
181 |
182 | Returns
183 | -------
184 | array
185 | New field estimate.
186 | """
187 | dispersion_op = numbaexp(-1j*self.model.waveguide.k*dz/2)
188 | a_int = dispersion_op*field
189 | k_1 = dz*dispersion_op*self.model.nonlinear_term(field)
190 | k_2 = dz*self.model.nonlinear_term(a_int + k_1/2)
191 | k_3 = dz*self.model.nonlinear_term(a_int + k_2/2)
192 | k_4 = dz*self.model.nonlinear_term(dispersion_op*(a_int + k_3))
193 | return dispersion_op*(a_int + k_1/6 + k_2/3 + k_3/3) + k_4/6
194 |
195 | def _rk4ip_step(self, field, dz):
196 | """
197 | Runge-Kutta order 4 adaptive scheme in the interaction picture (RK4IP)
198 | with step doubling and combining. Provided for comparison but slower
199 | than the dormand-prince method.
200 | References:
201 | DOI: 10.1109/JLT.2007.909373
202 | DOI: 10.1109/JLT.2009.2021538
203 |
204 | Parameters
205 | ----------
206 | field : array
207 | Current field.
208 | dz : float
209 | Current step size.
210 |
211 | Returns
212 | -------
213 | array
214 | New field estimate.
215 |
216 | float
217 | Error estimate.
218 | """
219 | sol_single = self._rk4ip_single_step(field, dz)
220 | sol_double = self._rk4ip_single_step(field, dz/2)
221 | sol_double = self._rk4ip_single_step(sol_double, dz/2)
222 | error = self._compute_error(sol_double, sol_single)
223 | sol_5 = (sol_double*16 - sol_single)/15
224 | return sol_5, error
225 |
226 | def _erk4ip_step(self, field, dz):
227 | """
228 | Embedded Runge-Kutta order 4(3) adaptive scheme in the interaction
229 | picture (ERK4IP). Can be faster than DP5IP if accuracy is irrelevant,
230 | for example in SPM only cases. Otherwise, DP5IP performs better.
231 | References:
232 | DOI: 10.1016/j.cpc.2012.12.020
233 |
234 | Parameters
235 | ----------
236 | field : array
237 | Current field.
238 | dz : float
239 | Current step size.
240 |
241 | Returns
242 | -------
243 | array
244 | New field estimate.
245 |
246 | float
247 | Error estimate.
248 | """
249 | dispersion_op = numbaexp(-1j*self.model.waveguide.k*dz/2)
250 | a_int = dispersion_op*field
251 | if self._k_5 is None:
252 | k_1 = dz*dispersion_op*self.model.nonlinear_term(field)
253 | else:
254 | k_1 = dispersion_op*self._k_5
255 | k_2 = dz*self.model.nonlinear_term(a_int + k_1/2)
256 | k_3 = dz*self.model.nonlinear_term(a_int + k_2/2)
257 | k_4 = dz*self.model.nonlinear_term(dispersion_op*(a_int + k_3))
258 | beta = dispersion_op*(a_int + k_1/6 + k_2/3 + k_3/3)
259 | sol_4 = beta + k_4/6
260 | self._k_5 = dz*self.model.nonlinear_term(sol_4)
261 | sol_3 = beta + k_4/15 + self._k_5/10
262 | error = self._compute_error(sol_4, sol_3)
263 | return sol_4, error
264 |
265 | def _integrate_to_z(self, z):
266 | """
267 | Integrate to z with adaptive step size.
268 |
269 | Parameters
270 | -------
271 | z : float
272 | Target propagation length.
273 | """
274 | while self.stock_z < z:
275 | # Actuate position inside the waveguide
276 | self.model.waveguide.z = self.stock_z
277 |
278 | # Check for forcing breakpoints
279 | if (len(self.breakpoints) != 0 and (self.stock_z + self.dz > self.breakpoints[0])):
280 |
281 | # Step to breakpoint
282 | dz = self.breakpoints[0] - self.stock_z + 1e-20
283 | vec_eval, _ = self.step(self.stock_vec, dz)
284 |
285 | # Remove breakpoint
286 | self.breakpoints = self.breakpoints[1:]
287 |
288 | # Update z pos and field
289 | self.stock_z += dz
290 | self.stock_vec = vec_eval
291 | self.stepsize_save = np.append(self.stepsize_save, dz)
292 |
293 | else:
294 |
295 | # Step of dz
296 | vec_eval, error = self.step(self.stock_vec, self.dz)
297 |
298 | # Error control
299 | if error >= 2*self.local_error:
300 | self.dz /= 2
301 | print('Discarded')
302 | if self.method_name == 'DP5IP':
303 | self._k_7 = None
304 | if self.method_name == 'ERK4IP':
305 | self._k_5 = None
306 | continue
307 | elif self.local_error <= error < 2*self.local_error:
308 | self.stock_z += self.dz
309 | self.stepsize_save = np.append(self.stepsize_save, self.dz)
310 | self.dz /= self.adaptive_factor
311 | elif 0.5*self.local_error <= error < self.local_error:
312 | self.stock_z += self.dz
313 | self.stepsize_save = np.append(self.stepsize_save, self.dz)
314 | else:
315 | self.stock_z += self.dz
316 | self.stepsize_save = np.append(self.stepsize_save, self.dz)
317 | if self.max_dz is None or self.dz*self.adaptive_factor < self.max_dz:
318 | self.dz *= self.adaptive_factor
319 | self.stock_vec = vec_eval
320 |
321 | def solve(self):
322 | """
323 | Integrate over waveguide length with adaptive step size
324 | """
325 | # Initialization
326 | self.spectrum = np.zeros((self.z_pts, self.model.waveguide.t_pts), dtype='complex128')
327 | self.dz = np.mean(np.diff(self.z_save))*np.sqrt(np.sqrt(self.local_error))
328 | self.stock_z = 0
329 | self.stock_vec = np.fft.fft(self.model.light.field_t_in)
330 | if self.method_name == 'DP5IP':
331 | self._k_7 = None
332 | self.step = self._dormand_prince_step
333 | elif self.method_name == 'ERK4IP':
334 | self._k_5 = None
335 | self.step = self._erk4ip_step
336 | elif self.method_name == 'RK4IP':
337 | self.step = self._rk4ip_step
338 | elif self.method_name == 'RK546M':
339 | self.step = self._rk546m
340 | timer = timing.perf_counter()
341 |
342 | # Total integration
343 | for i, z in enumerate(self.z_save):
344 | print('z: {}/{}'.format(i+1, self.z_pts))
345 |
346 | # Integrate over dz
347 | self._integrate_to_z(z)
348 |
349 | # Save spectrum
350 | self.spectrum[i, :] = np.fft.fftshift(self.stock_vec)\
351 | *numbaexp(1j*(self.model.waveguide.betas[0] + self.model.waveguide.betas[1]*self.model.waveguide.rel_omega)*self.stock_z)
352 |
353 | # Save waveform
354 | print(f"{timing.perf_counter() - timer} seconds for integration.")
355 | self.waveform = np.fft.ifft(np.fft.ifftshift(self.spectrum, axes=1), axis=1)
356 | self.model.light._set_propagation(self.z_save, self.model.waveguide.freq, self.spectrum, self.waveform)
357 |
358 | def plot_stepsize(self):
359 | """
360 | Plot the evolution of the stepsize against the position in the waveguide
361 | """
362 | plt.figure()
363 | plt.plot(np.cumsum(self.stepsize_save), self.stepsize_save)
364 | plt.xlabel('Distance [m]')
365 | plt.ylabel('Step size [m]')
366 |
367 |
368 | """
369 | Optimized functions
370 | """
371 | ### Numba exponential
372 | @numba.njit([numba.complex128[:](numba.complex128[:]),numba.complex64[:](numba.complex64[:])])
373 | def numbaexp(x):
374 | return np.exp(x)
375 |
376 | ### Numba norm
377 | @numba.njit([numba.float64(numba.complex128[:])])
378 | def numbanorm(field):
379 | return np.linalg.norm(field)
380 |
--------------------------------------------------------------------------------