Name | Helmi-FEM JSON |
Version |
0.2.0
JSON |
| download |
home_page | |
Summary | Finite element method for solving the electromagnetic Helmholtz equation. |
upload_time | 2023-02-09 16:41:29 |
maintainer | Vincent R. |
docs_url | None |
author | Vincent R. |
requires_python | >=3.8 |
license | BSD 3-Clause License Copyright (c) 2023, Vincent R Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
keywords |
helmholtz equation
finite-element analysis
finite-element method
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Helmi_FEM
An open-source implementation of the Helmholtz equation for finite element analysis of electromagnetic wave propagation and scattering.
Based on [scikit-fem](https://scikit-fem.readthedocs.io/en/latest/index.html) for finite element assembly and on [SciPy](https://scipy.org/), [NumPy](https://numpy.org/), and [matplotlib](https://matplotlib.org/) for solving, processing and plotting.
## Installation:
```python
pip install git+https://github.com/Vinc0110/Helmi_FEM.git
```
See the example workflow below and additional examples in the subfolder.
![Waveguide fields](./examples/waveguide/waveguide.png)
## Features:
- Supports complex-valued parameters
- TE and TM polarization
- Dirichlet and third-order boundary conditions (Neumann, freespace, absorbing)
- Near-field to far-field transformation
# Workflow
## 1. Create or load a mesh of the simulation domain
Use the mesh constructors of `skfem.mesh` for simple shapes such as rectangles, circles, or L-shapes.
Use *gmsh* or other software for complex shapes.
https://scikit-fem.readthedocs.io/en/latest/api.html#module-skfem.mesh
http://gmsh.info/
```python
import skfem
import numpy as np
# create a rectangular mesh with skfem:
x_pts = np.linspace(0, 100, 101)
y_pts = np.linspace(-5, 5, 21)
mesh = skfem.MeshTri.init_tensor(x_pts, y_pts)
mesh = mesh.with_subdomains({'air': lambda x: x[0] < 50,
'plastic': lambda x: x[0] >= 50})
mesh = mesh.with_boundaries({'bound_xmin': lambda x: np.isclose(x[0], x_pts[0]),
'bound_xmax': lambda x: np.isclose(x[0], x_pts[-1]),
'bound_ymin': lambda x: np.isclose(x[1], y_pts[0]),
'bound_ymax': lambda x: np.isclose(x[1], y_pts[-1])})
# alternatively, load a mesh from file:
mesh = skfem.Mesh.load('mymesh.msh')
```
## 2. Choose a finite element from `skfem.element`.
https://scikit-fem.readthedocs.io/en/latest/api.html#module-skfem.element
``` python
element = skfem.ElementTriP2()
fem = Helmholtz(mesh, element)
```
## 3. Assemble the domains and the boundaries
The Helmholtz equation is implemented as a general second-order partial differential equation:
$- \alpha (\frac{\partial^2 \Phi}{\partial x^2} + \frac{\partial^2 \Phi}{\partial y^2}) + \beta \Phi = f$.
The electromagnetic wave propagation can be formulated in two different ways, depending on the polarization of interest:
1) TM polarization: $\Phi = E_Z$, $\alpha = 1 / \mu_r$, $\beta = -k_0^2 \epsilon_r$, and $f = -j k_0 Z_0 J_Z$
2) TE polarization: $\Phi = H_Z$, $\alpha = 1 / \epsilon_r$, $\beta = -k_0^2 \mu_r$, and $f = \frac{1}{\epsilon_r} (\frac{\partial J_Y}{\partial x} - \frac{\partial J_X}{\partial y})$
with the normalized free-space vacuum wave number $k_0 = \frac{2 \pi}{\lambda_0} = \frac{2 \pi f}{c_0}$.
Here, $c_0$ is propagation velocity (speed of light) in vacuum, expressed in *mesh units per second*.
For $f = 10 GHz$ and a mesh unit of $a = 1 mm$, one gets $k_0 \approx \frac{2 \pi 10 GHz}{3e8 m/s / 1mm} \approx 0.209$.
For a mesh with two different subdomains labeled 'air' and 'plastic', the domains are assembled with their respective parameters:
```python
k0 = 0.5
eps_air = 1
mu_air = 1
eps_plastic = 2 - 0.1j
mu_plastic = 1
fem.assemble_subdomains(alpha={'air': 1 / mu_air,
'plastic': 1 / mu_plastic},
beta={'air': -1 * k0 ** 2 * eps_air,
'plastic': -1 * k0 ** 2 * eps_plastic},
f={'air': 0,
'plastic': 0})
```
Similarly, the boundary conditions are defined. In this example, the upper and lower boundaries, labeled as 'bound_ymax' and 'bound_ymin', are supposed to be perfectly conducting (metallic) waveguide walls.
The corresponding essential (Dirichlet) boundary condition is $E_Z = 0$:
```python
fem.assemble_boundaries_dirichlet(value={'bound_ymin': 0,
'bound_ymax': 0})
```
The boundaries on the left and right, labeled 'bound_xmin' and 'bound_xmax', are supposed to be waveguide interfaces that are artificially extended to behave like infinite waveguides for the fundamental propagation mode.
This can be formulated with the third-order boundary condition:
$\alpha (\frac{\partial \Phi}{\partial x} \hat{x} + \frac{\partial \Phi}{\partial y} \hat{y}) \hat{n} + \gamma \Phi = q$.
Here, $\hat{x}$, $\hat{y}$, and $\hat{n}$ are unit vectors in x and y direction, and outward normal to the boundary, respectively.
The desired waveguide boundary condition is obtained with $\gamma = \alpha \cdot 1j \cdot k_0$.
For the excitation, an incident field $E_{Z,inc} = 1$ is added with $q = \alpha \cdot 2j \cdot k_0$ on the left boundary.
The natural (Neumann) boundary condition is a special case with $\gamma = q = 0$, which does not have to be stated explicitly.
```python
fem.assemble_boundaries_3rd(gamma={'bound_xmin': 1 / mu_plastic * 1j * k0,
'bound_xmax': 1 / mu_plastic * 1j * k0},
q={'bound_xmin': 1 / mu_plastic * 2j * k0,
'bound_xmax': 0})
```
## 4. Solve the linear system for the field solution
```python
fem.solve()
```
## 5. Process the solution
After solving, the field solution is stored in `fem.phi` as a complex vector. The individual real and imaginary parts are also stored seperately in `fem.phi_re` and `fem.phi_im`.
The corresponding locations of the `N` elements in the solution vector on the mesh are stored in `fem.basis.doflocs`, which has the shape `(2, N)`.
scikit-fem offers helper functions to find certain elements, for example by means of labeled subdomains or boundaries:
```python
x_bound_xmin, y_bound_xmin = fem.basis.doflocs[:, fem.basis.get_dofs('bound_xmin')]
```
Plotting is simple with the functions in `skfem.visuals`:
```python
from skfem.visuals.matplotlib import plot
import matplotlib.pyplot as mplt
fig, ax = mplt.subplots(2, 1)
plot(fem.basis, fem.phi_re, ax=ax[0])
plot(fem.basis, fem.phi_im, ax=ax[1])
ax[0].set_aspect(1)
ax[1].set_aspect(1)
mplt.tight_layout()
mplt.show()
```
Raw data
{
"_id": null,
"home_page": "",
"name": "Helmi-FEM",
"maintainer": "Vincent R.",
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "",
"keywords": "Helmholtz equation,finite-element analysis,finite-element method",
"author": "Vincent R.",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/5a/df/2c2257d38d7e42411d558fe151f8722b08f35e3eedc4636b976395f73754/Helmi_FEM-0.2.0.tar.gz",
"platform": null,
"description": "# Helmi_FEM\nAn open-source implementation of the Helmholtz equation for finite element analysis of electromagnetic wave propagation and scattering.\n\nBased on [scikit-fem](https://scikit-fem.readthedocs.io/en/latest/index.html) for finite element assembly and on [SciPy](https://scipy.org/), [NumPy](https://numpy.org/), and [matplotlib](https://matplotlib.org/) for solving, processing and plotting.\n\n## Installation:\n```python\npip install git+https://github.com/Vinc0110/Helmi_FEM.git\n```\n\nSee the example workflow below and additional examples in the subfolder.\n\n![Waveguide fields](./examples/waveguide/waveguide.png)\n\n## Features:\n - Supports complex-valued parameters\n - TE and TM polarization\n - Dirichlet and third-order boundary conditions (Neumann, freespace, absorbing)\n - Near-field to far-field transformation\n\n# Workflow\n## 1. Create or load a mesh of the simulation domain\nUse the mesh constructors of `skfem.mesh` for simple shapes such as rectangles, circles, or L-shapes. \nUse *gmsh* or other software for complex shapes.\n\nhttps://scikit-fem.readthedocs.io/en/latest/api.html#module-skfem.mesh\n\nhttp://gmsh.info/\n\n```python\nimport skfem\nimport numpy as np\n\n# create a rectangular mesh with skfem:\nx_pts = np.linspace(0, 100, 101)\ny_pts = np.linspace(-5, 5, 21)\nmesh = skfem.MeshTri.init_tensor(x_pts, y_pts)\nmesh = mesh.with_subdomains({'air': lambda x: x[0] < 50,\n 'plastic': lambda x: x[0] >= 50})\nmesh = mesh.with_boundaries({'bound_xmin': lambda x: np.isclose(x[0], x_pts[0]),\n 'bound_xmax': lambda x: np.isclose(x[0], x_pts[-1]),\n 'bound_ymin': lambda x: np.isclose(x[1], y_pts[0]),\n 'bound_ymax': lambda x: np.isclose(x[1], y_pts[-1])})\n\n# alternatively, load a mesh from file:\nmesh = skfem.Mesh.load('mymesh.msh')\n```\n\n## 2. Choose a finite element from `skfem.element`. \nhttps://scikit-fem.readthedocs.io/en/latest/api.html#module-skfem.element\n\n``` python\nelement = skfem.ElementTriP2()\nfem = Helmholtz(mesh, element)\n```\n\n## 3. Assemble the domains and the boundaries\nThe Helmholtz equation is implemented as a general second-order partial differential equation:\n\n$- \\alpha (\\frac{\\partial^2 \\Phi}{\\partial x^2} + \\frac{\\partial^2 \\Phi}{\\partial y^2}) + \\beta \\Phi = f$.\n\nThe electromagnetic wave propagation can be formulated in two different ways, depending on the polarization of interest:\n1) TM polarization: $\\Phi = E_Z$, $\\alpha = 1 / \\mu_r$, $\\beta = -k_0^2 \\epsilon_r$, and $f = -j k_0 Z_0 J_Z$\n2) TE polarization: $\\Phi = H_Z$, $\\alpha = 1 / \\epsilon_r$, $\\beta = -k_0^2 \\mu_r$, and $f = \\frac{1}{\\epsilon_r} (\\frac{\\partial J_Y}{\\partial x} - \\frac{\\partial J_X}{\\partial y})$\n\nwith the normalized free-space vacuum wave number $k_0 = \\frac{2 \\pi}{\\lambda_0} = \\frac{2 \\pi f}{c_0}$. \nHere, $c_0$ is propagation velocity (speed of light) in vacuum, expressed in *mesh units per second*.\n\nFor $f = 10 GHz$ and a mesh unit of $a = 1 mm$, one gets $k_0 \\approx \\frac{2 \\pi 10 GHz}{3e8 m/s / 1mm} \\approx 0.209$.\n\nFor a mesh with two different subdomains labeled 'air' and 'plastic', the domains are assembled with their respective parameters:\n```python\nk0 = 0.5\neps_air = 1\nmu_air = 1\neps_plastic = 2 - 0.1j\nmu_plastic = 1\nfem.assemble_subdomains(alpha={'air': 1 / mu_air, \n 'plastic': 1 / mu_plastic}, \n beta={'air': -1 * k0 ** 2 * eps_air, \n 'plastic': -1 * k0 ** 2 * eps_plastic}, \n f={'air': 0, \n 'plastic': 0})\n```\n\nSimilarly, the boundary conditions are defined. In this example, the upper and lower boundaries, labeled as 'bound_ymax' and 'bound_ymin', are supposed to be perfectly conducting (metallic) waveguide walls. \nThe corresponding essential (Dirichlet) boundary condition is $E_Z = 0$:\n```python\nfem.assemble_boundaries_dirichlet(value={'bound_ymin': 0, \n 'bound_ymax': 0})\n```\n\nThe boundaries on the left and right, labeled 'bound_xmin' and 'bound_xmax', are supposed to be waveguide interfaces that are artificially extended to behave like infinite waveguides for the fundamental propagation mode.\nThis can be formulated with the third-order boundary condition:\n$\\alpha (\\frac{\\partial \\Phi}{\\partial x} \\hat{x} + \\frac{\\partial \\Phi}{\\partial y} \\hat{y}) \\hat{n} + \\gamma \\Phi = q$.\nHere, $\\hat{x}$, $\\hat{y}$, and $\\hat{n}$ are unit vectors in x and y direction, and outward normal to the boundary, respectively.\n\nThe desired waveguide boundary condition is obtained with $\\gamma = \\alpha \\cdot 1j \\cdot k_0$. \nFor the excitation, an incident field $E_{Z,inc} = 1$ is added with $q = \\alpha \\cdot 2j \\cdot k_0$ on the left boundary.\nThe natural (Neumann) boundary condition is a special case with $\\gamma = q = 0$, which does not have to be stated explicitly.\n\n```python\nfem.assemble_boundaries_3rd(gamma={'bound_xmin': 1 / mu_plastic * 1j * k0, \n 'bound_xmax': 1 / mu_plastic * 1j * k0}, \n q={'bound_xmin': 1 / mu_plastic * 2j * k0, \n 'bound_xmax': 0})\n```\n\n## 4. Solve the linear system for the field solution\n```python\nfem.solve()\n```\n\n## 5. Process the solution\nAfter solving, the field solution is stored in `fem.phi` as a complex vector. The individual real and imaginary parts are also stored seperately in `fem.phi_re` and `fem.phi_im`.\n\nThe corresponding locations of the `N` elements in the solution vector on the mesh are stored in `fem.basis.doflocs`, which has the shape `(2, N)`.\n\nscikit-fem offers helper functions to find certain elements, for example by means of labeled subdomains or boundaries:\n```python\nx_bound_xmin, y_bound_xmin = fem.basis.doflocs[:, fem.basis.get_dofs('bound_xmin')]\n```\n\nPlotting is simple with the functions in `skfem.visuals`:\n```python\nfrom skfem.visuals.matplotlib import plot\nimport matplotlib.pyplot as mplt\n\nfig, ax = mplt.subplots(2, 1)\nplot(fem.basis, fem.phi_re, ax=ax[0])\nplot(fem.basis, fem.phi_im, ax=ax[1])\nax[0].set_aspect(1)\nax[1].set_aspect(1)\nmplt.tight_layout()\nmplt.show()\n```\n",
"bugtrack_url": null,
"license": "BSD 3-Clause License Copyright (c) 2023, Vincent R Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ",
"summary": "Finite element method for solving the electromagnetic Helmholtz equation.",
"version": "0.2.0",
"split_keywords": [
"helmholtz equation",
"finite-element analysis",
"finite-element method"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "47897bb2257da10ef7e25587dc34f80a4963251648938ef3fcf76a590e231b46",
"md5": "772a97c9a20554e774730baef9f6e18a",
"sha256": "d586f96171aca8bc0a71a7444a2a34b21aa1952dcfad59e4b96617ad3bc92fa3"
},
"downloads": -1,
"filename": "Helmi_FEM-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "772a97c9a20554e774730baef9f6e18a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 10768,
"upload_time": "2023-02-09T16:41:28",
"upload_time_iso_8601": "2023-02-09T16:41:28.147660Z",
"url": "https://files.pythonhosted.org/packages/47/89/7bb2257da10ef7e25587dc34f80a4963251648938ef3fcf76a590e231b46/Helmi_FEM-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "5adf2c2257d38d7e42411d558fe151f8722b08f35e3eedc4636b976395f73754",
"md5": "f9c735957f288c3230bfd56ff272394a",
"sha256": "00614035dbf880da3a6c8fc77c3e9752283a38700d5ab450c330b1c3552f25a6"
},
"downloads": -1,
"filename": "Helmi_FEM-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "f9c735957f288c3230bfd56ff272394a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 9906,
"upload_time": "2023-02-09T16:41:29",
"upload_time_iso_8601": "2023-02-09T16:41:29.701129Z",
"url": "https://files.pythonhosted.org/packages/5a/df/2c2257d38d7e42411d558fe151f8722b08f35e3eedc4636b976395f73754/Helmi_FEM-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-02-09 16:41:29",
"github": false,
"gitlab": false,
"bitbucket": false,
"lcname": "helmi-fem"
}