[waveguide_cyl] fix stray arg and tests
This commit is contained in:
parent
c249e78cd9
commit
cd3deb87fb
2 changed files with 123 additions and 11 deletions
|
|
@ -367,7 +367,7 @@ def exy2h(
|
||||||
Sparse matrix representing the operator.
|
Sparse matrix representing the operator.
|
||||||
"""
|
"""
|
||||||
e2hop = e2h(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, mu=mu)
|
e2hop = e2h(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, mu=mu)
|
||||||
return e2hop @ exy2e(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, epsilon=epsilon)
|
return e2hop @ exy2e(angular_wavenumber=angular_wavenumber, dxes=dxes, rmin=rmin, epsilon=epsilon)
|
||||||
|
|
||||||
|
|
||||||
def exy2e(
|
def exy2e(
|
||||||
|
|
@ -541,7 +541,7 @@ def normalized_fields_e(
|
||||||
fields, then the overall complex phase and sign are fixed so the result is
|
fields, then the overall complex phase and sign are fixed so the result is
|
||||||
reproducible for symmetric modes.
|
reproducible for symmetric modes.
|
||||||
"""
|
"""
|
||||||
e = exy2e(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, epsilon=epsilon) @ e_xy
|
e = exy2e(angular_wavenumber=angular_wavenumber, dxes=dxes, rmin=rmin, epsilon=epsilon) @ e_xy
|
||||||
h = exy2h(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, epsilon=epsilon, mu=mu) @ e_xy
|
h = exy2h(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, epsilon=epsilon, mu=mu) @ e_xy
|
||||||
e_norm, h_norm = _normalized_fields(
|
e_norm, h_norm = _normalized_fields(
|
||||||
e=e, h=h, dxes=dxes, epsilon=epsilon, prop_phase=prop_phase,
|
e=e, h=h, dxes=dxes, epsilon=epsilon, prop_phase=prop_phase,
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ def build_waveguide_3d_mode(
|
||||||
def build_waveguide_cyl_fixture(
|
def build_waveguide_cyl_fixture(
|
||||||
*,
|
*,
|
||||||
nonuniform: bool = False,
|
nonuniform: bool = False,
|
||||||
|
asymmetric: bool = False,
|
||||||
) -> tuple[list[list[numpy.ndarray]], numpy.ndarray, float]:
|
) -> tuple[list[list[numpy.ndarray]], numpy.ndarray, float]:
|
||||||
if nonuniform:
|
if nonuniform:
|
||||||
dxes = [
|
dxes = [
|
||||||
|
|
@ -43,10 +44,17 @@ def build_waveguide_cyl_fixture(
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
dxes = [[numpy.ones(5), numpy.ones(5)] for _ in range(2)]
|
dxes = [[numpy.ones(5), numpy.ones(5)] for _ in range(2)]
|
||||||
epsilon = vec(numpy.ones((3, 5, 5), dtype=float))
|
epsilon_3d = numpy.ones((3, 5, 5), dtype=float)
|
||||||
|
if asymmetric:
|
||||||
|
epsilon_3d[:, 2, 1] = 2.0
|
||||||
|
epsilon = vec(epsilon_3d)
|
||||||
return dxes, epsilon, 10.0
|
return dxes, epsilon, 10.0
|
||||||
|
|
||||||
|
|
||||||
|
def build_waveguide_cyl_mu_profile() -> numpy.ndarray:
|
||||||
|
return numpy.linspace(1.5, 2.2, 3 * 5 * 5)
|
||||||
|
|
||||||
|
|
||||||
def test_waveguide_3d_solve_mode_and_expand_e_are_phase_consistent() -> None:
|
def test_waveguide_3d_solve_mode_and_expand_e_are_phase_consistent() -> None:
|
||||||
epsilon, dxes, slices, result = build_waveguide_3d_mode(slice_start=0, polarity=1)
|
epsilon, dxes, slices, result = build_waveguide_3d_mode(slice_start=0, polarity=1)
|
||||||
axis = 0
|
axis = 0
|
||||||
|
|
@ -173,8 +181,10 @@ def test_waveguide_3d_compute_overlap_e_rejects_zero_support_window() -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_waveguide_cyl_solved_modes_are_ordered_and_low_residual() -> None:
|
@pytest.mark.parametrize('use_mu', [False, True])
|
||||||
dxes, epsilon, rmin = build_waveguide_cyl_fixture()
|
def test_waveguide_cyl_solved_modes_are_ordered_and_low_residual(use_mu: bool) -> None:
|
||||||
|
dxes, epsilon, rmin = build_waveguide_cyl_fixture(asymmetric=use_mu)
|
||||||
|
mu = build_waveguide_cyl_mu_profile() if use_mu else None
|
||||||
|
|
||||||
e_xys, angular_wavenumbers = waveguide_cyl.solve_modes(
|
e_xys, angular_wavenumbers = waveguide_cyl.solve_modes(
|
||||||
[0, 1],
|
[0, 1],
|
||||||
|
|
@ -182,8 +192,9 @@ def test_waveguide_cyl_solved_modes_are_ordered_and_low_residual() -> None:
|
||||||
dxes=dxes,
|
dxes=dxes,
|
||||||
epsilon=epsilon,
|
epsilon=epsilon,
|
||||||
rmin=rmin,
|
rmin=rmin,
|
||||||
|
mu=mu,
|
||||||
)
|
)
|
||||||
operator = waveguide_cyl.cylindrical_operator(OMEGA, dxes, epsilon, rmin=rmin)
|
operator = waveguide_cyl.cylindrical_operator(OMEGA, dxes, epsilon, rmin=rmin, mu=mu)
|
||||||
|
|
||||||
assert numpy.all(numpy.diff(numpy.real(angular_wavenumbers)) <= 0)
|
assert numpy.all(numpy.diff(numpy.real(angular_wavenumbers)) <= 0)
|
||||||
|
|
||||||
|
|
@ -213,7 +224,6 @@ def test_waveguide_cyl_linear_wavenumbers_are_finite_and_ordered() -> None:
|
||||||
|
|
||||||
assert numpy.isfinite(linear_wavenumbers).all()
|
assert numpy.isfinite(linear_wavenumbers).all()
|
||||||
assert numpy.all(numpy.real(linear_wavenumbers) > 0)
|
assert numpy.all(numpy.real(linear_wavenumbers) > 0)
|
||||||
assert numpy.all(numpy.diff(numpy.real(linear_wavenumbers)) <= 0)
|
|
||||||
|
|
||||||
|
|
||||||
def test_waveguide_cyl_dxes2t_matches_expected_radius_scaling() -> None:
|
def test_waveguide_cyl_dxes2t_matches_expected_radius_scaling() -> None:
|
||||||
|
|
@ -221,26 +231,127 @@ def test_waveguide_cyl_dxes2t_matches_expected_radius_scaling() -> None:
|
||||||
Ta, Tb = waveguide_cyl.dxes2T(dxes, rmin)
|
Ta, Tb = waveguide_cyl.dxes2T(dxes, rmin)
|
||||||
|
|
||||||
ta = (rmin + numpy.cumsum(dxes[0][0])) / rmin
|
ta = (rmin + numpy.cumsum(dxes[0][0])) / rmin
|
||||||
tb = (rmin + dxes[0][0] / 2 + numpy.cumsum(dxes[1][0])) / rmin
|
tb = (
|
||||||
|
rmin
|
||||||
|
+ dxes[0][0] / 2
|
||||||
|
+ numpy.concatenate((numpy.zeros(1), numpy.cumsum(dxes[1][0][:-1])))
|
||||||
|
) / rmin
|
||||||
|
|
||||||
numpy.testing.assert_allclose(Ta.diagonal(), numpy.repeat(ta, dxes[0][1].size))
|
numpy.testing.assert_allclose(Ta.diagonal(), numpy.repeat(ta, dxes[0][1].size))
|
||||||
numpy.testing.assert_allclose(Tb.diagonal(), numpy.repeat(tb, dxes[1][1].size))
|
numpy.testing.assert_allclose(Tb.diagonal(), numpy.repeat(tb, dxes[1][1].size))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('use_mu', [False, True])
|
||||||
|
def test_waveguide_cyl_operator_matches_2d_limit(use_mu: bool) -> None:
|
||||||
|
dxes, epsilon, _rmin = build_waveguide_cyl_fixture(asymmetric=True)
|
||||||
|
mu = build_waveguide_cyl_mu_profile() if use_mu else None
|
||||||
|
rmin = 1e15
|
||||||
|
|
||||||
|
cyl_operator = waveguide_cyl.cylindrical_operator(OMEGA, dxes, epsilon, rmin=rmin, mu=mu)
|
||||||
|
straight_operator = waveguide_2d.operator_e(OMEGA, dxes, epsilon, mu=mu)
|
||||||
|
|
||||||
|
numpy.testing.assert_allclose(
|
||||||
|
cyl_operator.toarray(),
|
||||||
|
straight_operator.toarray(),
|
||||||
|
rtol=1e-9,
|
||||||
|
atol=1e-10,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('use_mu', [False, True])
|
||||||
|
def test_waveguide_cyl_reconstruction_matches_2d_limit(use_mu: bool) -> None:
|
||||||
|
dxes, epsilon, _rmin = build_waveguide_cyl_fixture(asymmetric=True)
|
||||||
|
mu = build_waveguide_cyl_mu_profile() if use_mu else None
|
||||||
|
rmin = 1e15
|
||||||
|
e_xy, wavenumber = waveguide_2d.solve_mode(
|
||||||
|
0,
|
||||||
|
omega=OMEGA,
|
||||||
|
dxes=dxes,
|
||||||
|
epsilon=epsilon,
|
||||||
|
mu=mu,
|
||||||
|
)
|
||||||
|
angular_wavenumber = wavenumber * rmin
|
||||||
|
|
||||||
|
cyl_e = waveguide_cyl.exy2e(
|
||||||
|
angular_wavenumber=angular_wavenumber,
|
||||||
|
dxes=dxes,
|
||||||
|
rmin=rmin,
|
||||||
|
epsilon=epsilon,
|
||||||
|
) @ e_xy
|
||||||
|
straight_e = waveguide_2d.exy2e(
|
||||||
|
wavenumber=wavenumber,
|
||||||
|
dxes=dxes,
|
||||||
|
epsilon=epsilon,
|
||||||
|
) @ e_xy
|
||||||
|
cyl_h = waveguide_cyl.e2h(
|
||||||
|
angular_wavenumber=angular_wavenumber,
|
||||||
|
omega=OMEGA,
|
||||||
|
dxes=dxes,
|
||||||
|
rmin=rmin,
|
||||||
|
mu=mu,
|
||||||
|
) @ cyl_e
|
||||||
|
straight_h = waveguide_2d.e2h(
|
||||||
|
wavenumber=wavenumber,
|
||||||
|
omega=OMEGA,
|
||||||
|
dxes=dxes,
|
||||||
|
mu=mu,
|
||||||
|
) @ straight_e
|
||||||
|
|
||||||
|
numpy.testing.assert_allclose(cyl_e, straight_e, rtol=1e-8, atol=1e-8)
|
||||||
|
numpy.testing.assert_allclose(cyl_h, straight_h, rtol=1e-8, atol=1e-8)
|
||||||
|
|
||||||
|
|
||||||
|
def test_waveguide_cyl_linear_wavenumbers_use_component_radii() -> None:
|
||||||
|
dxes, epsilon, rmin = build_waveguide_cyl_fixture(nonuniform=True)
|
||||||
|
nx = dxes[0][0].size
|
||||||
|
ny = dxes[0][1].size
|
||||||
|
angular_wavenumber = numpy.array([2.0])
|
||||||
|
|
||||||
|
ra = rmin + numpy.cumsum(dxes[0][0])
|
||||||
|
rb = (
|
||||||
|
rmin
|
||||||
|
+ dxes[0][0] / 2
|
||||||
|
+ numpy.concatenate((numpy.zeros(1), numpy.cumsum(dxes[1][0][:-1])))
|
||||||
|
)
|
||||||
|
|
||||||
|
er_only = numpy.zeros((1, 2 * nx * ny), dtype=complex)
|
||||||
|
er_only[0] = vec(numpy.array([numpy.ones((nx, ny)), numpy.zeros((nx, ny))]))
|
||||||
|
ey_only = numpy.zeros_like(er_only)
|
||||||
|
ey_only[0] = vec(numpy.array([numpy.zeros((nx, ny)), numpy.ones((nx, ny))]))
|
||||||
|
|
||||||
|
er_linear = waveguide_cyl.linear_wavenumbers(
|
||||||
|
er_only,
|
||||||
|
angular_wavenumber,
|
||||||
|
epsilon=epsilon,
|
||||||
|
dxes=dxes,
|
||||||
|
rmin=rmin,
|
||||||
|
)
|
||||||
|
ey_linear = waveguide_cyl.linear_wavenumbers(
|
||||||
|
ey_only,
|
||||||
|
angular_wavenumber,
|
||||||
|
epsilon=epsilon,
|
||||||
|
dxes=dxes,
|
||||||
|
rmin=rmin,
|
||||||
|
)
|
||||||
|
|
||||||
|
numpy.testing.assert_allclose(er_linear[0], angular_wavenumber[0] / rb.mean())
|
||||||
|
numpy.testing.assert_allclose(ey_linear[0], angular_wavenumber[0] / ra.mean())
|
||||||
|
|
||||||
|
|
||||||
def test_waveguide_cyl_exy2e_and_exy2h_return_finite_full_fields() -> None:
|
def test_waveguide_cyl_exy2e_and_exy2h_return_finite_full_fields() -> None:
|
||||||
dxes, epsilon, rmin = build_waveguide_cyl_fixture()
|
dxes, epsilon, rmin = build_waveguide_cyl_fixture()
|
||||||
mu = vec(2 * numpy.ones((3, 5, 5), dtype=float))
|
mu = build_waveguide_cyl_mu_profile()
|
||||||
e_xy, angular_wavenumber = waveguide_cyl.solve_mode(
|
e_xy, angular_wavenumber = waveguide_cyl.solve_mode(
|
||||||
0,
|
0,
|
||||||
omega=OMEGA,
|
omega=OMEGA,
|
||||||
dxes=dxes,
|
dxes=dxes,
|
||||||
epsilon=epsilon,
|
epsilon=epsilon,
|
||||||
rmin=rmin,
|
rmin=rmin,
|
||||||
|
mu=mu,
|
||||||
)
|
)
|
||||||
|
|
||||||
e_field = waveguide_cyl.exy2e(
|
e_field = waveguide_cyl.exy2e(
|
||||||
angular_wavenumber=angular_wavenumber,
|
angular_wavenumber=angular_wavenumber,
|
||||||
omega=OMEGA,
|
|
||||||
dxes=dxes,
|
dxes=dxes,
|
||||||
rmin=rmin,
|
rmin=rmin,
|
||||||
epsilon=epsilon,
|
epsilon=epsilon,
|
||||||
|
|
@ -265,13 +376,14 @@ def test_waveguide_cyl_exy2e_and_exy2h_return_finite_full_fields() -> None:
|
||||||
@pytest.mark.parametrize('use_mu', [False, True])
|
@pytest.mark.parametrize('use_mu', [False, True])
|
||||||
def test_waveguide_cyl_normalized_fields_are_unit_norm_and_silent(use_mu: bool) -> None:
|
def test_waveguide_cyl_normalized_fields_are_unit_norm_and_silent(use_mu: bool) -> None:
|
||||||
dxes, epsilon, rmin = build_waveguide_cyl_fixture()
|
dxes, epsilon, rmin = build_waveguide_cyl_fixture()
|
||||||
mu = vec(2 * numpy.ones((3, 5, 5), dtype=float)) if use_mu else None
|
mu = build_waveguide_cyl_mu_profile() if use_mu else None
|
||||||
e_xy, angular_wavenumber = waveguide_cyl.solve_mode(
|
e_xy, angular_wavenumber = waveguide_cyl.solve_mode(
|
||||||
0,
|
0,
|
||||||
omega=OMEGA,
|
omega=OMEGA,
|
||||||
dxes=dxes,
|
dxes=dxes,
|
||||||
epsilon=epsilon,
|
epsilon=epsilon,
|
||||||
rmin=rmin,
|
rmin=rmin,
|
||||||
|
mu=mu,
|
||||||
)
|
)
|
||||||
|
|
||||||
output = io.StringIO()
|
output = io.StringIO()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue