[waveguide_cyl] fix stray arg and tests

This commit is contained in:
Forgejo Actions 2026-06-25 12:05:25 -07:00
commit cd3deb87fb
2 changed files with 123 additions and 11 deletions

View file

@ -367,7 +367,7 @@ def exy2h(
Sparse matrix representing the operator.
"""
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(
@ -541,7 +541,7 @@ def normalized_fields_e(
fields, then the overall complex phase and sign are fixed so the result is
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
e_norm, h_norm = _normalized_fields(
e=e, h=h, dxes=dxes, epsilon=epsilon, prop_phase=prop_phase,

View file

@ -35,6 +35,7 @@ def build_waveguide_3d_mode(
def build_waveguide_cyl_fixture(
*,
nonuniform: bool = False,
asymmetric: bool = False,
) -> tuple[list[list[numpy.ndarray]], numpy.ndarray, float]:
if nonuniform:
dxes = [
@ -43,10 +44,17 @@ def build_waveguide_cyl_fixture(
]
else:
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
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:
epsilon, dxes, slices, result = build_waveguide_3d_mode(slice_start=0, polarity=1)
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:
dxes, epsilon, rmin = build_waveguide_cyl_fixture()
@pytest.mark.parametrize('use_mu', [False, True])
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(
[0, 1],
@ -182,8 +192,9 @@ def test_waveguide_cyl_solved_modes_are_ordered_and_low_residual() -> None:
dxes=dxes,
epsilon=epsilon,
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)
@ -213,7 +224,6 @@ def test_waveguide_cyl_linear_wavenumbers_are_finite_and_ordered() -> None:
assert numpy.isfinite(linear_wavenumbers).all()
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:
@ -221,26 +231,127 @@ def test_waveguide_cyl_dxes2t_matches_expected_radius_scaling() -> None:
Ta, Tb = waveguide_cyl.dxes2T(dxes, 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(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:
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(
0,
omega=OMEGA,
dxes=dxes,
epsilon=epsilon,
rmin=rmin,
mu=mu,
)
e_field = waveguide_cyl.exy2e(
angular_wavenumber=angular_wavenumber,
omega=OMEGA,
dxes=dxes,
rmin=rmin,
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])
def test_waveguide_cyl_normalized_fields_are_unit_norm_and_silent(use_mu: bool) -> None:
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(
0,
omega=OMEGA,
dxes=dxes,
epsilon=epsilon,
rmin=rmin,
mu=mu,
)
output = io.StringIO()