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

add stop_when_energy_decayed termination condition #2021

Merged
merged 2 commits into from
Apr 7, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 54 additions & 33 deletions doc/docs/Python_User_Interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,40 +87,40 @@ control various parameters of the Meep computation.

```python
def __init__(self,
cell_size:Union[meep.geom.Vector3, Tuple[float, ...], NoneType]=None,
resolution:float=None,
geometry:Union[List[meep.geom.GeometricObject], NoneType]=None,
sources:Union[List[meep.source.Source], NoneType]=None,
eps_averaging:bool=True,
dimensions:int=3,
boundary_layers:Union[List[meep.simulation.PML], NoneType]=None,
symmetries:Union[List[meep.simulation.Symmetry], NoneType]=None,
force_complex_fields:bool=False,
default_material:meep.geom.Medium=Medium(),
m:float=0,
k_point:Union[meep.geom.Vector3, Tuple[float, ...], bool]=False,
kz_2d:str='complex',
extra_materials:Union[List[meep.geom.Medium], NoneType]=None,
material_function:Union[Callable[[Union[meep.geom.Vector3, Tuple[float, ...]]], meep.geom.Medium], NoneType]=None,
epsilon_func:Union[Callable[[Union[meep.geom.Vector3, Tuple[float, ...]]], float], NoneType]=None,
epsilon_input_file:str='',
progress_interval:float=4,
subpixel_tol:float=0.0001,
subpixel_maxeval:int=100000,
loop_tile_base_db:int=0,
loop_tile_base_eh:int=0,
ensure_periodicity:bool=True,
num_chunks:int=0,
Courant:float=0.5,
accurate_fields_near_cylorigin:bool=False,
filename_prefix:Union[str, NoneType]=None,
output_volume:Union[meep.simulation.Volume, NoneType]=None,
output_single_precision:bool=False,
geometry_center:Union[meep.geom.Vector3, Tuple[float, ...]]=Vector3<0.0, 0.0, 0.0>,
force_all_components:bool=False,
split_chunks_evenly:bool=True,
cell_size: Union[meep.geom.Vector3, Tuple[float, ...], NoneType] = None,
resolution: float = None,
geometry: Optional[List[meep.geom.GeometricObject]] = None,
sources: Optional[List[meep.source.Source]] = None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's going on with all of these Union -> Optional changes? Seems like they belong in a separate PR.

Copy link
Collaborator Author

@oskooi oskooi Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1919 added the Optional type hint to various parameters of the Simulation constructor such as geometry, sources, etc. The type hint Optional[Type] is equivalent to Union[Type, None] according to PEP 484. The default values of each parameter are parsed by the ast.parse() function in doc/generate_py_api.py. Because I have been using different versions of Python (3.5, 3.8) to call generate_py_api.py in various PRs which involve updating the docs (i.e., #1958, #1926, etc.), the different Python grammars seem to have been interchanging Optional and Union. The same thing seems to be happening again in this PR. ast.parse() is also inserting an extra space before and after the = sign. We therefore probably need to edit generate_py_api.py in a separate PR to ensure consistent parsing of the type hints and thus avoid these unnecessary changes.

eps_averaging: bool = True,
dimensions: int = 3,
boundary_layers: Optional[List[meep.simulation.PML]] = None,
symmetries: Optional[List[meep.simulation.Symmetry]] = None,
force_complex_fields: bool = False,
default_material: meep.geom.Medium = Medium(),
m: float = 0,
k_point: Union[meep.geom.Vector3, Tuple[float, ...], bool] = False,
kz_2d: str = 'complex',
extra_materials: Optional[List[meep.geom.Medium]] = None,
material_function: Optional[Callable[[Union[meep.geom.Vector3, Tuple[float, ...]]], meep.geom.Medium]] = None,
epsilon_func: Optional[Callable[[Union[meep.geom.Vector3, Tuple[float, ...]]], float]] = None,
epsilon_input_file: str = '',
progress_interval: float = 4,
subpixel_tol: float = 0.0001,
subpixel_maxeval: int = 100000,
loop_tile_base_db: int = 0,
loop_tile_base_eh: int = 0,
ensure_periodicity: bool = True,
num_chunks: int = 0,
Courant: float = 0.5,
accurate_fields_near_cylorigin: bool = False,
filename_prefix: Optional[str] = None,
output_volume: Optional[meep.simulation.Volume] = None,
output_single_precision: bool = False,
geometry_center: Union[meep.geom.Vector3, Tuple[float, ...]] = Vector3<0.0, 0.0, 0.0>,
force_all_components: bool = False,
split_chunks_evenly: bool = True,
chunk_layout=None,
collect_stats:bool=False):
collect_stats: bool = False):
```

<div class="method_docstring" markdown="1">
Expand Down Expand Up @@ -2843,6 +2843,27 @@ slow group velocities and are absorbed poorly by [PML](Perfectly_Matched_Layer.m

</div>

<a id="stop_when_energy_decayed"></a>

```python
def stop_when_energy_decayed(dt=None, decay_by=None):
```

<div class="function_docstring" markdown="1">

Return a `condition` function, suitable for passing to `Simulation.run` as the `until`
or `until_after_sources` parameter, that examines the field energy over the entire
cell volume at every `dt` time units and keeps incrementing the run time by `dt` until
its absolute value has decayed by at least `decay_by` from its maximum recorded value.

Note that, if you make `decay_by` very small, you may need to increase the `cutoff`
property of your source(s), to decrease the amplitude of the small high-frequency
field components that are excited when the source turns off. High frequencies near the
[Nyquist frequency](https://en.wikipedia.org/wiki/Nyquist_frequency) of the grid have
slow group velocities and are absorbed poorly by [PML](Perfectly_Matched_Layer.md).

</div>

<a id="stop_when_dft_decayed"></a>

```python
Expand Down
1 change: 1 addition & 0 deletions doc/docs/Python_User_Interface.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ A common point of confusion is described in [The Run Function Is Not A Loop](The
In particular, a useful value for `until_after_sources` or `until` is often `stop_when_field_decayed`, which is demonstrated in [Tutorial/Basics](Python_Tutorials/Basics.md#transmittance-spectrum-of-a-waveguide-bend). These top-level functions are available:

@@ stop_when_fields_decayed @@
@@ stop_when_energy_decayed @@
@@ stop_when_dft_decayed @@
@@ stop_after_walltime @@
@@ stop_on_interrupt @@
Expand Down
1 change: 1 addition & 0 deletions python/meep.i
Original file line number Diff line number Diff line change
Expand Up @@ -1833,6 +1833,7 @@ PyObject *_get_array_slice_dimensions(meep::fields *f, const meep::volume &where
stop_on_interrupt,
stop_when_dft_decayed,
stop_when_fields_decayed,
stop_when_energy_decayed,
synchronized_magnetic,
to_appended,
vec,
Expand Down
36 changes: 36 additions & 0 deletions python/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4514,6 +4514,42 @@ def _stop(sim):
return _stop


def stop_when_energy_decayed(dt=None, decay_by=None):
"""
Return a `condition` function, suitable for passing to `Simulation.run` as the `until`
or `until_after_sources` parameter, that examines the field energy over the entire
cell volume at every `dt` time units and keeps incrementing the run time by `dt` until
its absolute value has decayed by at least `decay_by` from its maximum recorded value.

Note that, if you make `decay_by` very small, you may need to increase the `cutoff`
property of your source(s), to decrease the amplitude of the small high-frequency
field components that are excited when the source turns off. High frequencies near the
[Nyquist frequency](https://en.wikipedia.org/wiki/Nyquist_frequency) of the grid have
slow group velocities and are absorbed poorly by [PML](Perfectly_Matched_Layer.md).
"""
if (dt is None) or (decay_by is None):
raise ValueError("dt and decay_by are all required.")

closure = {
'max_abs': 0,
't0': 0,
}

def _stop(sim):
if sim.round_time() <= dt + closure['t0']:
return False
else:
cell_volume = mp.Volume(center=sim.geometry_center, size=sim.cell_size)
cur_abs = abs(sim.field_energy_in_box(box=cell_volume))
closure['max_abs'] = max(closure['max_abs'], cur_abs)
closure['t0'] = sim.round_time()
if closure['max_abs'] != 0 and verbosity.meep > 0:
fmt = "energy decay(t = {}): {} / {} = {}"
print(fmt.format(sim.meep_time(), cur_abs, closure['max_abs'], cur_abs / closure['max_abs']))
return cur_abs <= closure['max_abs'] * decay_by
return _stop


def stop_after_walltime(t):
"""
Return a `condition` function, suitable for passing to `Simulation.run` as the `until`
Expand Down
4 changes: 2 additions & 2 deletions python/tests/test_bend_flux.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def init(self, no_bend=False, gdsii=False):
def run_bend_flux(self, from_gdsii_file):
# Normalization run
self.init(no_bend=True, gdsii=from_gdsii_file)
self.sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, self.pt, 1e-3))
self.sim.run(until_after_sources=mp.stop_when_energy_decayed(100, 1e-3))
# Save flux data for use in real run below
fdata = self.sim.get_flux_data(self.refl)
fdata_decimated = self.sim.get_flux_data(self.refl_decimated)
Expand Down Expand Up @@ -126,7 +126,7 @@ def run_bend_flux(self, from_gdsii_file):
# Load flux data obtained from normalization run
self.sim.load_minus_flux_data(self.refl, fdata)
self.sim.load_minus_flux_data(self.refl_decimated, fdata_decimated)
self.sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, self.pt, 1e-3))
self.sim.run(until_after_sources=mp.stop_when_energy_decayed(100, 1e-3))

expected = [
(0.09999999999999999, 1.8392235204829767e-5, -7.259467687598002e-6),
Expand Down