def spherical_wave_expansion(self, particle, layer_system): """Regular spherical wave expansion of the wave including layer system response, at the locations of the particles. Args: particle (smuthi.particles.Particle): particle relative to which the swe is computed layer_system (smuthi.layer.LayerSystem): stratified medium Returns: regular smuthi.field_expansion.SphericalWaveExpansion object """ virtual_particle = part.Particle(position=self.position, l_max=1, m_max=1) wd = pc.direct_coupling_block(vacuum_wavelength=self.vacuum_wavelength, receiving_particle=particle, emitting_particle=virtual_particle, layer_system=layer_system) wr = pc.layer_mediated_coupling_block( vacuum_wavelength=self.vacuum_wavelength, receiving_particle=particle, emitting_particle=virtual_particle, layer_system=layer_system, k_parallel=self.k_parallel) k = self.angular_frequency() * layer_system.refractive_indices[ layer_system.layer_number(particle.position[2])] swe = fldex.SphericalWaveExpansion(k=k, l_max=particle.l_max, m_max=particle.m_max, kind='regular', reference_point=particle.position) swe.coefficients = np.dot( wd + wr, self.outgoing_spherical_wave_expansion(layer_system).coefficients) return swe
def test_w_against_wr(): coord.set_default_k_parallel(wl, [0, 0.8, 0.8 - 0.1j, 2.1 - 0.1j, 2.1, 7], 2e-3) laysys_air_1 = lay.LayerSystem(thicknesses=[0, 0], refractive_indices=[1, 1]) laysys_air_2 = lay.LayerSystem(thicknesses=[0, 250, 0], refractive_indices=[1, 1, 1]) part1 = part.Sphere(position=[100, -100, 200], refractive_index=1.7, radius=100, l_max=2, m_max=2) part2 = part.Sphere(position=[-100, 200, 400], refractive_index=1.7, radius=100, l_max=2, m_max=2) w_air_1 = coup.direct_coupling_block(wl, part1, part2, laysys_air_1) wr_air_2 = coup.layer_mediated_coupling_block(wl, part1, part2, laysys_air_2) error = wr_air_2 - w_air_1 np.testing.assert_almost_equal(wr_air_2, w_air_1, decimal=4)
def __init__(self, vacuum_wavelength, particle_list, layer_system, k_parallel='default'): SystemMatrix.__init__(self, particle_list) coup_mat = np.zeros(self.shape, dtype=complex) sys.stdout.write('Coupling matrix memory footprint: ' + coup.size_format(coup_mat.nbytes) + '\n') sys.stdout.flush() for s1, particle1 in enumerate( tqdm(particle_list, desc='Particle coupling matrix ', file=sys.stdout, bar_format='{l_bar}{bar}| elapsed: {elapsed} ' 'remaining: {remaining}')): idx1 = np.array(self.index_block(s1))[:, None] for s2, particle2 in enumerate(particle_list): idx2 = self.index_block(s2) coup_mat[idx1, idx2] = (coup.layer_mediated_coupling_block( vacuum_wavelength, particle1, particle2, layer_system, k_parallel) + coup.direct_coupling_block( vacuum_wavelength, particle1, particle2, layer_system)) self.linear_operator = scipy.sparse.linalg.aslinearoperator(coup_mat)
def test_w_against_prototype(): part1 = part.Sphere(position=[100, -100, 200], refractive_index=1.7, radius=100, l_max=2, m_max=2) part2 = part.Sphere(position=[-100, 200, 300], refractive_index=1.7, radius=100, l_max=2, m_max=2) part3 = part.Sphere(position=[200, 200, -300], refractive_index=1.7, radius=100, l_max=2, m_max=2) laysys_waveguide = lay.LayerSystem(thicknesses=[0, 500, 0], refractive_indices=[1, 2, 1]) w_wg11 = coup.direct_coupling_block(wl, part1, part1, laysys_waveguide) w_wg12 = coup.direct_coupling_block(wl, part1, part2, laysys_waveguide) w_wg13 = coup.direct_coupling_block(wl, part1, part3, laysys_waveguide) w_wg_0010 = 0.078085976865533 + 0.054600388160436j assert abs((w_wg12[0, 0] - w_wg_0010) / w_wg_0010) < 1e-5 w_wg_0110 = -0.014419231182754 + 0.029269376752105j assert abs((w_wg12[1, 0] - w_wg_0110) / w_wg_0110) < 1e-5 w_wg_0912 = -0.118607476554146 + 0.020532217124574j assert abs((w_wg12[9, 2] - w_wg_0912) / w_wg_0912) < 1e-5 assert np.linalg.norm(w_wg11) == 0 # no direct self interaction assert np.linalg.norm( w_wg13 ) == 0 # no direct interaction between particles in different layers
def dissipated_power(self, particle_list, layer_system, show_progress=True): r"""Compute the power that the dipole feeds into the system. It is computed according to .. math:: P = P_0 + \frac{\omega}{2} \mathrm{Im} (\mathbf{\mu}^* \cdot \mathbf{E}(\mathbf{r}_D)) where :math:`P_0` is the power that the dipole would feed into an infinte homogeneous medium with the same refractive index as the layer that contains the dipole, :math:`\mathbf{r}_D` is the location of the dipole, :math:`\omega` is the angular frequency, :math:`\mathbf{\mu}` is the dipole moment and :math:`\mathbf{E}` includes the reflections of the dipole field from the layer interfaces, as well as the scattered field from all particles. Args: particle_list (list of smuthi.particles.Particle objects): scattering particles layer_system (smuthi.layers.LayerSystem): stratified medium show_progress (bool): if true, display progress Returns: dissipated power as float """ k = layer_system.wavenumber( layer_system.layer_number(self.position[2]), self.vacuum_wavelength) virtual_particle = part.Particle(position=self.position, l_max=1, m_max=1) scattered_field_swe = fldex.SphericalWaveExpansion( k=k, l_max=1, m_max=1, kind='regular', reference_point=self.position) if show_progress: iterator = tqdm( particle_list, desc='Dipole dissipated power ', file=sys.stdout, bar_format= '{l_bar}{bar}| elapsed: {elapsed} remaining: {remaining}') else: iterator = particle_list for particle in iterator: wd = pc.direct_coupling_block( vacuum_wavelength=self.vacuum_wavelength, receiving_particle=virtual_particle, emitting_particle=particle, layer_system=layer_system) wr = pc.layer_mediated_coupling_block( vacuum_wavelength=self.vacuum_wavelength, receiving_particle=virtual_particle, emitting_particle=particle, layer_system=layer_system, k_parallel=self.k_parallel) scattered_field_swe.coefficients += np.dot( wd + wr, particle.scattered_field.coefficients) e_x_scat, e_y_scat, e_z_scat = scattered_field_swe.electric_field( x=self.position[0], y=self.position[1], z=self.position[2]) e_x_in, e_y_in, e_z_in = self.electric_field( x=self.position[0], y=self.position[1], z=self.position[2], layer_system=layer_system, include_direct_field=False) power = self.angular_frequency() / 2 * ( np.conjugate(self.dipole_moment[0]) * (e_x_scat + e_x_in) + np.conjugate(self.dipole_moment[1]) * (e_y_scat + e_y_in) + np.conjugate(self.dipole_moment[2]) * (e_z_scat + e_z_in)).imag return self.dissipated_power_homogeneous_background( layer_system) + power
# Test fails for mmax != lmax, # Computation of matrix elements in the laboratory coordinate system of degree l # require the knowledge of all orders m of same degree l: m = (-l, -l + 1, ..., l - 1, l) # see e.g.: Mishchenko et al., Scattering, Absorption, and Emission of Light by Small Particles, # Cambridge University Press, 2002. Eq. (5.29) p. 120 #spheroid1 = part.Spheroid(position=[0, 0, 400],euler_angles=[0, 0, 0], # refractive_index=2.4 + 0.0j, semi_axis_c=50, semi_axis_a=100, l_max=2, m_max=1) # #spheroid2 = part.Spheroid(position=[0,0,0],euler_angles=[0, 0, 0], # refractive_index=2.4 + 0.0j, semi_axis_c=100, semi_axis_a=50, l_max=2, m_max=2) # conventional coupling using svwf addition theorem W = pacou.direct_coupling_block(vacuum_wavelength=wl, receiving_particle=spheroid2, emitting_particle=spheroid1, layer_system=lay_sys) # plane wave coupling k_parallel = coord.complex_contour( vacuum_wavelength=wl, neff_waypoints=[0, 0.9, 0.9 - 0.1j, 1.1 - 0.1j, 1.1, 7], neff_resolution=1e-3) W_pvwf = pacou.direct_coupling_block_pvwf_mediated( vacuum_wavelength=wl, receiving_particle=spheroid2, emitting_particle=spheroid1, layer_system=lay_sys, k_parallel=k_parallel)
refractive_index=1.7 + 0.0j, radius=90, l_max=3, m_max=3) particle_list = [sphere1, sphere2, sphere3] # initialize layer system object lay_sys = lay.LayerSystem([0, 400, 0], [1.5, 2 + 0.01j, 1]) phi12 = np.arctan2(sphere1.position[1] - sphere2.position[1], sphere1.position[0] - sphere2.position[0]) rho12 = np.sqrt( sum([(sphere1.position[i] - sphere2.position[i])**2 for i in range(3)])) wr12 = coup.layer_mediated_coupling_block(vacuum_wavelength, sphere1, sphere2, lay_sys) w12 = coup.direct_coupling_block(vacuum_wavelength, sphere1, sphere2, lay_sys) phi13 = np.arctan2(sphere1.position[1] - sphere3.position[1], sphere1.position[0] - sphere3.position[0]) rho13 = np.sqrt( sum([(sphere1.position[i] - sphere3.position[i])**2 for i in range(3)])) wr13 = coup.layer_mediated_coupling_block(vacuum_wavelength, sphere1, sphere3, lay_sys) w13 = coup.direct_coupling_block(vacuum_wavelength, sphere1, sphere3, lay_sys) # initialize initial field object init_fld = init.GaussianBeam(vacuum_wavelength=vacuum_wavelength, polar_angle=beam_polar_angle, azimuthal_angle=beam_azimuthal_angle, polarization=beam_polarization, amplitude=beam_amplitude,