Generalized Polarizabilties - Mode density and multiple illuminations¶
New functionalities in ``multipole`` added in v1.1.3
!!CAUTION!! : ``multipole`` is a new functionality. Please report possible problems and errors.
The generalized polarizabilities (GP) formalism is particularly interesting to calculate the total density of multipole modes of a nanostructure as well as to evaluate rapidly the multipole expansion of the response for various illuminations. How to do this technically is demonstrated in the following.
The GP formalism is based on the exact multipole expansion [1]. It is described in [2].
[1] Alaee, R., Rockstuhl, C. and Fernandez-Corbaton, I. An electromagnetic multipole expansion beyond the long-wavelength approximation. Optics Communications 407, 17-21 (2018)
[2] Majorel et al. Generalized polarizabilites for an exact multipole analysis of complex nanostructures under inhomogeneous illumination. arXiv (2022)
Setup and run simulation¶
[1]:
from __future__ import print_function, division
import numpy as np
import matplotlib.pyplot as plt
import copy
from pyGDM2 import structures
from pyGDM2 import materials
from pyGDM2 import fields
from pyGDM2 import tools
from pyGDM2 import propagators
from pyGDM2 import linear
from pyGDM2 import core
from pyGDM2 import visu
from pyGDM2 import multipole
# =============================================================================
# sim setup
# =============================================================================
method = 'lu'
#method = 'cupy'
## ----- set up single structure
step = 24
mat = materials.dummy(3.5)
geo = structures.spheroid(step, R1=10, R2=5, R3=5, mesh='hex')
struct = structures.struct(step, geo, mat)
struct = structures.center_struct(struct, which_axis=['x','y','z'])
## ----- illumination
wavelengths = np.linspace(500, 1500, 26)
field_generator = fields.plane_wave
field_kwargs = dict(E_s=0, E_p=1, inc_angle=0, inc_plane='xz') # lin-pol X, normal incidence from below
efield = fields.efield(field_generator, wavelengths=wavelengths, kwargs=copy.deepcopy(field_kwargs))
## ----- environment: vacuum
n1 = 1.0
dyads = propagators.DyadsQuasistatic123(n1)
## ----- simulation1
sim = core.simulation(struct=struct, efield=efield, dyads=dyads)
visu.structure(sim, tit='N dipoles = {}'.format(len(sim.struct.geometry)))
structure initialization - automatic mesh detection: hex
structure initialization - consistency check: 1639/1639 dipoles valid
/home/pwiecha/.local/lib/python3.8/site-packages/pyGDM2/visu.py:49: UserWarning: 3D data. Falling back to XY projection...
warnings.warn("3D data. Falling back to XY projection...")
![../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_1_2.png](../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_1_2.png)
[1]:
<matplotlib.collections.PathCollection at 0x7fc3b7a9fa90>
spectral density of modes¶
Now we calculate spectra of the maximum possible radiated energy of every multipole. This corresponds to integrating the euklidian norm of all generalized polarizability tenors for each multipole and taking it to the power 2.
[2]:
wl, d_mode_spec = tools.calculate_spectrum(
sim, 0, multipole.density_of_multipolar_modes, method=method,
which_moments=['p', 'm', 'qe', 'qm'])
K_E_spec = d_mode_spec.T[0]
K_M_spec = d_mode_spec.T[1]
K_QE_spec = d_mode_spec.T[2]
K_QM_spec = d_mode_spec.T[3]
plt.figure(figsize=(14,2.5))
plt.subplot(141)
plt.title('p', x=0.9, y=0.9, fontsize=16, color='k', ha='right', va='top')
plt.plot(wl, np.array(K_E_spec)/np.max(K_E_spec), color='C0', label='p')
plt.ylabel('sum of tensor norm (a.u.)', fontsize=14)
plt.ylim(-0.02, 1.03)
plt.subplot(142)
plt.title('m', x=0.9, y=0.9, fontsize=16, color='k', ha='right', va='top')
plt.plot(wl, np.array(K_M_spec)/np.max(K_M_spec), color='C2', label='m')
plt.xlabel('wavelength (nm)', x=1.1, fontsize=14)
plt.ylim(-0.02, 1.03)
plt.subplot(143)
plt.title('Qe', x=0.9, y=0.9, fontsize=16, color='k', ha='right', va='top')
plt.plot(wl, np.array(K_QE_spec)/np.max(K_QE_spec), color='C1', label='Qm')
plt.ylim(-0.02, 1.03)
plt.subplot(144)
plt.title('Qm', x=0.9, y=0.9, fontsize=16, color='k', ha='right', va='top')
plt.plot(wl, np.array(K_QM_spec)/np.max(K_QM_spec), color='C3', label='Qe')
plt.ylim(-0.02, 1.03)
plt.show()
wl=500.0nm. calc. K: 2285.7ms. electric... 11505.5ms. magnetic... 1583.4ms. Done.
wl=540.0nm. calc. K: 334.8ms. electric... 11359.3ms. magnetic... 1566.2ms. Done.
wl=580.0nm. calc. K: 334.5ms. electric... 11334.1ms. magnetic... 1594.9ms. Done.
wl=620.0nm. calc. K: 335.9ms. electric... 11187.7ms. magnetic... 1549.6ms. Done.
wl=660.0nm. calc. K: 334.5ms. electric... 11185.6ms. magnetic... 1551.1ms. Done.
wl=700.0nm. calc. K: 331.2ms. electric... 11280.3ms. magnetic... 1567.9ms. Done.
wl=740.0nm. calc. K: 340.2ms. electric... 11302.2ms. magnetic... 1563.4ms. Done.
wl=780.0nm. calc. K: 339.3ms. electric... 11294.4ms. magnetic... 1570.0ms. Done.
wl=820.0nm. calc. K: 324.5ms. electric... 11276.7ms. magnetic... 1565.6ms. Done.
wl=860.0nm. calc. K: 336.4ms. electric... 11375.3ms. magnetic... 1577.9ms. Done.
wl=900.0nm. calc. K: 327.6ms. electric... 11200.2ms. magnetic... 1553.6ms. Done.
wl=940.0nm. calc. K: 338.7ms. electric... 11295.6ms. magnetic... 1565.4ms. Done.
wl=980.0nm. calc. K: 314.8ms. electric... 11299.1ms. magnetic... 1579.6ms. Done.
wl=1020.0nm. calc. K: 337.5ms. electric... 11159.4ms. magnetic... 1547.1ms. Done.
wl=1060.0nm. calc. K: 331.9ms. electric... 11497.7ms. magnetic... 1587.5ms. Done.
wl=1100.0nm. calc. K: 341.9ms. electric... 11344.7ms. magnetic... 1568.3ms. Done.
wl=1140.0nm. calc. K: 334.0ms. electric... 11360.8ms. magnetic... 1577.8ms. Done.
wl=1180.0nm. calc. K: 323.5ms. electric... 11343.4ms. magnetic... 1573.1ms. Done.
wl=1220.0nm. calc. K: 322.5ms. electric... 11363.0ms. magnetic... 1566.5ms. Done.
wl=1260.0nm. calc. K: 323.0ms. electric... 11390.7ms. magnetic... 1593.4ms. Done.
wl=1300.0nm. calc. K: 335.8ms. electric... 11340.7ms. magnetic... 1571.2ms. Done.
wl=1340.0nm. calc. K: 339.4ms. electric... 11367.1ms. magnetic... 1586.2ms. Done.
wl=1380.0nm. calc. K: 342.5ms. electric... 11210.0ms. magnetic... 1551.0ms. Done.
wl=1420.0nm. calc. K: 330.0ms. electric... 11248.0ms. magnetic... 1553.0ms. Done.
wl=1460.0nm. calc. K: 343.4ms. electric... 11356.4ms. magnetic... 1590.7ms. Done.
wl=1500.0nm. calc. K: 337.9ms. electric... 11324.0ms. magnetic... 1566.5ms. Done.
![../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_3_1.png](../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_3_1.png)
configure various illumination fields¶
This is done using the normal pyGDM API and in particular its efield
class.
[3]:
wavelengths = sim.efield.wavelengths
## ------ plane wave - various incident angles
field_generator = fields.plane_wave
field_kwargs_S = [
dict(E_s=1, E_p=0, inc_angle=angle, inc_plane='xz')
for angle in np.linspace(0, 90, 10)
]
field_kwargs_P = [
dict(E_s=0, E_p=1, inc_angle=angle, inc_plane='xz')
for angle in np.linspace(0, 90, 10)
]
efield1 = fields.efield(field_generator, wavelengths=wavelengths, kwargs=field_kwargs_S)
efield2 = fields.efield(field_generator, wavelengths=wavelengths, kwargs=field_kwargs_P)
## ------ dipole illumination, e/m dipole of various orientations
field_generator_p = fields.dipole_electric
field_generator_m = fields.dipole_magnetic
field_kwargs_dp = [
dict(x0=300, y0=0, z0=0,
mx=np.sin(angle), my=0, mz=np.cos(angle))
for angle in np.linspace(-np.pi/2,0, 9)]
efield3 = fields.efield(field_generator_p, wavelengths=wavelengths, kwargs=field_kwargs_dp)
efield4 = fields.efield(field_generator_m, wavelengths=wavelengths, kwargs=field_kwargs_dp)
evalute all illumination fields¶
Now we use the generalized polarizabities to evaluate the multipole expansion of each illumination.
[5]:
for _ef in [efield1, efield2, efield3, efield4]:
sim.efield = _ef
all_spec = []
for i in range(len(tools.get_possible_field_params_spectra(sim))):
kw = tools.get_possible_field_params_spectra(sim)[i]
## calculate spectra using multiprocessing
wl, mpsc_Kp_spec = tools.calculate_spectrum(sim, i, multipole.scs,
use_generalized_polarizabilities=True,
normalization_E0=False, N_cpu=16)
sc_p_Kp, sc_m_Kp, sc_Qe_Kp, sc_Qm_Kp = mpsc_Kp_spec.T
all_spec.append(mpsc_Kp_spec)
all_spec = np.array(all_spec)
print(_ef)
colors0 = plt.cm.Greys(np.linspace(0.3, 1, len(all_spec)))
colors1 = plt.cm.Blues(np.linspace(0.3, 1, len(all_spec)))
colors2 = plt.cm.Greens(np.linspace(0.3, 1, len(all_spec)))
colors3 = plt.cm.Oranges(np.linspace(0.3, 1, len(all_spec)))
colors4 = plt.cm.Reds(np.linspace(0.3, 1, len(all_spec)))
plt.figure(figsize=(15,2.5))
# ax0 = plt.subplot(161); plt.title('mode density', x=0.5, y=1.05, fontsize=14, color='k', ha='left', va='top')
ax1 = plt.subplot(151); plt.title('tot.', x=0.5, y=1.05, fontsize=14, color='k', ha='left', va='top')
ax2 = plt.subplot(152); plt.title('p', x=0.5, y=1.05, fontsize=14, color='C0', ha='left', va='top')
ax3 = plt.subplot(153); plt.title('m', x=0.5, y=1.05, fontsize=14, color='C2', ha='left', va='top')
ax4 = plt.subplot(154); plt.title('Qe', x=0.5, y=1.05, fontsize=14, color='C1', ha='left', va='top')
ax5 = plt.subplot(155); plt.title('Qm', x=0.5, y=1.05, fontsize=14, color='C3', ha='left', va='top')
for i in range(len(tools.get_possible_field_params_spectra(sim))):
kw = tools.get_possible_field_params_spectra(sim)[i]
ax1.plot(wl, np.sum(all_spec[i], axis=-1), color=colors0[i])
ax2.plot(wl, all_spec[i,:,0], color=colors1[i])
ax3.plot(wl, all_spec[i,:,1], color=colors2[i])
ax4.plot(wl, all_spec[i,:,2], color=colors3[i])
ax5.plot(wl, all_spec[i,:,3], color=colors4[i])
ax3.set_xlabel('wavelength (nm)', fontsize=12)
ax1.set_ylabel(r'scattered intensity (a.u.)', fontsize=12)
plt.show()
----- incident field -----
field generator: "plane_wave"
26 wavelengths between 500.0 and 1500.0nm
10 incident field configurations per wavelength
![../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_7_1.png](../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_7_1.png)
----- incident field -----
field generator: "plane_wave"
26 wavelengths between 500.0 and 1500.0nm
10 incident field configurations per wavelength
![../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_7_3.png](../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_7_3.png)
----- incident field -----
field generator: "dipole_electric"
26 wavelengths between 500.0 and 1500.0nm
9 incident field configurations per wavelength
![../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_7_5.png](../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_7_5.png)
----- incident field -----
field generator: "dipole_magnetic"
26 wavelengths between 500.0 and 1500.0nm
9 incident field configurations per wavelength
![../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_7_7.png](../../_images/examples_multipole_exampleMultipole_GPex4_evaluate_several_illuminations_7_7.png)