Files
cdtools/tests/tools/test_analysis.py
T

101 lines
3.7 KiB
Python

from __future__ import division, print_function, absolute_import
import pytest
import numpy as np
import torch as t
from itertools import combinations
from CDTools.tools import analysis, cmath, initializers
def test_orthogonalize_probes():
# The test strategy should be to define a few non-orthogonal probes
# and orthogonalize them. Then we can test two features of the results:
# 1) Are they orthogonal?
# 2) Is the total intensity at each point the same as it was originally?
probe_xs = np.arange(128) - 64
probe_ys = np.arange(150) - 75
probe_Ys, probe_Xs = np.meshgrid(probe_ys, probe_xs)
probe_Rs = np.sqrt(probe_Xs**2 + probe_Ys**2)
probes = np.array([10*np.exp(-probe_Rs**2 / (2 * 10**2)),
3*np.exp(-probe_Rs**2 / (2 * 12**2)),
1*np.exp(-probe_Rs**2 / (2 * 15**2))]).astype(np.complex64)
ortho_probes = cmath.torch_to_complex(analysis.orthogonalize_probes(probes))
for p1,p2 in combinations(ortho_probes,2):
assert np.sum(np.conj(p1)*p2) / np.sum(np.abs(p1)**2) < 1e-6
for probe in ortho_probes:
print(np.sum(np.abs(probe)**2))
for probe in probes:
print(np.sum(np.abs(probe)**2))
probe_intensity = np.sum(np.abs(probes)**2,axis=0)
ortho_probe_intensity = np.sum(np.abs(ortho_probes)**2,axis=0)
assert np.allclose(probe_intensity,ortho_probe_intensity)
from matplotlib import pyplot as plt
def test_standardize():
# Start by making a probe and object that should meet the standardization
# conditions
probe = initializers.gaussian((230,240),(20,20),curvature=(0.01,0.01))
probe = cmath.torch_to_complex(probe)
probe = probe * np.sqrt(len(probe.ravel()) / np.sum(np.abs(probe)**2))
probe = probe * np.exp(-1j * np.angle(np.sum(probe)))
assert np.isclose(1, np.sum(np.abs(probe)**2)/ len(probe.ravel()))
assert np.isclose(0,np.angle(np.sum(probe)))
obj = 30 * np.random.rand(230,240) * np.exp(1j * (np.random.rand(230,240) - 0.5))
obj_slice = np.s_[(obj.shape[0]//8)*3:(obj.shape[0]//8)*5,
(obj.shape[1]//8)*3:(obj.shape[1]//8)*5]
obj = obj * np.exp(-1j * np.angle(np.sum(obj[obj_slice])))
assert np.isclose(0,np.angle(np.sum(obj[obj_slice])))
# Then make a nonstandard version of them and standardize it
# First, don't add a phase ramp and test
test_probe = probe * 37.6 * np.exp(1j*0.35)
test_obj = obj / 37.6 * np.exp(1j*1.43)
s_probe, s_obj = analysis.standardize(test_probe, test_obj)
assert np.allclose(probe, s_probe)
assert np.allclose(obj, s_obj)
# Test that it works on torch tensors
s_probe, s_obj = analysis.standardize(cmath.complex_to_torch(test_probe).to(t.float32), cmath.complex_to_torch(test_obj).to(t.float32))
s_probe = cmath.torch_to_complex(s_probe)
s_obj = cmath.torch_to_complex(s_obj)
assert np.allclose(probe, s_probe)
assert np.allclose(obj, s_obj)
# And ensure that standardization maps back to the standard versions
phase_ramp_dir = (np.random.rand(2) - 0.5)
probe_Xs, probe_Ys = np.mgrid[:probe.shape[0],:probe.shape[1]]
phase_ramp = np.exp(1j*probe_Ys * phase_ramp_dir[1]+
1j*probe_Xs * phase_ramp_dir[0])
test_probe = test_probe * phase_ramp
obj_Xs, obj_Ys = np.mgrid[:obj.shape[0],:obj.shape[1]]
phase_ramp = np.exp(-1j*obj_Ys * phase_ramp_dir[1]+
-1j*obj_Xs * phase_ramp_dir[0])
test_obj = test_obj * phase_ramp
s_probe, s_obj = analysis.standardize(test_probe, test_obj, correct_ramp=True)
assert np.max(s_probe - probe) / np.max(np.abs(probe)) < 1e-4
assert np.max(s_obj - obj) / np.max(np.abs(obj)) < 1e-4