def test_interpolate_is_same_as_direct_computation(self): k = 2 * np.pi / 0.66 rho = np.linspace(0, 15, 151) phi = np.linspace(0, 8 * np.pi, rho.size) # Test over a few particle parameters: radii = [0.5, 1.5, 6.5] zs = [5.0, 10.0, -10.] index_ratios = [1.1, 1.2, 1.3] for rad, z, index_ratio in itertools.product(radii, zs, index_ratios): kz = k * z ka = k * rad kwargs = {'particle_kz': kz, 'size_parameter': ka, 'index_ratio': index_ratio, 'lens_angle': 1.0, } direct_calculator = mielensfunctions.MieLensCalculator( interpolate_integrals=False, **kwargs) interpolating_calculator = mielensfunctions.MieLensCalculator( interpolate_integrals=True, **kwargs) fdx, fdy = direct_calculator.calculate_scattered_field( k * rho, phi) fix, fiy = interpolating_calculator.calculate_scattered_field( k * rho, phi) with self.subTest(rad=rad, z=z, index_ratio=index_ratio): close_enough_x = np.allclose(fdx, fix, **TOLS) close_enough_y = np.allclose(fdy, fiy, **TOLS) self.assertTrue(close_enough_x) self.assertTrue(close_enough_y)
def test_holopy_hologram_equal_to_exact_calculation(self): # Checks that phase shifts and wrappers for mielens are correct theory_mielens = MieLens() illum_wavelength = 0.66 # 660 nm red light k = 2 * np.pi / illum_wavelength center = (10, 10, 5.) kwargs = {'particle_kz': center[2] * k, 'index_ratio': 1.2, 'size_parameter': 0.5 * k, 'lens_angle': theory_mielens.lens_angle} detector = detector_grid(10, 2.0) x = detector.x.values.reshape(-1, 1) - center[0] y = detector.y.values.reshape(1, -1) - center[1] rho = np.sqrt(x**2 + y**2) phi = np.arctan2(y, x) calculator = mielensfunctions.MieLensCalculator(**kwargs) scatterer = Sphere(n=kwargs['index_ratio'], r=kwargs['size_parameter'] / k, center=center) holo_calculate = calculator.calculate_total_intensity(k * rho, phi) holo_holopy = calc_holo( detector, scatterer, illum_wavelen=illum_wavelength, medium_index=1., illum_polarization=(1, 0), theory=theory_mielens) is_ok = np.allclose(holo_calculate, holo_holopy.values.squeeze(), **TOLS) self.assertTrue(is_ok)
def test_raises_error_integral_is_not_i0_or_i2(self): miecalculator = mielensfunctions.MieLensCalculator( particle_kz=10, index_ratio=1.2, size_parameter=10.0, lens_angle=0.9) krho = np.linspace(0, 30, 300) self.assertRaises( ValueError, miecalculator._eval_mielens_i_n, krho, n=1)
def evaluate_intensity_at_rho_zero(kz, index_ratio=1.05): miecalculator = mielensfunctions.MieLensCalculator(particle_kz=kz, index_ratio=index_ratio, size_parameter=10, lens_angle=0.8) krho = np.array([0]) return miecalculator.calculate_total_intensity(krho, 0 * krho)
def test_calculation_doesnt_crash_for_large_rho(self): miecalculator = mielensfunctions.MieLensCalculator( particle_kz=10, index_ratio=1.2, size_parameter=10., lens_angle=0.9) krho = np.linspace(1000, 1100, 10) kphi = np.full_like(krho, 0.25 * np.pi) fields = miecalculator.calculate_scattered_field(krho, kphi) self.assertTrue(fields is not None)
def evaluate_scattered_field_in_lens(delta_index=0.1, size_parameter=0.1): miecalculator = mielensfunctions.MieLensCalculator( particle_kz=10, index_ratio=1.0 + delta_index, size_parameter=size_parameter, lens_angle=0.9) krho = np.linspace(0, 30, 300) # for phi, we pick an off-axis value where both polarizations are nonzero kphi = np.full_like(krho, 0.25 * np.pi) return miecalculator.calculate_scattered_field(krho, kphi) # x,y component
def test_fields_go_to_zero_at_large_distances(self): rho = np.logspace(2.4, 5, 80) calculator = mielensfunctions.MieLensCalculator( size_parameter=10, lens_angle=1.0, particle_kz=10., index_ratio=1.1) field_x, field_y = calculator.calculate_scattered_field(rho, 0*rho) fields_dont_explode = np.all(np.abs(field_x < 2e-4)) self.assertTrue(fields_dont_explode)
def test_raises_error_when_inputs_mismatched_size(self): miecalculator = mielensfunctions.MieLensCalculator( particle_kz=10, index_ratio=1.2, size_parameter=10.0, lens_angle=0.9) krho = np.linspace(0, 30, 300) phi = np.full(krho.size - 4, 0.25 * np.pi) self.assertRaises( ValueError, miecalculator.calculate_scattered_field, krho, phi)
def calc_holo_mielens(center0, center1, center2, n, r, lens_angle): params = { 'particle_kz': k * center2, 'index_ratio': n / index_water, 'size_parameter': k * r, 'lens_angle': lens_angle, } calc = mielensfunctions.MieLensCalculator(**params) dx = x - center0 dy = y - center1 rho = np.sqrt(dx**2 + dy**2) phi = np.arctan2(dy, dx) return calc.calculate_total_intensity(k * rho, phi)
def test_xpolarization_is_larger_along_phi_equals_0(self): fieldcalc = mielensfunctions.MieLensCalculator( particle_kz=0.0, index_ratio=1.19, size_parameter=0.1, lens_angle=0.8) krho = np.linspace(0.1, 2, 30) phi_0 = np.zeros(krho.shape) phi_pi4 = phi_0 + np.pi / 4. fx_0, fy_0 = fieldcalc.calculate_scattered_field(krho, phi_0) fx_pi4, fy_pi4 = fieldcalc.calculate_scattered_field(krho, phi_pi4) is_ok = fx_0.real > fx_pi4.real self.assertTrue(np.all(is_ok))
def get_excess_power(max_x, npts): """Calculates (total power) - (power at detector) This should be _negative_, slightly, as some of the scattered beam does not enter the lens""" t = np.linspace(-max_x, max_x, npts) x = t.reshape(-1, 1) y = t.reshape(1, -1) dt = t[1] - t[0] dA = dt**2 rho = np.sqrt(x**2 + y**2) phi = np.arctan2(y, x) k = 2 * np.pi / 0.66 * 1.33 kwargs = {'particle_kz': 5 * k, 'index_ratio': 1.59 / 1.33, 'size_parameter': k * 0.5, 'lens_angle': 0.8, } calc = mielensfunctions.MieLensCalculator(**kwargs) hologram = calc.calculate_total_intensity(k*rho, phi) excess_power = dA * (hologram - 1).sum() return excess_power
def get_ratio_of_scattered_powerin_to_scattered_powerout(**kwargs): mielenscalc = mielensfunctions.MieLensCalculator(**kwargs) checker = CheckEnergyIsConserved(mielenscalc) power_in = checker.evaluate_scattered_power_incident_on_pupil() power_out = checker.evaluate_scattered_power_incident_on_detector() return power_in / power_out
def create_calculator(**kwargs): return mielensfunctions.MieLensCalculator(**kwargs)
def test_fields_are_correct_values(self): # Tests fields are correct for a sphere 5 um above the focus # 1. Setup k = 2 * np.pi / 0.66 # 660 nm red light kwargs = {'particle_kz': 5.0 * k, 'index_ratio': 1.1, 'size_parameter': 0.5 * k, # 1 um sphere = 0.5 um radius 'lens_angle': 0.8} calculator = mielensfunctions.MieLensCalculator(**kwargs) # 2. Calculate # We calculate at 3 angles: phi=0, pi/4, pi/2: rho = np.linspace(0, 10., 15) phi_0 = np.full(rho.size, 0) phi_pi4 = np.full(rho.size, np.pi / 4) phi_pi2 = np.full(rho.size, np.pi / 2) field_0 = calculator.calculate_scattered_field(k * rho, phi_0) field_pi4 = calculator.calculate_scattered_field(k * rho, phi_pi4) field_pi2 = calculator.calculate_scattered_field(k * rho, phi_pi2) truefield_0 = ( np.array([-1.32809510e-01+0.08146271j, -9.06794903e-02+0.1172825j , 8.21893968e-02+0.08204799j, 7.56371204e-03-0.08694946j, -6.16821976e-03+0.05753421j, -1.28205169e-02-0.02865722j, 1.52658533e-02+0.00194537j, -4.02116676e-03+0.00734771j, -3.67872355e-03-0.00180371j, 1.60209148e-03-0.00231238j, 1.70980783e-03+0.0002438j , -5.04523640e-04+0.00112576j, -1.11374256e-03+0.00025535j, 4.17810243e-05-0.00059301j, 7.81002777e-04-0.00039032j]), np.array([0.+0.j, 0.+0.j, 0.-0.j, -0.+0.j, 0.+0.j, 0.+0.j, 0.-0.j, 0.+0.j, 0.+0.j, -0.+0.j, 0.-0.j, 0.+0.j, 0.+0.j, -0.+0.j, 0.-0.j])) truefield_pi4 = ( np.array([-1.32809510e-01+8.14627106e-02j, -9.10453076e-02+1.17600194e-01j, 8.35512121e-02+8.30232340e-02j, 8.14492728e-03-8.96475613e-02j, -7.20628427e-03+6.07260692e-02j, -1.33209135e-02-3.11720004e-02j, 1.68662078e-02+2.68433934e-03j, -4.88607511e-03+7.98665504e-03j, -4.02303040e-03-2.38353337e-03j, 2.01334697e-03-2.43175325e-03j, 1.86014012e-03+5.10936483e-04j, -6.88469988e-04+1.18558752e-03j, -1.23001081e-03+1.16072274e-04j, 1.22899446e-04-6.46969142e-04j, 8.78058364e-04-3.11103837e-04j]), np.array([ 0.00000000e+00+0.00000000e+00j, 3.65817305e-04-3.17693628e-04j, -1.36181529e-03-9.75243907e-04j, -5.81215242e-04+2.69810296e-03j, 1.03806451e-03-3.19185972e-03j, 5.00396567e-04+2.51477939e-03j, -1.60035452e-03-7.38974073e-04j, 8.64908349e-04-6.38943288e-04j, 3.44306845e-04+5.79818489e-04j, -4.11255487e-04+1.19369202e-04j, -1.50332293e-04-2.67135310e-04j, 1.83946348e-04-5.98313492e-05j, 1.16268243e-04+1.39275966e-04j, -8.11184216e-05+5.39575376e-05j, -9.70555866e-05-7.92120153e-05j])) truefield_pi2 = ( np.array([-0.13280951+8.14627106e-02j, -0.09141112+1.17917888e-01j, 0.08491303+8.39984779e-02j, 0.00872614-9.23456643e-02j, -0.00824435+6.39179289e-02j, -0.01382131-3.36867798e-02j, 0.01846656+3.42331341e-03j, -0.00575098+8.62559833e-03j, -0.00436734-2.96335185e-03j, 0.0024246 -2.55112245e-03j, 0.00201047+7.78071792e-04j, -0.00087242+1.24541887e-03j, -0.00134628-2.32036918e-05j, 0.00020402-7.00926680e-04j, 0.00097511-2.31891822e-04j]), np.array([ 0.00000000e+00+0.00000000e+00j, 4.47996992e-20-3.89062485e-20j, -1.66774273e-19-1.19432933e-19j, -7.11783386e-20+3.30422315e-19j, 1.27126238e-19-3.90890079e-19j, 6.12809053e-20+3.07971653e-19j, -1.95986904e-19-9.04982233e-20j, 1.05920724e-19-7.82479853e-20j, 4.21654276e-20+7.10072856e-20j, -5.03642716e-20+1.46185111e-20j, -1.84103962e-20-3.27146402e-20j, 2.25269306e-20-7.32722703e-21j, 1.42387532e-20+1.70563866e-20j, -9.93414154e-21+6.60789257e-21j, -1.18858814e-20-9.70067410e-21j])) # compare; medtols b/c fields are only copied to 9 digits self.assertTrue(np.allclose(field_0, truefield_0, **MEDTOLS)) self.assertTrue(np.allclose(field_pi2, truefield_pi2, **MEDTOLS)) self.assertTrue(np.allclose(field_pi4, truefield_pi4, **MEDTOLS))