add acf and psdf nodes
This commit is contained in:
@@ -2316,7 +2316,7 @@ def test_line_cursors():
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# Analysis — FFT2D
|
||||
# Analysis — FFT2D / ACF / PSDF
|
||||
# =========================================================================
|
||||
|
||||
def test_fft2d():
|
||||
@@ -2374,6 +2374,86 @@ def test_fft2d():
|
||||
print(" PASS\n")
|
||||
|
||||
|
||||
def test_acf():
|
||||
print("=== Test: ACF ===")
|
||||
from backend.nodes.acf import ACF
|
||||
|
||||
node = ACF()
|
||||
data = np.array([
|
||||
[1.0, 2.0, 3.0, 4.0],
|
||||
[5.0, 6.0, 7.0, 8.0],
|
||||
[2.0, 1.0, 0.0, -1.0],
|
||||
[0.0, 1.0, 2.0, 3.0],
|
||||
], dtype=np.float64)
|
||||
field = DataField(data=data, xreal=8.0, yreal=4.0, si_unit_xy="nm", si_unit_z="V")
|
||||
|
||||
acf, = node.process(field, level="none")
|
||||
assert acf.data.shape == (3, 3)
|
||||
assert acf.domain == "spatial"
|
||||
assert acf.si_unit_xy == "nm"
|
||||
assert acf.si_unit_z == "V^2"
|
||||
assert np.isclose(acf.xreal, 6.0)
|
||||
assert np.isclose(acf.yreal, 3.0)
|
||||
assert np.isclose(acf.xoff, -3.0)
|
||||
assert np.isclose(acf.yoff, -1.5)
|
||||
|
||||
expected = np.zeros((3, 3), dtype=np.float64)
|
||||
for iy, dy in enumerate(range(-1, 2)):
|
||||
for ix, dx in enumerate(range(-1, 2)):
|
||||
y0a = max(0, dy)
|
||||
y1a = min(data.shape[0], data.shape[0] + dy)
|
||||
x0a = max(0, dx)
|
||||
x1a = min(data.shape[1], data.shape[1] + dx)
|
||||
lhs = data[y0a:y1a, x0a:x1a]
|
||||
rhs = data[y0a - dy:y1a - dy, x0a - dx:x1a - dx]
|
||||
expected[iy, ix] = float(np.mean(lhs * rhs))
|
||||
|
||||
assert np.allclose(acf.data, expected)
|
||||
assert np.allclose(acf.data, acf.data[::-1, ::-1])
|
||||
print(" PASS\n")
|
||||
|
||||
|
||||
def test_psdf_node():
|
||||
print("=== Test: PSDF ===")
|
||||
from backend.nodes.fft_2d import FFT2D
|
||||
from backend.nodes.psdf import PSDF
|
||||
|
||||
field = DataField(
|
||||
data=np.random.default_rng(17).standard_normal((64, 64)),
|
||||
xreal=2.0e-6,
|
||||
yreal=1.0e-6,
|
||||
si_unit_xy="m",
|
||||
si_unit_z="nm",
|
||||
)
|
||||
|
||||
fft_node = FFT2D()
|
||||
psdf_node = PSDF()
|
||||
|
||||
fft_psdf = fft_node.process(field, windowing="hann", level="plane")[3]
|
||||
psdf, = psdf_node.process(field, windowing="hann", level="plane")
|
||||
assert np.allclose(psdf.data, fft_psdf.data)
|
||||
assert psdf.data.shape == field.data.shape
|
||||
assert psdf.domain == "frequency"
|
||||
assert psdf.si_unit_xy == "1/m"
|
||||
assert psdf.si_unit_z == "nm^2 m^2"
|
||||
assert np.all(psdf.data >= 0.0)
|
||||
|
||||
white = DataField(
|
||||
data=np.random.default_rng(123).standard_normal((128, 128)),
|
||||
xreal=1.0e-6,
|
||||
yreal=1.0e-6,
|
||||
si_unit_xy="m",
|
||||
si_unit_z="m",
|
||||
)
|
||||
psdf_white, = psdf_node.process(white, windowing="none", level="none")
|
||||
variance = float(np.var(white.data))
|
||||
dk_x = psdf_white.xreal / psdf_white.xres
|
||||
dk_y = psdf_white.yreal / psdf_white.yres
|
||||
integral = float(np.sum(psdf_white.data) * dk_x * dk_y)
|
||||
assert 0.8 < integral / variance < 1.2
|
||||
print(" PASS\n")
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# Analysis — Stats
|
||||
# =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user