# Tutorial: Combine simulations - Born approximation¶

This tutorial demonstrates how to use the tool combine_simulations to study near-field coupling effects.

## setup single silicon cube simulation¶

[1]:

import numpy as np
import matplotlib.pyplot as plt

from pyGDM2 import core
from pyGDM2 import propagators
from pyGDM2 import fields
from pyGDM2 import materials
from pyGDM2 import linear

from pyGDM2 import structures
from pyGDM2 import tools
from pyGDM2 import visu

# =============================================================================
# some global parameters
# =============================================================================
solver_method = 'cupy'      # on CUDA-GPU
#solver_method = 'scipyinv'

## simulation environment
n3 = 1.0   # cladding layer
n2 = 1.0   # environment
n1 = 1.45  # substrate

# =============================================================================
# set up dielectric cube structure
# =============================================================================
## size of blocks
mesh = 'cube'
step = 20     # in nm

## generate two different size cuboids
geo = structures.rect_wire(step, L=5, H=5, W=5, mesh=mesh)
material = materials.silicon()
struct_single = structures.struct(step, geo, material)

print('N dipoles = {}'.format(len(geo)))

# =============================================================================
# illumination: y-polarized, normal incidence plane wave, single wavelength
# =============================================================================
field_generator = fields.plane_wave
wavelengths = [600]  # nm
field_kwargs = dict(inc_angle=0, E_s=1, E_p=0)  # 0 deg: incidence from below, s-polar.: Y

efield = fields.efield(field_generator, wavelengths=wavelengths, kwargs=field_kwargs)

# =============================================================================
# single cube simulation object
# =============================================================================

structure initialization - automatic mesh detection: cube
structure initialization - consistency check: 125/125 dipoles valid
N dipoles = 125


## setup array of simulations¶

Now we create a planar array of 5x5 silicon nano-cubes, the center-to-center distance is 150nm (gaps of 50nm). This should be sufficiently close to induce significant near-field interaction.

[2]:

## create copies of simulation with shifted structure
print("Run isolated simulations...")
sim_list = []
for ix in np.arange(-2,3):
for iy in np.arange(-2,3):
## copy and shift simulation
_sim = sim_single.copy()
_sim = structures.shift(_sim, [ix*150, iy*150, 0])

## run sim
_sim.scatter(method=solver_method, calc_H=1)

sim_list.append(_sim)

## combine simulations. This also combines the individually simulated fields
## --> the combined simulation corresponds to the Born approximation
## (= no optical interactions between scatterers)
sim_array_born = tools.combine_simulations(sim_list)
visu.structure(sim_array_born, scale=0.45)

## we copy the combined sim again and run scatter to get the full optical response
print("Run combined simulation...")
sim_array = sim_array_born.copy()
sim_array.scatter(method=solver_method, calc_H=1)

Run isolated simulations...

/home/hans/.local/lib/python3.8/site-packages/numba/core/dispatcher.py:237: UserWarning: Numba extension module 'numba_scipy' failed to load due to 'ValueError(No function '__pyx_fuse_0pdtr' found in __pyx_capi__ of 'scipy.special.cython_special')'.
entrypoints.init_all()

timing for wl=600.00nm - setup: EE 2777.3ms, HE 227.5ms, inv.: 563.1ms, repropa.: 831.7ms (1 field configs), tot: 4399.9ms
timing for wl=600.00nm - setup: EE 38.5ms, HE 13.5ms, inv.: 1.0ms, repropa.: 13.7ms (1 field configs), tot: 67.4ms
timing for wl=600.00nm - setup: EE 38.2ms, HE 13.3ms, inv.: 1.1ms, repropa.: 13.8ms (1 field configs), tot: 66.6ms
timing for wl=600.00nm - setup: EE 37.8ms, HE 12.0ms, inv.: 1.0ms, repropa.: 13.5ms (1 field configs), tot: 64.5ms
timing for wl=600.00nm - setup: EE 39.7ms, HE 13.3ms, inv.: 1.4ms, repropa.: 14.2ms (1 field configs), tot: 68.8ms
timing for wl=600.00nm - setup: EE 39.2ms, HE 13.5ms, inv.: 1.0ms, repropa.: 13.7ms (1 field configs), tot: 67.5ms
timing for wl=600.00nm - setup: EE 37.7ms, HE 13.9ms, inv.: 1.1ms, repropa.: 17.6ms (1 field configs), tot: 70.5ms
timing for wl=600.00nm - setup: EE 38.6ms, HE 13.8ms, inv.: 1.0ms, repropa.: 13.8ms (1 field configs), tot: 67.5ms
timing for wl=600.00nm - setup: EE 37.9ms, HE 21.1ms, inv.: 2.1ms, repropa.: 18.7ms (1 field configs), tot: 80.3ms
timing for wl=600.00nm - setup: EE 36.4ms, HE 14.4ms, inv.: 1.2ms, repropa.: 17.8ms (1 field configs), tot: 70.0ms
timing for wl=600.00nm - setup: EE 38.7ms, HE 12.0ms, inv.: 1.0ms, repropa.: 13.3ms (1 field configs), tot: 65.6ms
timing for wl=600.00nm - setup: EE 41.1ms, HE 13.7ms, inv.: 1.3ms, repropa.: 13.9ms (1 field configs), tot: 70.6ms
timing for wl=600.00nm - setup: EE 39.0ms, HE 12.2ms, inv.: 1.0ms, repropa.: 13.9ms (1 field configs), tot: 66.3ms
timing for wl=600.00nm - setup: EE 38.0ms, HE 13.7ms, inv.: 1.1ms, repropa.: 14.2ms (1 field configs), tot: 67.3ms
timing for wl=600.00nm - setup: EE 38.0ms, HE 13.3ms, inv.: 1.0ms, repropa.: 20.3ms (1 field configs), tot: 72.9ms
timing for wl=600.00nm - setup: EE 37.4ms, HE 24.3ms, inv.: 1.9ms, repropa.: 22.4ms (1 field configs), tot: 86.5ms
timing for wl=600.00nm - setup: EE 37.9ms, HE 12.7ms, inv.: 1.1ms, repropa.: 13.9ms (1 field configs), tot: 65.9ms
timing for wl=600.00nm - setup: EE 39.8ms, HE 20.2ms, inv.: 1.5ms, repropa.: 14.5ms (1 field configs), tot: 76.3ms
timing for wl=600.00nm - setup: EE 37.1ms, HE 12.6ms, inv.: 1.0ms, repropa.: 13.7ms (1 field configs), tot: 64.7ms
timing for wl=600.00nm - setup: EE 38.0ms, HE 13.3ms, inv.: 1.3ms, repropa.: 14.0ms (1 field configs), tot: 67.3ms
timing for wl=600.00nm - setup: EE 38.7ms, HE 12.2ms, inv.: 1.0ms, repropa.: 14.0ms (1 field configs), tot: 66.0ms
timing for wl=600.00nm - setup: EE 43.8ms, HE 13.4ms, inv.: 1.6ms, repropa.: 14.4ms (1 field configs), tot: 73.6ms
timing for wl=600.00nm - setup: EE 40.9ms, HE 12.5ms, inv.: 1.0ms, repropa.: 14.0ms (1 field configs), tot: 68.7ms
timing for wl=600.00nm - setup: EE 37.6ms, HE 13.7ms, inv.: 1.3ms, repropa.: 14.4ms (1 field configs), tot: 67.5ms
timing for wl=600.00nm - setup: EE 38.5ms, HE 12.4ms, inv.: 1.0ms, repropa.: 14.0ms (1 field configs), tot: 66.1ms

/home/hans/.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...")

Run combined simulation...
timing for wl=600.00nm - setup: EE 16310.4ms, HE 3740.0ms, inv.: 1191.4ms, repropa.: 755.8ms (1 field configs), tot: 22104.7ms

[2]:

1


## Plot the real part of the E-field vectors¶

Near-field plots reveal a significant impact of the optical interactions between the nano-cubes

[3]:

#%% plot field vectors (real part)
plt.subplot(121)
plt.title("no interactions")
visu.vectorfield_by_fieldindex(sim_array_born, field_index=0, show=0)

plt.subplot(122)
plt.title("full sim")
visu.vectorfield_by_fieldindex(sim_array, field_index=0, show=0)

plt.show()


## Plot near-field intensity maps 50nm above¶

Near-field plots reveal a significant impact of the optical interactions between the nano-cubes

[4]:

## nearfield map
r_probe = tools.generate_NF_map(-600, 600, 51, -600, 600, 51, Z0=150)

## total and scattered fields
Et_b, Es_b, Bt_b, Bs_b = linear.nearfield(sim_array_born, field_index=0, r_probe=r_probe)
Et, Es, Bt, Bs = linear.nearfield(sim_array, field_index=0, r_probe=r_probe)

## plot
plt.figure(figsize=(10,8))

plt.subplot(221)
visu.structure_contour(sim_array_born, color='w', dashes=[2,2], show=0)
im = visu.vectorfield_color(Et_b, tit='E-field I - Born approx.', cmap='jet', show=0)
plt.colorbar(im, label='|E|^2 / |E0|^2')

plt.subplot(222)
visu.structure_contour(sim_array_born, color='w', dashes=[2,2], show=0)
im = visu.vectorfield_color(Bt_b, tit='H-field I - Born approx.', cmap='jet', show=0)
plt.colorbar(im, label='|H|^2 / |H0|^2')

plt.subplot(223)
visu.structure_contour(sim_array, color='w', dashes=[2,2], show=0)
im = visu.vectorfield_color(Et, tit='E-field I - full sim', cmap='jet', show=0)
plt.colorbar(im, label='|E|^2 / |E0|^2')

plt.subplot(224)
visu.structure_contour(sim_array, color='w', dashes=[2,2], show=0)
im = visu.vectorfield_color(Bt, tit='H-field I - full sim', cmap='jet', show=0)
plt.colorbar(im, label='|H|^2 / |H0|^2')

plt.tight_layout()
plt.show()