[bloch] fixup some vectorization and add tests
This commit is contained in:
parent
f35b334100
commit
07b16ad86a
2 changed files with 101 additions and 14 deletions
|
|
@ -136,6 +136,14 @@ except ImportError:
|
||||||
logger.info('Using numpy fft')
|
logger.info('Using numpy fft')
|
||||||
|
|
||||||
|
|
||||||
|
def _assemble_hmn_vector(
|
||||||
|
h_m: NDArray[numpy.complex128],
|
||||||
|
h_n: NDArray[numpy.complex128],
|
||||||
|
) -> NDArray[numpy.complex128]:
|
||||||
|
stacked = numpy.concatenate((numpy.ravel(h_m), numpy.ravel(h_n)))
|
||||||
|
return stacked[:, None]
|
||||||
|
|
||||||
|
|
||||||
def generate_kmn(
|
def generate_kmn(
|
||||||
k0: ArrayLike,
|
k0: ArrayLike,
|
||||||
G_matrix: ArrayLike,
|
G_matrix: ArrayLike,
|
||||||
|
|
@ -253,8 +261,8 @@ def maxwell_operator(
|
||||||
h_m, h_n = b_m, b_n
|
h_m, h_n = b_m, b_n
|
||||||
else:
|
else:
|
||||||
# transform from mn to xyz
|
# transform from mn to xyz
|
||||||
b_xyz = (m * b_m[:, :, :, None]
|
b_xyz = (m * b_m
|
||||||
+ n * b_n[:, :, :, None])
|
+ n * b_n) # noqa: E128
|
||||||
|
|
||||||
# divide by mu
|
# divide by mu
|
||||||
temp = ifftn(b_xyz, axes=range(3))
|
temp = ifftn(b_xyz, axes=range(3))
|
||||||
|
|
@ -265,10 +273,7 @@ def maxwell_operator(
|
||||||
h_m = numpy.sum(h_xyz * m, axis=3)
|
h_m = numpy.sum(h_xyz * m, axis=3)
|
||||||
h_n = numpy.sum(h_xyz * n, axis=3)
|
h_n = numpy.sum(h_xyz * n, axis=3)
|
||||||
|
|
||||||
h.shape = (h.size,)
|
return _assemble_hmn_vector(h_m, h_n)
|
||||||
h = numpy.concatenate((h_m.ravel(), h_n.ravel()), axis=None, out=h) # ravel and merge
|
|
||||||
h.shape = (h.size, 1)
|
|
||||||
return h
|
|
||||||
|
|
||||||
return operator
|
return operator
|
||||||
|
|
||||||
|
|
@ -403,8 +408,8 @@ def inverse_maxwell_operator_approx(
|
||||||
b_m, b_n = hin_m, hin_n
|
b_m, b_n = hin_m, hin_n
|
||||||
else:
|
else:
|
||||||
# transform from mn to xyz
|
# transform from mn to xyz
|
||||||
h_xyz = (m * hin_m[:, :, :, None]
|
h_xyz = (m * hin_m
|
||||||
+ n * hin_n[:, :, :, None])
|
+ n * hin_n) # noqa: E128
|
||||||
|
|
||||||
# multiply by mu
|
# multiply by mu
|
||||||
temp = ifftn(h_xyz, axes=range(3))
|
temp = ifftn(h_xyz, axes=range(3))
|
||||||
|
|
@ -412,8 +417,8 @@ def inverse_maxwell_operator_approx(
|
||||||
b_xyz = fftn(temp, axes=range(3))
|
b_xyz = fftn(temp, axes=range(3))
|
||||||
|
|
||||||
# transform back to mn
|
# transform back to mn
|
||||||
b_m = numpy.sum(b_xyz * m, axis=3)
|
b_m = numpy.sum(b_xyz * m, axis=3, keepdims=True)
|
||||||
b_n = numpy.sum(b_xyz * n, axis=3)
|
b_n = numpy.sum(b_xyz * n, axis=3, keepdims=True)
|
||||||
|
|
||||||
# cross product and transform into xyz basis
|
# cross product and transform into xyz basis
|
||||||
e_xyz = (n * b_m
|
e_xyz = (n * b_m
|
||||||
|
|
@ -428,10 +433,7 @@ def inverse_maxwell_operator_approx(
|
||||||
h_m = numpy.sum(d_xyz * n, axis=3, keepdims=True) / +k_mag
|
h_m = numpy.sum(d_xyz * n, axis=3, keepdims=True) / +k_mag
|
||||||
h_n = numpy.sum(d_xyz * m, axis=3, keepdims=True) / -k_mag
|
h_n = numpy.sum(d_xyz * m, axis=3, keepdims=True) / -k_mag
|
||||||
|
|
||||||
h.shape = (h.size,)
|
return _assemble_hmn_vector(h_m, h_n)
|
||||||
h = numpy.concatenate((h_m, h_n), axis=None, out=h)
|
|
||||||
h.shape = (h.size, 1)
|
|
||||||
return h
|
|
||||||
|
|
||||||
return operator
|
return operator
|
||||||
|
|
||||||
|
|
|
||||||
85
meanas/test/test_bloch_foundations.py
Normal file
85
meanas/test/test_bloch_foundations.py
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
import numpy
|
||||||
|
from numpy.linalg import norm
|
||||||
|
|
||||||
|
from ..fdfd import bloch
|
||||||
|
|
||||||
|
|
||||||
|
SHAPE = (2, 2, 2)
|
||||||
|
K0 = numpy.array([0.1, 0.2, 0.3])
|
||||||
|
G_MATRIX = numpy.eye(3)
|
||||||
|
EPSILON = numpy.ones((3, *SHAPE), dtype=float)
|
||||||
|
MU = numpy.stack([
|
||||||
|
numpy.linspace(2.0, 2.7, numpy.prod(SHAPE)).reshape(SHAPE),
|
||||||
|
numpy.linspace(2.1, 2.8, numpy.prod(SHAPE)).reshape(SHAPE),
|
||||||
|
numpy.linspace(2.2, 2.9, numpy.prod(SHAPE)).reshape(SHAPE),
|
||||||
|
])
|
||||||
|
H_MN = (numpy.arange(2 * numpy.prod(SHAPE)) + 0.25j).astype(complex)
|
||||||
|
ZERO_H_MN = numpy.zeros_like(H_MN)
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_kmn_general_case_returns_orthonormal_basis() -> None:
|
||||||
|
k_mag, m_vecs, n_vecs = bloch.generate_kmn(K0, G_MATRIX, SHAPE)
|
||||||
|
|
||||||
|
assert k_mag.shape == SHAPE + (1,)
|
||||||
|
assert m_vecs.shape == SHAPE + (3,)
|
||||||
|
assert n_vecs.shape == SHAPE + (3,)
|
||||||
|
assert numpy.isfinite(k_mag).all()
|
||||||
|
assert numpy.isfinite(m_vecs).all()
|
||||||
|
assert numpy.isfinite(n_vecs).all()
|
||||||
|
|
||||||
|
numpy.testing.assert_allclose(norm(m_vecs.reshape(-1, 3), axis=1), 1.0)
|
||||||
|
numpy.testing.assert_allclose(norm(n_vecs.reshape(-1, 3), axis=1), 1.0)
|
||||||
|
numpy.testing.assert_allclose(numpy.sum(m_vecs * n_vecs, axis=3), 0.0, atol=1e-12)
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_kmn_z_aligned_uses_default_transverse_basis() -> None:
|
||||||
|
k_mag, m_vecs, n_vecs = bloch.generate_kmn([0.0, 0.0, 0.25], G_MATRIX, (1, 1, 1))
|
||||||
|
|
||||||
|
assert numpy.isfinite(k_mag).all()
|
||||||
|
numpy.testing.assert_allclose(m_vecs[0, 0, 0], [0.0, 1.0, 0.0])
|
||||||
|
numpy.testing.assert_allclose(numpy.sum(m_vecs * n_vecs, axis=3), 0.0, atol=1e-12)
|
||||||
|
numpy.testing.assert_allclose(norm(n_vecs.reshape(-1, 3), axis=1), 1.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_maxwell_operator_returns_finite_column_vector_without_mu() -> None:
|
||||||
|
operator = bloch.maxwell_operator(K0, G_MATRIX, EPSILON)
|
||||||
|
|
||||||
|
result = operator(H_MN.copy())
|
||||||
|
zero_result = operator(ZERO_H_MN.copy())
|
||||||
|
|
||||||
|
assert result.shape == (2 * numpy.prod(SHAPE), 1)
|
||||||
|
assert numpy.isfinite(result).all()
|
||||||
|
numpy.testing.assert_allclose(zero_result, 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_maxwell_operator_returns_finite_column_vector_with_mu() -> None:
|
||||||
|
operator = bloch.maxwell_operator(K0, G_MATRIX, EPSILON, MU)
|
||||||
|
|
||||||
|
result = operator(H_MN.copy())
|
||||||
|
zero_result = operator(ZERO_H_MN.copy())
|
||||||
|
|
||||||
|
assert result.shape == (2 * numpy.prod(SHAPE), 1)
|
||||||
|
assert numpy.isfinite(result).all()
|
||||||
|
numpy.testing.assert_allclose(zero_result, 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_inverse_maxwell_operator_returns_finite_column_vector_for_both_mu_branches() -> None:
|
||||||
|
for mu in (None, MU):
|
||||||
|
operator = bloch.inverse_maxwell_operator_approx(K0, G_MATRIX, EPSILON, mu)
|
||||||
|
|
||||||
|
result = operator(H_MN.copy())
|
||||||
|
zero_result = operator(ZERO_H_MN.copy())
|
||||||
|
|
||||||
|
assert result.shape == (2 * numpy.prod(SHAPE), 1)
|
||||||
|
assert numpy.isfinite(result).all()
|
||||||
|
numpy.testing.assert_allclose(zero_result, 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bloch_field_converters_return_finite_fields() -> None:
|
||||||
|
e_field = bloch.hmn_2_exyz(K0, G_MATRIX, EPSILON)(H_MN.copy())
|
||||||
|
h_field = bloch.hmn_2_hxyz(K0, G_MATRIX, EPSILON)(H_MN.copy())
|
||||||
|
|
||||||
|
assert e_field.shape == (3, *SHAPE)
|
||||||
|
assert h_field.shape == (3, *SHAPE)
|
||||||
|
assert numpy.isfinite(e_field).all()
|
||||||
|
assert numpy.isfinite(h_field).all()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue