diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 744705d..c9b9f8f 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -10,6 +10,28 @@ on: - develop jobs: + python-style-checks: + runs-on: ubuntu-18.04 + steps: + - name: Check out repository + uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + + - name: Upgrade pip + run: python3 -m pip install --upgrade pip + + - name: Install dependencies + run: pip install -qU pydocstyle flake8 + + - name: Check docstrings + run: pydocstyle --convention=numpy optbeam + + - name: Lint with flake8 + run: flake8 optbeam --count --show-source --statistics build-and-deploy-pages: runs-on: ubuntu-18.04 steps: @@ -28,8 +50,9 @@ jobs: run: | pip install -q -r docs/requirements.txt - - name: Build docs + - name: Build API and docs run: | + # sphinx-apidoc -fPM -o docs/source/api optbeam sphinx-build -W --keep-going -b html -d docs/_build/doctrees docs/source docs/_build/html mv -v docs/_build/html public diff --git a/.gitignore b/.gitignore index e925824..b5356b0 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,7 @@ coverage.xml # Sphinx documentation docs/_build/ +#docs/source/api/ # PyBuilder target/ diff --git a/docs/Makefile b/docs/Makefile index adf61f4..a59fed3 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -20,5 +20,5 @@ help: @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -apidocs: - sphinx-apidoc -f -o source/api ../optbeam +# apidocs: + # sphinx-apidoc -fPM -o source/api ../optbeam diff --git a/docs/source/api/optbeam._2d.rst b/docs/source/api/optbeam._2d.rst new file mode 100644 index 0000000..179d64d --- /dev/null +++ b/docs/source/api/optbeam._2d.rst @@ -0,0 +1,20 @@ +optbeam.\_2d package +==================== + +.. automodule:: optbeam._2d + :members: + :undoc-members: + :show-inheritance: + :private-members: + + +optbeam.\_2d.beams module +------------------------- + +.. automodule:: optbeam._2d.beams + :members: + :undoc-members: + :show-inheritance: + :private-members: + + diff --git a/docs/source/api/optbeam._3d.rst b/docs/source/api/optbeam._3d.rst new file mode 100644 index 0000000..0c6fdbc --- /dev/null +++ b/docs/source/api/optbeam._3d.rst @@ -0,0 +1,19 @@ +optbeam.\_3d package +==================== + +.. automodule:: optbeam._3d + :members: + :undoc-members: + :show-inheritance: + :private-members: + + +optbeam.\_3d.beams module +------------------------- + +.. automodule:: optbeam._3d.beams + :members: + :undoc-members: + :show-inheritance: + :private-members: + diff --git a/docs/source/api/optbeam.rst b/docs/source/api/optbeam.rst new file mode 100644 index 0000000..c13ba4c --- /dev/null +++ b/docs/source/api/optbeam.rst @@ -0,0 +1,17 @@ +optbeam package +=============== + +.. automodule:: optbeam + :members: + :undoc-members: + :show-inheritance: + :private-members: + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + optbeam._2d + optbeam._3d diff --git a/docs/source/conf.py b/docs/source/conf.py index 3105d03..ad87eb3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -47,7 +47,10 @@ 'cython', ] -autodoc_member_order = 'groupwise' +autodoc_default_options = { + 'private-members': False, + 'member-order': 'groupwise', +} # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/source/index.md b/docs/source/index.md index a40533a..41b811f 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -5,6 +5,14 @@ :relative-images: ``` +```{toctree} +--- +caption: API Reference +maxdepth: 1 +--- + +api/optbeam +``` ```{toctree} --- diff --git a/optbeam/_2d/beams.py b/optbeam/_2d/beams.py index d4a8898..2f724b7 100644 --- a/optbeam/_2d/beams.py +++ b/optbeam/_2d/beams.py @@ -1,3 +1,4 @@ +"""Contains classes for beams in 2d.""" import math import sys @@ -74,7 +75,30 @@ def __init__(self, x, params, called=False): super().__init__(x, params, called) def profile(self, r): - """...""" + r"""Field amplitude function. + + Plane wave decomposition: calculate field amplitude at light source + position if not coinciding with beam waist. + + Parameters + ---------- + r : type + Description of parameter `r`. + + Returns + ------- + type + Description of returned object. + + Notes + ----- + The beam profile at waist is given by + + .. math:: + + \psi_\text{G} (x, z=0) = \exp\biggl[-\Bigl(\frac{x}{w_0} \Bigr)^2\biggr] + + """ # beam profile distribution (field amplitude) at the waist of the beam if self.x == 0: return self._norm * _exp(-(r.y / self._W_y)**2) @@ -82,7 +106,25 @@ def profile(self, r): return super().profile(r) def spectrum(self, k_y): - """Spectrum amplitude function, f.""" + r"""Gauss spectrum amplitude function, f. + + Parameters + ---------- + k_y : type + Description of parameter `k_y`. + + Returns + ------- + type + Description of returned object. + + Notes + ----- + .. math:: + f_\text{G} (k_x) = \frac{w_0}{2 \sqrt{\pi}} \ + \exp\biggl[-\Bigl(\frac{k_x w_0}{2} \Bigr)^2 \biggr] + + """ return self._f_Gauss(k_y, self._W_y) def _f_Gauss(self, k_y, W_y): @@ -91,7 +133,26 @@ def _f_Gauss(self, k_y, W_y): class IncAiry2d(Beam2dCartesian): - """2d incomplete Airy beam.""" + """2d incomplete Airy beam. + + The implementation is based on [2]_. + + Parameters + ---------- + x : type + Description of parameter `x`. + params : type + Description of parameter `params`. + called : type + Description of parameter `called` (the default is False). + + References + ---------- + .. [2] Ring, J D, Howls, C J, Dennis, M R: Incomplete Airy beams: + finite energy from a sharp spectral cutoff , Optics Letters 38(10), + OSA, 1639–1641, May 2013. + + """ def __init__(self, x, params, called=False): """...""" @@ -101,7 +162,30 @@ def __init__(self, x, params, called=False): super().__init__(x, params, called) def profile(self, r): - """...""" + r"""Beam profile, psi. + + Parameters + ---------- + r : type + Description of parameter `r`. + + Returns + ------- + type + Description of returned object. + + Notes + ----- + The beam profile at waist is defined by the incomplete Airy function, + see [2]_ + + .. math:: + + \psi^\text{Airy}_{M,W}(x, z=0) = \int_{M-W}^{M+W}\mathrm{d}\xi\, \ + \mathrm{exp}\left[\mathrm{i}\left(\frac{1}{3} \xi^3 + \ + \xi \frac{x}{w_0}\right)\right] + + """ if self.x == 0: # adjust integration boundaries self._a = self._M-self._W @@ -110,7 +194,32 @@ def profile(self, r): return super().profile(r) def spectrum(self, k_y): - """...""" + r"""Spectrum amplitude function, f. + + Parameters + ---------- + k_y : type + Description of parameter `k_y`. + + Returns + ------- + f_Airy: complex + Spectrum amplitude function + + Notes + ----- + .. math:: + + \begin{align*} + f^\text{Airy}_{M,W}(k_x) &= \frac{1}{2 \pi} \int_{-\infty}^\infty\mathrm{d}x\, \psi^\text{Airy}_{M,W}(x, z=0) \exp(-\mathrm{i}k_x x)\\ + &= \int_{M-W}^{M+W}\mathrm{d}\xi\, \exp\Bigl(\mathrm{i}\frac{1}{3}\xi^3 \Bigr) \delta\Bigl(\frac{\xi}{w_0} -k_x\Bigr)\\ + &=\begin{cases} + w_0 \exp\Bigl[\mathrm{i} \frac{1}{3} \bigl(w_0k_x \bigr)^3\Bigr] & M-W < w_0k_x >> LGbeam = LaguerreGauss3d(x=x, params=params) + >>> LGbeam.profile(r) + >>> LGbeam.spectrum(sin_theta, theta, phi) - Usage: - LGbeam = LaguerreGauss3d(x=x, params=params) - LGbeam.profile(r) - LGbeam.spectrum(sin_theta, theta, phi) """ def __init__(self, x, params, called=False): @@ -191,14 +206,61 @@ def __init__(self, x, params, called=False): self._norm = 4 * math.pi / (self._W_y**2) def profile(self, r): - """...""" + r"""Beam profile, psi. + + Parameters + ---------- + r : type + Description of parameter `r`. + + Returns + ------- + complex + Description of returned object. + + Notes + ----- + .. math:: + + \psi_\text{LG}(x,y,z) = k^2 \int_0^{\pi/2}\mathrm{d}\theta\int_0^{2\pi}\mathrm{d}\phi\, \sin{\theta}\cos{\theta}\,f_\text{LG}(\theta, \phi) \exp\bigl[\mathrm{i}k \bigl(x \cos{\theta} + y\sin{\theta}\sin{\phi} - z \sin{\theta}\cos{\phi}\bigr)\bigr] + + """ if self.x == 0 and self._m == 0: return self._norm * _exp(-((r.y**2 + r.z**2) / self._W_y**2)) else: return super().profile(r) def spectrum(self, sin_theta, theta, phi): - """Spectrum amplitude function, f.""" + r"""Spectrum amplitude function, f. + + Parameters + ---------- + sin_theta : type + Description of parameter `sin_theta`. + theta : type + Description of parameter `theta`. + phi : type + Description of parameter `phi`. + + Returns + ------- + complex + Description of returned object. + + Notes + ----- + The implementation is based on [1]_. + + The spectrum amplitude is of the form + + .. math:: + + f_\text{LG}(\theta,\phi) = \theta^{|m|} \ + \exp\biggl[-\Bigl(\frac{kw_0}{2} \ + \sin\theta\Bigr)^2 \ + \biggr] \exp(\mathrm{i} m \phi) + + """ if self._m == 0: return self._f_Gauss_spherical(sin_theta, self._W_y, self._k) else: diff --git a/optbeam/__init__.py b/optbeam/__init__.py index bcb6130..184a28a 100644 --- a/optbeam/__init__.py +++ b/optbeam/__init__.py @@ -1,3 +1,21 @@ +"""optbeam: exact and fast calculation of optical beam profiles. + +Copyright (c) 2021 Daniel Kotik, Jörg B. Götte. +All rights reserved. + +optbeam is a Cython-based package for fast calculation of exact field +configurations of various optical beams in two and three dimensions. +Intended for use together with `PyMeep`_. + +.. _PyMeep: https://meep.readthedocs.io/en/latest/ + +Classes +------- +* :class:`._2d.beams.Gauss2d` : 2d Gaussian beam +* :class:`._2d.beams.IncAiry2d` : 2d incomplete Airy beam +* :class:`._3d.beams.LaguerreGauss3d` : 3d vortex beam + +""" __version__ = "2.1.2" @@ -10,11 +28,39 @@ def critical(n1, n2): - """Calculate critical angle in degrees.""" + """Calculate critical angle. + + Parameters + ---------- + n1 : float + Index of refraction of the incident medium. + n2 : float + Index of refraction of the refractive medium. + + Returns + ------- + float + Angle in degrees. + + """ assert n1 > n2, "\nWarning: Critical angle is not defined, since n1 <= n2!" return _degrees(_asin(n2/n1)) def brewster(n1, n2): - """Calculate Brewster angle in degrees.""" + """Calculate Brewster angle. + + Parameters + ---------- + n1 : float + Index of refraction of the incident medium. + n2 : float + Index of refraction of the refractive medium. + + Returns + ------- + float + Angle in degrees. + + """ return _degrees(_atan(n2/n1))