-
Notifications
You must be signed in to change notification settings - Fork 640
/
Copy pathpoint_dipole_cyl.py
156 lines (130 loc) · 4.5 KB
/
point_dipole_cyl.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"""Tutorial example for point-dipole sources in cylindrical coordinates.
This example demonstrates that the total and radiated flux from a point dipole
in a dielectric layer (a quantum well) above a lossless ground plane (an LED)
computed in cylindrical coordinates as part of the calculation of the extraction
efficiency is independent of the dipole's position in the radial direction.
reference: https://meep.readthedocs.io/en/latest/Python_Tutorials/Cylindrical_Coordinates/#nonaxisymmetric-dipole-sources
"""
from typing import Tuple
import meep as mp
import numpy as np
resolution = 80 # pixels/μm
n = 2.4 # refractive index of dielectric layer
wvl = 1.0 # wavelength (in vacuum)
fcen = 1 / wvl # center frequency of source/monitor
def led_flux(dmat: float, h: float, rpos: float, m: int) -> Tuple[float, float]:
"""Computes the radiated and total flux of a point source embedded
within a dielectric layer above a lossless ground plane.
Args:
dmat: thickness of dielectric layer.
h: height of dipole above ground plane as a fraction of dmat.
rpos: position of source in radial direction.
m: angular φ dependence of the fields exp(imφ).
Returns:
The radiated and total flux as a 2-Tuple.
"""
L = 20 # length of non-PML region in radial direction
dair = 1.0 # thickness of air padding
dpml = 1.0 # PML thickness
sr = L + dpml
sz = dmat + dair + dpml
cell_size = mp.Vector3(sr, 0, sz)
boundary_layers = [
mp.PML(dpml, direction=mp.R),
mp.PML(dpml, direction=mp.Z, side=mp.High),
]
src_pt = mp.Vector3(rpos, 0, -0.5 * sz + h * dmat)
sources = [
mp.Source(
src=mp.GaussianSource(fcen, fwidth=0.1 * fcen),
component=mp.Er,
center=src_pt,
),
]
geometry = [
mp.Block(
material=mp.Medium(index=n),
center=mp.Vector3(0, 0, -0.5 * sz + 0.5 * dmat),
size=mp.Vector3(mp.inf, mp.inf, dmat),
)
]
sim = mp.Simulation(
resolution=resolution,
cell_size=cell_size,
dimensions=mp.CYLINDRICAL,
m=m,
boundary_layers=boundary_layers,
sources=sources,
geometry=geometry,
)
flux_air_mon = sim.add_flux(
fcen,
0,
1,
mp.FluxRegion(
center=mp.Vector3(0.5 * L, 0, 0.5 * sz - dpml),
size=mp.Vector3(L, 0, 0),
),
mp.FluxRegion(
center=mp.Vector3(L, 0, 0.5 * sz - dpml - 0.5 * dair),
size=mp.Vector3(0, 0, dair),
),
)
sim.run(
mp.dft_ldos(fcen, 0, 1),
until_after_sources=mp.stop_when_fields_decayed(
50.0,
mp.Er,
src_pt,
1e-8,
),
)
flux_air = mp.get_fluxes(flux_air_mon)[0]
if rpos == 0:
dV = np.pi / (resolution**3)
else:
dV = 2 * np.pi * rpos / (resolution**2)
# total flux from point source via LDOS
flux_src = -np.real(sim.ldos_Fdata[0] * np.conj(sim.ldos_Jdata[0])) * dV
print(f"flux-cyl:, {rpos:.2f}, {m:3d}, {flux_src:.6f}, {flux_air:.6f}")
return flux_air, flux_src
if __name__ == "__main__":
layer_thickness = 0.7 * wvl / n
dipole_height = 0.5
# r = 0 source requires a single simulation with m = ±1
rpos = 0
m = 1
flux_air, flux_src = led_flux(
layer_thickness,
dipole_height,
rpos,
m,
)
ext_eff = flux_air / flux_src
print(f"exteff:, {rpos}, {ext_eff:.6f}")
# r > 0 source requires Fourier-series expansion of φ
flux_tol = 1e-5 # threshold flux to determine when to truncate expansion
rpos = [3.5, 6.7, 9.5]
for rp in rpos:
# analytic upper bound on m based on coupling to free-space modes
# in light cone of source medium
cutoff_M = int(rp * 2 * np.pi * fcen * n)
ms = range(cutoff_M + 1)
flux_src_tot = 0
flux_air_tot = 0
flux_air_max = 0
for m in ms:
flux_air, flux_src = led_flux(
layer_thickness,
dipole_height,
rp,
m,
)
flux_air_tot += flux_air if m == 0 else 2 * flux_air
flux_src_tot += flux_src if m == 0 else 2 * flux_src
if flux_air > flux_air_max:
flux_air_max = flux_air
if m > 0 and (flux_air / flux_air_max) < flux_tol:
break
ext_eff = flux_air_tot / flux_src_tot
print(f"exteff:, {rp}, {ext_eff:.6f}")