def spherical_wave_expansion(self, particle, layer_system): """Regular spherical wave expansion of the dipole collection including layer system response, at the locations of the particles. If self.compute_swe_by_pwe is True, use the dipole collection plane wave expansion, otherwise use the individual dipoles spherical_wave_expansion method. 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 """ # compute by pwe? if self.compute_swe_by_pwe and not any( layer_system.layer_number(particle.position[2]) == np.array([ layer_system.layer_number(dip.position[2]) for dip in self.dipole_list ])): # (make sure the particle is not in the same layer as one of the dipoles) return InitialPropagatingWave.spherical_wave_expansion( self, particle, layer_system) # otherwise, compute by swe of virtual particles 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) for dipole in self.dipole_list: swe = swe + dipole.spherical_wave_expansion(particle, layer_system) return swe
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 outgoing_spherical_wave_expansion(self, layer_system): """The dipole field as an expansion in spherical vector wave functions. Args: layer_system (smuthi.layers.LayerSystem): stratified medium Returns: outgoing smuthi.field_expansion.SphericalWaveExpansion object """ laynum = layer_system.layer_number(self.position[2]) k = layer_system.refractive_indices[laynum] * self.angular_frequency() swe_out = fldex.SphericalWaveExpansion( k=k, l_max=1, m_max=1, kind='outgoing', reference_point=self.position, lower_z=layer_system.lower_zlimit(laynum), upper_z=layer_system.upper_zlimit(laynum)) l = 1 for tau in range(2): for m in range(-1, 2): ex, ey, ez = vwf.spherical_vector_wave_function( 0, 0, 0, k, 1, tau, l, -m) b = 1j * k / np.pi * 1j * self.angular_frequency() * ( ex * self.current()[0] + ey * self.current()[1] + ez * self.current()[2]) swe_out.coefficients[fldex.multi_to_single_index( tau, l, m, 1, 1)] = b return swe_out
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
kp_vec5 = np.linspace(0, 6, 1000) * k + 1.01 * k kp = np.concatenate([kp_vec1, kp_vec2, kp_vec3, kp_vec4, kp_vec5]) a = np.linspace(0, 2 * np.pi, num=200) pwe_ref = [-100, -100, -100] swe_ref = [-400, 200, 500] fieldpoint = [-500, 310, 620] vb = [0, 800] layer_system = lay.LayerSystem([0, 0], [1, 1]) x = np.array([fieldpoint[0]]) y = np.array([fieldpoint[1]]) z = np.array([fieldpoint[2]]) swe = fldex.SphericalWaveExpansion(k=k, l_max=3, m_max=3, kind='outgoing', reference_point=swe_ref) swe.coefficients[0] = 2 swe.coefficients[1] = -3j swe.coefficients[16] = 1 swe.coefficients[18] = 0.5 kp2 = np.linspace(0, 2, num=1000) * k pwe = fldex.PlaneWaveExpansion(k=k, k_parallel=kp2, azimuthal_angles=a, kind='upgoing', reference_point=pwe_ref, lower_z=vb[0], upper_z=vb[1]) pwe.coefficients[0, :, :] = 100000 * np.exp(- pwe.k_parallel_grid() / k / 20) pwe.coefficients[1, :, :] = -100000 * np.exp(- pwe.k_parallel_grid() / k / 10) def test_swe2pwe(): ex, ey, ez = swe.electric_field(x, y, z) pwe_up, pwe_down = fldex.swe_to_pwe_conversion(swe, k_parallel=kp, azimuthal_angles=a, layer_system=layer_system)
def solve(self): """Compute scattered field coefficients and store them in the particles' spherical wave expansion objects.""" if len(self.particle_list) > 0: if self.solver_type == 'LU': sys.stdout.write('Solve (LU decomposition) : ...') if not hasattr(self.master_matrix.linear_operator, 'A'): raise ValueError( 'LU factorization only possible ' 'with the option "store coupling matrix".') if not hasattr(self.master_matrix, 'LU_piv'): lu, piv = scipy.linalg.lu_factor( self.master_matrix.linear_operator.A, overwrite_a=False) self.master_matrix.LU_piv = (lu, piv) b = scipy.linalg.lu_solve(self.master_matrix.LU_piv, self.t_matrix.right_hand_side()) sys.stdout.write(' done\n') sys.stdout.flush() elif self.solver_type == 'gmres': rhs = self.t_matrix.right_hand_side() start_time = time.time() def status_msg(rk): global iter_num iter_msg = ('Solve (GMRES) : Iter ' + str(iter_num) + ' | Rel. residual: ' + "{:.2e}".format(np.linalg.norm(rk)) + ' | elapsed: ' + str(int(time.time() - start_time)) + 's') sys.stdout.write('\r' + iter_msg) iter_num += 1 global iter_num iter_num = 0 b, info = scipy.sparse.linalg.gmres( self.master_matrix.linear_operator, rhs, rhs, tol=self.solver_tolerance, callback=status_msg) # sys.stdout.write('\n') else: raise ValueError( 'This solver type is currently not implemented.') for iS, particle in enumerate(self.particle_list): i_iS = self.layer_system.layer_number(particle.position[2]) n_iS = self.layer_system.refractive_indices[i_iS] k = coord.angular_frequency( self.initial_field.vacuum_wavelength) * n_iS loz, upz = self.layer_system.lower_zlimit( i_iS), self.layer_system.upper_zlimit(i_iS) particle.scattered_field = fldex.SphericalWaveExpansion( k=k, l_max=particle.l_max, m_max=particle.m_max, kind='outgoing', reference_point=particle.position, lower_z=loz, upper_z=upz) particle.scattered_field.coefficients = b[ self.master_matrix.index_block(iS)]