Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

meep plugin and docs improvements #510

Merged
merged 3 commits into from Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 11 additions & 1 deletion CHANGELOG.md
@@ -1,5 +1,15 @@
# [CHANGELOG](https://keepachangelog.com/en/1.0.0/)

## [5.12.5](https://github.com/gdsfactory/gdsfactory/pull/502)

- better docstrings with autodoc_typehints = "description"
- improve meep plugin.
- remove port_field_monitor_name parameter (no longer needed) thanks to meep 1.23 introduced to use the energy in the whole simulation to determine when to terminate, which is a better termination condition than the energy at the ports. [PR](https://github.com/gdsfactory/gdsfactory/pull/495/files). Requires meep 1.23 or newer.
- update termination condition for grating_coupler simulations.
- rename effective permitivity to get_effective index. Change units from meters to um, and permitivities to refractive_index to be consistent with gdsfactory units in um.
- add `gf.generate_doe` [PR](https://github.com/gdsfactory/gdsfactory/pull/508/files)
- add add_center_section to CrossSection and cross_section for slot cross_section [PR](https://github.com/gdsfactory/gdsfactory/pull/509) [fixes](https://github.com/gdsfactory/gdsfactory/issues/506)

## [5.12.4](https://github.com/gdsfactory/gdsfactory/pull/502)

- function to calculate_effective_permittivity [PR](https://github.com/gdsfactory/gdsfactory/pull/501)
Expand All @@ -8,7 +18,7 @@
## [5.12.2](https://github.com/gdsfactory/gdsfactory/pull/498)

- extract generating component list for doe into a separate function for use in pack_doe and elsewhere [fixes issue](https://github.com/gdsfactory/gdsfactory/issues/496)
- meep 1.23 introduced to use the energy in the whole simulation to determine when to terminate, which is a better termination condition than the energy at the ports. [PR](https://github.com/gdsfactory/gdsfactory/issues/496). Requires meep 1.23 or newer.
- meep 1.23 introduced to use the energy in the whole simulation to determine when to terminate, which is a better termination condition than the energy at the ports. [PR](https://github.com/gdsfactory/gdsfactory/pull/495/files). Requires meep 1.23 or newer.

## [5.12.1](https://github.com/gdsfactory/gdsfactory/pull/494)

Expand Down
16 changes: 16 additions & 0 deletions docs/_static/css/custom.css
@@ -0,0 +1,16 @@
/* Newlines (\a) and spaces (\20) before each parameter */
.sig-param::before {
content: "\a\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20";
white-space: pre;
}

/* Newline after the last parameter (so the closing bracket is on a new line) */
dt em.sig-param:last-of-type::after {
content: "\a";
white-space: pre;
}

/* To have blue background of width of the block (instead of width of content) */
dl.class > dt:first-of-type {
display: block !important;
}
1 change: 1 addition & 0 deletions docs/conf.py
Expand Up @@ -80,6 +80,7 @@
autodoc_pydantic_model_show_config_summary = False
autodoc_pydantic_model_show_validator_summary = False
autodoc_pydantic_model_show_validator_members = False
autodoc_typehints = "description"


autodoc_default_options = {
Expand Down
Expand Up @@ -7,38 +7,43 @@
from typing_extensions import Literal


def calculate_effective_permittivity(
epsilon_film: float,
epsilon_substrate: float,
epsilon_cladding: float,
def get_effective_index(
ncore: float,
nsubstrate: float,
ncladding: float,
thickness: float,
wavelength: float,
polarization: Literal["te", "tm"],
) -> List[float]:
"""
Calculate the effective refractive index for a 1D mode.
"""Returns the effective refractive index for a 1D mode.

.. code::

----------------- |
epsilon_cladding inf
ncladding inf
----------------- |
epsilon_film thickness
ncore thickness
----------------- |
epsilon_substrate inf
nsubstrate inf
----------------- |

Args:
epsilon_film: Relative permittivity of the film.
epsilon_core: Relative permittivity of the film.
epsilon_substrate: Relative permittivity of the substrate.
epsilon_cladding: Relative permittivity of the cladding.
thickness: Thickness of the film.
wavelength: Wavelength.
thickness: Thickness of the film in um.
wavelength: Wavelength in um.
polarization: Either "te" or "tm".

Returns:
List of effective permittivity.
"""

epsilon_core = ncore**2
epsilon_cladding = ncladding**2
epsilon_substrate = nsubstrate**2

thickness = thickness * 1e-6
wavelength = wavelength * 1e-6

if polarization == "te":
tm = False
elif polarization == "tm":
Expand All @@ -49,7 +54,7 @@ def calculate_effective_permittivity(
k_0 = 2 * np.pi / wavelength

def k_f(e_eff):
return k_0 * np.sqrt(epsilon_film - e_eff) / (epsilon_film if tm else 1)
return k_0 * np.sqrt(epsilon_core - e_eff) / (epsilon_core if tm else 1)

def k_s(e_eff):
return (
Expand All @@ -67,7 +72,7 @@ def objective(e_eff):
# scan roughly for indices
# use a by 1e-10 smaller search area to avoid division by zero
x = np.linspace(
min(epsilon_substrate, epsilon_cladding) + 1e-10, epsilon_film - 1e-10, 1000
min(epsilon_substrate, epsilon_cladding) + 1e-10, epsilon_core - 1e-10, 1000
)
indices_temp = x[np.abs(objective(x)) < 0.1]
if not len(indices_temp):
Expand All @@ -76,18 +81,29 @@ def objective(e_eff):
# and then use fsolve to get exact indices
indices_temp = fsolve(objective, indices_temp)

# then make the indices unique
indices = []
for index in indices_temp:
if not any(np.isclose(index, i, atol=1e-7) for i in indices):
indices.append(index)
return np.sqrt(indices_temp[0])


return indices
def test_effective_index():
neff = get_effective_index(
ncore=3.4777,
ncladding=1.444,
nsubstrate=1.444,
thickness=0.22,
wavelength=1.55,
polarization="te",
)
assert np.isclose(neff, 2.8494636999424405)


if __name__ == "__main__":
print(
calculate_effective_permittivity(
3.4777**2, 1.444**2, 1.444**2, 0.22e-6, 1.55e-6, "te"
get_effective_index(
ncore=3.4777,
ncladding=1.444,
nsubstrate=1.444,
thickness=0.22,
wavelength=1.55,
polarization="te",
)
)
8 changes: 4 additions & 4 deletions gdsfactory/simulation/gmeep/get_material.py
Expand Up @@ -70,14 +70,14 @@ def get_index(
"""Returns refractive index from Meep's material database.

Args:
name: material name
wavelength: wavelength (um)
name: material name.
wavelength: wavelength (um).
dispersive: True for built-in Meep index model,
False for simple, non-dispersive model
False for simple, non-dispersive model.

Note:
Using the built-in models can be problematic at low resolution.
If fields are NaN or Inf, increase resolution or use a non-dispersive model
If fields are NaN or Inf, increase resolution or use a non-dispersive model.

"""
medium = get_material(name=name, wavelength=wavelength, dispersive=dispersive)
Expand Down
24 changes: 2 additions & 22 deletions gdsfactory/simulation/gmeep/get_simulation.py
Expand Up @@ -37,7 +37,6 @@ def get_simulation(
wavelength_points: int = 50,
dfcen: float = 0.2,
port_source_name: str = "o1",
port_field_monitor_name: str = "o2",
port_margin: float = 3,
distance_source_to_monitors: float = 0.2,
port_source_offset: float = 0,
Expand Down Expand Up @@ -104,14 +103,13 @@ def get_simulation(
wavelength_points: wavelength steps.
dfcen: delta frequency.
port_source_name: input port name.
port_field_monitor_name: for component port.
port_margin: margin on each side of the port.
distance_source_to_monitors: in (um) source goes before.
port_source_offset: offset between source GDS port and source MEEP port.
port_monitor_offset: offset between monitor GDS port and monitor MEEP port.
dispersive: use dispersive material models (requires higher resolution).
material_name_to_meep: dispersive materials have a wavelength
dependent index. Maps layer_stack names with meep material database names.
material_name_to_meep: map layer_stack names with meep material database name
or refractive index. dispersive materials have a wavelength dependent index.

Keyword Args:
settings: other parameters for sim object (resolution, symmetries, etc.)
Expand Down Expand Up @@ -154,20 +152,6 @@ def get_simulation(
port_source_name = port_source.name
warnings.warn(f"Selecting port_source_name={port_source_name!r} instead.")

if port_field_monitor_name not in component_ref.ports:
warnings.warn(
f"port_field_monitor_name={port_field_monitor_name!r} not in {port_names}"
)
port_field_monitor = (
component_ref.get_ports_list()[0]
if len(component.ports) < 2
else component.get_ports_list()[1]
)
port_field_monitor_name = port_field_monitor.name
warnings.warn(
f"Selecting port_field_monitor_name={port_field_monitor_name!r} instead."
)

assert isinstance(
component, Component
), f"component needs to be a gf.Component, got Type {type(component)}"
Expand Down Expand Up @@ -236,9 +220,6 @@ def get_simulation(
)
center = xy_shifted.tolist() + [0] # (x, y, z=0)

field_monitor_port = component_ref.ports[port_field_monitor_name]
field_monitor_point = field_monitor_port.center.tolist() + [0] # (x, y, z=0)

if np.isclose(port.orientation, 0):
direction = mp.X
elif np.isclose(port.orientation, 90):
Expand Down Expand Up @@ -312,7 +293,6 @@ def get_simulation(
freqs=freqs,
monitors=monitors,
sources=sources,
field_monitor_point=field_monitor_point,
port_source_name=port_source_name,
initialized=False,
)
Expand Down
40 changes: 20 additions & 20 deletions gdsfactory/simulation/gmeep/get_simulation_grating_fiber.py
Expand Up @@ -66,37 +66,37 @@ def get_simulation_grating_fiber(
ncore = sqrt(na**2 + ncore**2)

Args:
period: fiber grating period
period: fiber grating period.
fill_factor: fraction of the grating period filled with the grating material.
n_periods: number of periods
widths: Optional list of widths. Overrides period, fill_factor, n_periods
gaps: Optional list of gaps. Overrides period, fill_factor, n_periods
fiber_angle_deg: fiber angle in degrees
fiber_xposition: xposition
fiber_core_diameter: fiber diameter
fiber_numerical_aperture: NA
n_periods: number of periods.
widths: Optional list of widths. Overrides period, fill_factor, n_periods.
gaps: Optional list of gaps. Overrides period, fill_factor, n_periods.
fiber_angle_deg: fiber angle in degrees.
fiber_xposition: xposition.
fiber_core_diameter: fiber diameter.
fiber_numerical_aperture: NA.
fiber_nclad: fiber cladding index.
fiber_ncore: fiber core index
fiber_ncore: fiber core index.
nwg: waveguide index.
nclad: top cladding index.
nbox: box index bottom.
nsubstrate: index substrate.
pml_thickness: pml_thickness (um)
substrate_thickness: substrate_thickness (um)
box_thickness: thickness for bottom cladding (um)
wg_thickness: wg_thickness (um)
pml_thickness: pml_thickness (um).
substrate_thickness: substrate_thickness (um).
box_thickness: thickness for bottom cladding (um).
wg_thickness: wg_thickness (um).
top_clad_thickness: thickness of the top cladding.
air_gap_thickness: air gap thickness.
fiber_thickness: fiber_thickness
resolution: resolution pixels/um
wavelength_start: min wavelength (um)
wavelength_stop: max wavelength (um)
fiber_thickness: fiber_thickness.
resolution: resolution pixels/um.
wavelength_start: min wavelength (um).
wavelength_stop: max wavelength (um).
wavelength_points: wavelength points.
eps_averaging: epsilon averaging.
fiber_port_y_offset_from_air: y_offset from fiber to air (um).
waveguide_port_x_offset_from_grating_start:
fiber_port_x_size:
xmargin: margin from PML to grating end
waveguide_port_x_offset_from_grating_start: in um.
fiber_port_x_size: in um.
xmargin: margin from PML to grating end in um.


.. code::
Expand Down
16 changes: 8 additions & 8 deletions gdsfactory/simulation/gmeep/test_eigenmode.py
Expand Up @@ -16,17 +16,17 @@


def lumerical_parser(E_1D, H_1D, y_1D, z_1D, res=50, z_offset=0.11 * 1e-6):
"""
"""Converts 1D arrays of fields to 2D arrays according to positions.

Lumerical data is in 1D arrays, and over a nonregular mesh
Converts 1D arrays of fields to 2D arrays according to positions

Args
E_1D: E array from Lumerical
H_1D: H array from Lumerical
y_1D: y array from Lumerical
z_1D: z array from Lumerical
res: desired resolution
z_offset: z offset to move the fields
E_1D: E array from Lumerical.
H_1D: H array from Lumerical.
y_1D: y array from Lumerical.
z_1D: z array from Lumerical.
res: desired resolution.
z_offset: z offset to move the fields.
"""
# Make regular grid from resolution and range of domain
y_1D = y_1D[...].flatten()
Expand Down
4 changes: 2 additions & 2 deletions gdsfactory/simulation/gmeep/test_write_sparameters_meep.py
Expand Up @@ -132,8 +132,8 @@ def test_sparameters_straight_batch(dataframe_regression) -> None:


if __name__ == "__main__":
# test_sparameters_straight(None)
test_sparameters_straight(None)
# test_sparameters_straight_symmetric(False)
test_sparameters_straight_batch(None)
# test_sparameters_straight_batch(None)
# test_sparameters_straight_mpi(None)
# test_sparameters_crossing_symmetric(False)
10 changes: 1 addition & 9 deletions gdsfactory/simulation/gmeep/write_sparameters_grating.py
Expand Up @@ -122,15 +122,7 @@ def write_sparameters_grating(
plt.show()
return

termination = [
mp.stop_when_fields_decayed(
dt=50,
c=mp.Ez,
pt=monitor.regions[0].center,
decay_by=decay_by,
)
for monitor in [sim_dict["waveguide_monitor"], sim_dict["fiber_monitor"]]
]
termination = [mp.stop_when_energy_decayed(dt=50, decay_by=1e-3)]

if animate:
# Run while saving fields
Expand Down
11 changes: 5 additions & 6 deletions gdsfactory/simulation/gmeep/write_sparameters_meep.py
Expand Up @@ -254,17 +254,16 @@ def write_sparameters_meep(
wavelength_points: wavelength steps.
dfcen: delta frequency.
port_source_name: input port name.
port_field_monitor_name:
port_margin: margin on each side of the port (um).
distance_source_to_monitors: in (um).
port_source_offset: offset between source Component port and source MEEP port.
port_monitor_offset: offset between monitor Component port and monitor MEEP port.
material_name_to_meep: dispersive materials have a wavelength
dependent index. Maps layer_stack names with meep material database names.
port_monitor_offset: offset between Component and MEEP port monitor.
material_name_to_meep: map layer_stack names with meep material database name
or refractive index. dispersive materials have a wavelength dependent index.

Returns:
sparameters in a pandas Dataframe (wavelengths, s11a, s12m, ...)
where `a` is the angle in radians and `m` the module
where `a` is the angle in radians and `m` the module.

"""
component = gf.get_component(component)
Expand All @@ -273,7 +272,7 @@ def write_sparameters_meep(

for setting in settings.keys():
if setting not in settings_get_simulation:
raise ValueError(f"{setting} not in {settings_get_simulation}")
raise ValueError(f"{setting!r} not in {settings_get_simulation}")

port_symmetries = port_symmetries or {}

Expand Down
Expand Up @@ -91,7 +91,6 @@ def write_sparameters_meep_batch(
wavelength_points: wavelength steps.
dfcen: delta frequency.
port_source_name: input port name.
port_field_monitor_name: from component port.
port_margin: margin on each side of the port.
distance_source_to_monitors: in (um) source goes before.
port_source_offset: offset between source GDS port and source MEEP port.
Expand Down