Skip to content

Commit bd171ad

Browse files
authored
fix bug in cavity length in LDOS tutorial and add note regarding impact of grid resolution on cell size (#3076)
1 parent c0c2b8a commit bd171ad

File tree

2 files changed

+29
-27
lines changed

2 files changed

+29
-27
lines changed

doc/docs/Python_Tutorials/Local_Density_of_States.md

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ In 3D, each simulation uses three [mirror symmetries](../Exploiting_Symmetry.md#
2727

2828
In cylindrical coordinates, the dipole is polarized in the $r$ direction. Setting up a linearly polarized source in cylindrical coordinates is demonstrated in [Tutorial/Cylindrical Coordinates/Scattering Cross Section of a Finite Dielectric Cylinder](Cylindrical_Coordinates.md#scattering-cross-section-of-a-finite-dielectric-cylinder). However, all that is necessary in this example which involves a single point dipole rather than a planewave is one simulation involving an $E_r$ source at $r=0$ with $m=-1$. This is actually a circularly polarized source but this is sufficient because the $m=+1$ simulation produces an identical result to the $m=-1$ simulation. It is therefore not necessary to perform two separate simulations for $m=\pm 1$ in order to average the results from the left- and right-circularly polarized sources.
2929

30-
One important parameter when setting up this calculation is the grid resolution.
30+
One important parameter when setting up this calculation is the grid resolution. In this example, the length of the cavity is used to specify the length of the computational cell in $z$. However, it is important to note that Meep will *round the cell size to the nearest pixel*. This means there will likely be a small discrepancy between the intended cavity length and the value used by Meep. Demonstrating consistent agreement between the simulated and analytic Purcell enhancement for a range of cavity lengths may therefore require using a fine grid resolution.
3131

32-
A key feature of the LDOS in this geometry is that it experiences discontinuities, called [Van Hove singularities](https://en.wikipedia.org/wiki/Van_Hove_singularity), any time the cavity thickness/λ passes through the cutoff for a waveguide mode, which occurs for cavity-thickness/λ values of 0.5, 1.5, 2.5, etc. (Mathematically, Van Hove singularities depend strongly on the dimensionality — it is a discontinuity in this case because the waves are propagating along two dimensions, i.e. each cutoff is a minimum in the 2d dispersion relation $\omega(k_x,k_y)$.) This discontinuity also means that the LDOS *exactly at* the cutoff thickness/λ is ill-defined and convergence with discretization can be problematic at this point. (In consequence, the LDOS *exactly* at the Van Hove discontinuity can behave erratically with resolution, and should be viewed with caution.)
32+
A key feature of the LDOS in this geometry is that it experiences discontinuities, called [Van Hove singularities](https://en.wikipedia.org/wiki/Van_Hove_singularity), any time the cavity thickness/λ passes through the cutoff for a waveguide mode, which occurs for cavity-thickness/λ values of 0.5, 1.5, 2.5, etc. (Mathematically, Van Hove singularities depend strongly on the dimensionality — it is a discontinuity in this case because the waves are propagating along two dimensions, i.e. each cutoff is a minimum in the 2d dispersion relation $\omega(k_x,k_y)$.) This discontinuity also means that the LDOS *exactly at* the cutoff thickness/λ is ill-defined and convergence with discretization can be problematic at this point. (In consequence, the LDOS *exactly* at the Van Hove discontinuity can behave erratically with resolution, and should be viewed with caution.)
3333

3434
As shown in the plot below, the results from Meep for both coordinate systems agree well with the analytic theory over the entire range of values of the cavity thickness.
3535

@@ -49,7 +49,7 @@ import numpy as np
4949

5050
# Note: Meep may round the cell dimensions to an integer number of pixels which
5151
# could modify the cavity structure.
52-
RESOLUTION_UM = 70
52+
RESOLUTION_UM = 71
5353

5454
PML_UM = 0.5
5555
BULK_UM = 6.0
@@ -80,11 +80,16 @@ def ldos_cyl(cavity_um: Optional[float] = None) -> float:
8080
cell_r_um = BULK_UM + PML_UM
8181
cell_size = mp.Vector3(cell_r_um, 0, cell_z_um)
8282

83+
# An Er source at r = 0 and m=±1 needs to be slightly offset.
84+
# https://github.com/NanoComp/meep/issues/2704
85+
dipole_rpos_um = 1.5 / RESOLUTION_UM
86+
87+
src_pt = mp.Vector3(dipole_rpos_um, 0, 0)
8388
sources = [
8489
mp.Source(
8590
src=mp.GaussianSource(frequency, fwidth=0.2 * frequency),
8691
component=mp.Er,
87-
center=mp.Vector3(),
92+
center=src_pt,
8893
)
8994
]
9095

@@ -101,7 +106,7 @@ def ldos_cyl(cavity_um: Optional[float] = None) -> float:
101106
sim.run(
102107
mp.dft_ldos(frequency, 0, 1),
103108
until_after_sources=mp.stop_when_fields_decayed(
104-
FIELD_DECAY_PERIOD, mp.Er, mp.Vector3(), FIELD_DECAY_TOL
109+
FIELD_DECAY_PERIOD, mp.Er, src_pt, FIELD_DECAY_TOL
105110
),
106111
)
107112

@@ -124,7 +129,7 @@ def ldos_3d(cavity_um: Optional[float] = None) -> float:
124129
size_z_um = cavity_um
125130
pml_layers = [
126131
mp.PML(thickness=PML_UM, direction=mp.X),
127-
mp.PML(thickness=PML_UM, direction=mp.Y)
132+
mp.PML(thickness=PML_UM, direction=mp.Y),
128133
]
129134

130135
size_xy_um = BULK_UM + 2 * PML_UM
@@ -168,33 +173,27 @@ if __name__ == "__main__":
168173
ldos_bulk_3d = ldos_3d()
169174

170175
cavity_um = np.arange(0.50, 2.55, 0.05)
171-
172-
num_cavity_um = cavity_um.shape[0]
173-
174176
vacuum_cavity_um = cavity_um * WAVELENGTH_UM / N_CAVITY
175177

178+
num_cavity_um = cavity_um.shape[0]
176179
ldos_cavity_cyl = np.zeros(num_cavity_um)
177180
ldos_cavity_3d = np.zeros(num_cavity_um)
178181

179182
for j in range(num_cavity_um):
180-
ldos_cavity_cyl[j] = ldos_cyl(cavity_um[j])
181-
ldos_cavity_3d[j] = ldos_3d(cavity_um[j])
183+
ldos_cavity_cyl[j] = ldos_cyl(vacuum_cavity_um[j])
184+
ldos_cavity_3d[j] = ldos_3d(vacuum_cavity_um[j])
182185
purcell_cyl = ldos_cavity_cyl[j] / ldos_bulk_cyl
183186
purcell_3d = ldos_cavity_3d[j] / ldos_bulk_3d
184-
print(
185-
f"purcell:, {cavity_um[j]:.3f}, {purcell_cyl:.6f}, {purcell_3d:.6f}"
186-
)
187+
print(f"purcell:, {cavity_um[j]:.3f}, {purcell_cyl:.6f}, {purcell_3d:.6f}")
187188

188189
# Purcell enhancement factor (relative to bulk medium)
189190
purcell_meep_cyl = ldos_cavity_cyl / ldos_bulk_cyl
190191
purcell_meep_3d = ldos_cavity_3d / ldos_bulk_3d
191192

192193
# Equation 7 of 1998 reference.
193-
purcell_theory = (
194-
3 * np.fix(cavity_um + 0.5) / (4 * cavity_um) +
195-
(4 * np.power(np.fix(cavity_um + 0.5), 3) - np.fix(cavity_um + 0.5) ) /
196-
(16 * np.power(cavity_um, 3))
197-
)
194+
purcell_theory = 3 * np.fix(cavity_um + 0.5) / (4 * cavity_um) + (
195+
4 * np.power(np.fix(cavity_um + 0.5), 3) - np.fix(cavity_um + 0.5)
196+
) / (16 * np.power(cavity_um, 3))
198197

199198
if mp.am_master():
200199
fig, ax = plt.subplots()

python/examples/planar_cavity_ldos.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
# Note: Meep may round the cell dimensions to an integer number of pixels which
1717
# could modify the cavity structure.
18-
RESOLUTION_UM = 70
18+
RESOLUTION_UM = 71
1919

2020
PML_UM = 0.5
2121
BULK_UM = 6.0
@@ -46,11 +46,16 @@ def ldos_cyl(cavity_um: Optional[float] = None) -> float:
4646
cell_r_um = BULK_UM + PML_UM
4747
cell_size = mp.Vector3(cell_r_um, 0, cell_z_um)
4848

49+
# An Er source at r = 0 and m=±1 needs to be slightly offset.
50+
# https://github.com/NanoComp/meep/issues/2704
51+
dipole_rpos_um = 1.5 / RESOLUTION_UM
52+
53+
src_pt = mp.Vector3(dipole_rpos_um, 0, 0)
4954
sources = [
5055
mp.Source(
5156
src=mp.GaussianSource(frequency, fwidth=0.2 * frequency),
5257
component=mp.Er,
53-
center=mp.Vector3(),
58+
center=src_pt,
5459
)
5560
]
5661

@@ -67,7 +72,7 @@ def ldos_cyl(cavity_um: Optional[float] = None) -> float:
6772
sim.run(
6873
mp.dft_ldos(frequency, 0, 1),
6974
until_after_sources=mp.stop_when_fields_decayed(
70-
FIELD_DECAY_PERIOD, mp.Er, mp.Vector3(), FIELD_DECAY_TOL
75+
FIELD_DECAY_PERIOD, mp.Er, src_pt, FIELD_DECAY_TOL
7176
),
7277
)
7378

@@ -134,17 +139,15 @@ def ldos_3d(cavity_um: Optional[float] = None) -> float:
134139
ldos_bulk_3d = ldos_3d()
135140

136141
cavity_um = np.arange(0.50, 2.55, 0.05)
137-
138-
num_cavity_um = cavity_um.shape[0]
139-
140142
vacuum_cavity_um = cavity_um * WAVELENGTH_UM / N_CAVITY
141143

144+
num_cavity_um = cavity_um.shape[0]
142145
ldos_cavity_cyl = np.zeros(num_cavity_um)
143146
ldos_cavity_3d = np.zeros(num_cavity_um)
144147

145148
for j in range(num_cavity_um):
146-
ldos_cavity_cyl[j] = ldos_cyl(cavity_um[j])
147-
ldos_cavity_3d[j] = ldos_3d(cavity_um[j])
149+
ldos_cavity_cyl[j] = ldos_cyl(vacuum_cavity_um[j])
150+
ldos_cavity_3d[j] = ldos_3d(vacuum_cavity_um[j])
148151
purcell_cyl = ldos_cavity_cyl[j] / ldos_bulk_cyl
149152
purcell_3d = ldos_cavity_3d[j] / ldos_bulk_3d
150153
print(f"purcell:, {cavity_um[j]:.3f}, {purcell_cyl:.6f}, {purcell_3d:.6f}")

0 commit comments

Comments
 (0)