fdfd_tools/meanas/fdfd/functional.py

183 lines
5.2 KiB
Python
Raw Normal View History

2016-05-30 22:30:45 -07:00
"""
Functional versions of many FDFD operators. These can be useful for performing
FDFD calculations without needing to construct large matrices in memory.
2019-08-04 13:48:41 -07:00
The functions generated here expect field inputs with shape (3, X, Y, Z),
e.g. E = [E_x, E_y, E_z] where each component has shape (X, Y, Z)
2016-05-30 22:30:45 -07:00
"""
from typing import List, Callable
import numpy
from . import dx_lists_t, field_t
__author__ = 'Jan Petykiewicz'
2016-07-03 01:20:51 -07:00
functional_matrix = Callable[[field_t], field_t]
2016-05-30 22:30:45 -07:00
def curl_h(dxes: dx_lists_t) -> functional_matrix:
"""
Curl operator for use with the H field.
2019-08-04 13:48:41 -07:00
:param dxes: Grid parameters [dx_e, dx_h] as described in meanas.types
2016-05-30 22:30:45 -07:00
:return: Function for taking the discretized curl of the H-field, F(H) -> curlH
"""
dxyz_b = numpy.meshgrid(*dxes[1], indexing='ij')
2016-07-03 03:01:01 -07:00
def dh(f, ax):
2016-05-30 22:30:45 -07:00
return (f - numpy.roll(f, 1, axis=ax)) / dxyz_b[ax]
2016-07-03 01:20:51 -07:00
def ch_fun(h: field_t) -> field_t:
e = [dh(h[2], 1) - dh(h[1], 2),
dh(h[0], 2) - dh(h[2], 0),
dh(h[1], 0) - dh(h[0], 1)]
return e
2016-05-30 22:30:45 -07:00
return ch_fun
def curl_e(dxes: dx_lists_t) -> functional_matrix:
"""
Curl operator for use with the E field.
2019-08-04 13:48:41 -07:00
:param dxes: Grid parameters [dx_e, dx_h] as described in meanas.types
2016-05-30 22:30:45 -07:00
:return: Function for taking the discretized curl of the E-field, F(E) -> curlE
"""
dxyz_a = numpy.meshgrid(*dxes[0], indexing='ij')
2016-07-03 03:01:01 -07:00
def de(f, ax):
2016-05-30 22:30:45 -07:00
return (numpy.roll(f, -1, axis=ax) - f) / dxyz_a[ax]
2016-07-03 01:20:51 -07:00
def ce_fun(e: field_t) -> field_t:
h = [de(e[2], 1) - de(e[1], 2),
de(e[0], 2) - de(e[2], 0),
de(e[1], 0) - de(e[0], 1)]
return h
2016-05-30 22:30:45 -07:00
return ce_fun
def e_full(omega: complex,
dxes: dx_lists_t,
epsilon: field_t,
mu: field_t = None
) -> functional_matrix:
"""
Wave operator del x (1/mu * del x) - omega**2 * epsilon, for use with E-field,
with wave equation
(del x (1/mu * del x) - omega**2 * epsilon) E = -i * omega * J
:param omega: Angular frequency of the simulation
2019-08-04 13:48:41 -07:00
:param dxes: Grid parameters [dx_e, dx_h] as described in meanas.types
2016-05-30 22:30:45 -07:00
:param epsilon: Dielectric constant
:param mu: Magnetic permeability (default 1 everywhere)
:return: Function implementing the wave operator A(E) -> E
"""
ch = curl_h(dxes)
ce = curl_e(dxes)
2016-07-03 01:20:51 -07:00
def op_1(e):
curls = ch(ce(e))
return [c - omega ** 2 * e * x for c, e, x in zip(curls, epsilon, e)]
2016-05-30 22:30:45 -07:00
2016-07-03 01:20:51 -07:00
def op_mu(e):
curls = ch([m * y for m, y in zip(mu, ce(e))])
return [c - omega ** 2 * p * x for c, p, x in zip(curls, epsilon, e)]
2016-05-30 22:30:45 -07:00
if numpy.any(numpy.equal(mu, None)):
return op_1
else:
return op_mu
def eh_full(omega: complex,
dxes: dx_lists_t,
epsilon: field_t,
mu: field_t = None
) -> functional_matrix:
"""
Wave operator for full (both E and H) field representation.
:param omega: Angular frequency of the simulation
2019-08-04 13:48:41 -07:00
:param dxes: Grid parameters [dx_e, dx_h] as described in meanas.types
2016-05-30 22:30:45 -07:00
:param epsilon: Dielectric constant
:param mu: Magnetic permeability (default 1 everywhere)
:return: Function implementing the wave operator A(E, H) -> (E, H)
"""
ch = curl_h(dxes)
ce = curl_e(dxes)
2016-07-03 01:20:51 -07:00
def op_1(e, h):
return ([c - 1j * omega * p * x for c, p, x in zip(ch(h), epsilon, e)],
[c + 1j * omega * y for c, y in zip(ce(e), h)])
2016-05-30 22:30:45 -07:00
2016-07-03 01:20:51 -07:00
def op_mu(e, h):
return ([c - 1j * omega * p * x for c, p, x in zip(ch(h), epsilon, e)],
[c + 1j * omega * m * y for c, m, y in zip(ce(e), mu, h)])
2016-05-30 22:30:45 -07:00
if numpy.any(numpy.equal(mu, None)):
return op_1
else:
return op_mu
def e2h(omega: complex,
dxes: dx_lists_t,
mu: field_t = None,
) -> functional_matrix:
"""
Utility operator for converting the E field into the H field.
For use with e_full -- assumes that there is no magnetic current M.
:param omega: Angular frequency of the simulation
2019-08-04 13:48:41 -07:00
:param dxes: Grid parameters [dx_e, dx_h] as described in meanas.types
2016-05-30 22:30:45 -07:00
:param mu: Magnetic permeability (default 1 everywhere)
:return: Function for converting E to H
"""
A2 = curl_e(dxes)
2016-07-03 01:20:51 -07:00
def e2h_1_1(e):
return [y / (-1j * omega) for y in A2(e)]
2016-05-30 22:30:45 -07:00
2016-07-03 01:20:51 -07:00
def e2h_mu(e):
return [y / (-1j * omega * m) for y, m in zip(A2(e), mu)]
2016-05-30 22:30:45 -07:00
if numpy.any(numpy.equal(mu, None)):
return e2h_1_1
else:
return e2h_mu
2019-07-09 20:13:07 -07:00
def m2j(omega: complex,
dxes: dx_lists_t,
mu: field_t = None,
) -> functional_matrix:
"""
Utility operator for converting magnetic current (M) distribution
into equivalent electric current distribution (J).
For use with e.g. e_full().
:param omega: Angular frequency of the simulation
2019-08-04 13:48:41 -07:00
:param dxes: Grid parameters [dx_e, dx_h] as described in meanas.types
2019-07-09 20:13:07 -07:00
:param mu: Magnetic permeability (default 1 everywhere)
:return: Function for converting M to J
"""
ch = curl_h(dxes)
def m2j_mu(m):
m_mu = [m[k] / mu[k] for k in range[3]]
J = [Ji / (-1j * omega) for Ji in ch(m_mu)]
return J
def m2j_1(m):
J = [Ji / (-1j * omega) for Ji in ch(m)]
return J
if numpy.any(numpy.equal(mu, None)):
return m2j_1
else:
return m2j_mu