From 4844f6b835eab496e5d90791fc9656fec3c069e3 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Fri, 17 Sep 2021 17:56:43 -0700 Subject: [PATCH 1/5] documentation for stop_when_dft_decayed --- doc/docs/Python_User_Interface.md | 29 +++++++++++++++++++++++----- doc/docs/Python_User_Interface.md.in | 2 +- python/simulation.py | 29 ++++++++++++++++------------ 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/doc/docs/Python_User_Interface.md b/doc/docs/Python_User_Interface.md index 2a739ab3f..3df312bfa 100644 --- a/doc/docs/Python_User_Interface.md +++ b/doc/docs/Python_User_Interface.md @@ -2685,7 +2685,7 @@ In particular, a useful value for `until_after_sources` or `until` is often `sto ```python -def stop_when_fields_decayed(dt, c, pt, decay_by): +def stop_when_fields_decayed(dt=None, c=None, pt=None, decay_by=None): ```
@@ -2694,7 +2694,7 @@ Return a `condition` function, suitable for passing to `Simulation.run` as the ` or `until_after_sources` parameter, that examines the component `c` (e.g. `Ex`, etc.) at the point `pt` (a `Vector3`) and keeps running until its absolute value *squared* has decayed by at least `decay_by` from its maximum previous value. In particular, it -keeps incrementing the run time by `dT` (in Meep units) and checks the maximum value +keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value over that time period — in this way, it won't be fooled just because the field happens to go through 0 at some instant. @@ -2706,6 +2706,26 @@ slow group velocities and are absorbed poorly by [PML](Perfectly_Matched_Layer.m
+ + +```python +def stop_when_dft_decayed(tol=None, + minimum_run_time=0, + maximum_run_time=None): +``` + +
+ +Return a `condition` function, suitable for passing to `Simulation.run` as the `until` +or `until_after_sources` parameter, that checks all of the `Simulation`'s dft objects +every `dt` timesteps, and stops the simulation once *all* the field components and frequencies +of *every* dft object have decayed by at least some tolerance `tol` (no default value). +The optimal `dt` is determined automatically based on the frequency content in the DFT monitors. +There are two optional parameters: a minimum run time `minimum_run_time` (default: 0) or a +maximum run time `maximum_run_time` (no default). + +
+ ```python @@ -2734,7 +2754,6 @@ follows the `run` function (e.g., outputting fields). - Finally, another run function, useful for computing ω(**k**) band diagrams, is available via these `Simulation` methods: @@ -7491,7 +7510,7 @@ fr = mp.FluxRegion(volume=mp.GDSII_vol(fname, layer, zmin, zmax)) ```python -def stop_when_fields_decayed(dt, c, pt, decay_by): +def stop_when_fields_decayed(dt=None, c=None, pt=None, decay_by=None): ```
@@ -7500,7 +7519,7 @@ Return a `condition` function, suitable for passing to `Simulation.run` as the ` or `until_after_sources` parameter, that examines the component `c` (e.g. `Ex`, etc.) at the point `pt` (a `Vector3`) and keeps running until its absolute value *squared* has decayed by at least `decay_by` from its maximum previous value. In particular, it -keeps incrementing the run time by `dT` (in Meep units) and checks the maximum value +keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value over that time period — in this way, it won't be fooled just because the field happens to go through 0 at some instant. diff --git a/doc/docs/Python_User_Interface.md.in b/doc/docs/Python_User_Interface.md.in index 4fa2065a9..9affaf435 100644 --- a/doc/docs/Python_User_Interface.md.in +++ b/doc/docs/Python_User_Interface.md.in @@ -450,10 +450,10 @@ 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_dft_decayed @@ @@ stop_after_walltime @@ @@ stop_on_interrupt @@ - Finally, another run function, useful for computing ω(**k**) band diagrams, is available via these `Simulation` methods: @@ Simulation.run_k_points @@ diff --git a/python/simulation.py b/python/simulation.py index e71c41ab0..203520681 100644 --- a/python/simulation.py +++ b/python/simulation.py @@ -4354,13 +4354,13 @@ def _to_appended(sim, todo): return _to_appended -def stop_when_fields_decayed(dt, c, pt, decay_by): +def stop_when_fields_decayed(dt=None, c=None, pt=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 component `c` (e.g. `Ex`, etc.) at the point `pt` (a `Vector3`) and keeps running until its absolute value *squared* has decayed by at least `decay_by` from its maximum previous value. In particular, it - keeps incrementing the run time by `dT` (in Meep units) and checks the maximum value + keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value over that time period — in this way, it won't be fooled just because the field happens to go through 0 at some instant. @@ -4370,6 +4370,9 @@ def stop_when_fields_decayed(dt, c, pt, decay_by): [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 (c is None) or (pt is None) or (decay_by is None): + raise TypeError("stop_when_fields_decayed: dt, c, pt, decay_by must all be specified.") + closure = { 'max_abs': 0, 'cur_max': 0, @@ -4428,18 +4431,20 @@ def _stop(sim): return _stop -def stop_when_dft_decayed(tol, minimum_run_time=0, maximum_run_time=None): +def stop_when_dft_decayed(tol=None, minimum_run_time=0, maximum_run_time=None): """ - Return a `condition` function, suitable for passing to `sim.run()` as the `until` - or `until_after_sources` parameter, that checks all of the Simulation's dft objects - every `dt` timesteps, and stops the simulation once all the components and frequencies - of *every* dft object have decayed by at least some tolerance, `tol`. The routine - calculates the optimal `dt` to use based on the frequency content in the DFT monitors. - - Optionally the user can specify a minimum run time (`minimum_run_time`) or a maximum - run time (`maximum_run_time`). + Return a `condition` function, suitable for passing to `Simulation.run` as the `until` + or `until_after_sources` parameter, that checks all of the `Simulation`'s dft objects + every `dt` timesteps, and stops the simulation once *all* the field components and frequencies + of *every* dft object have decayed by at least some tolerance `tol` (no default value). + The optimal `dt` is determined automatically based on the frequency content in the DFT monitors. + There are two optional parameters: a minimum run time `minimum_run_time` (default: 0) or a + maximum run time `maximum_run_time` (no default). """ - # Record data in closure so that we can persitently edit + if tol is None: + raise TypeError("stop_when_dft_decayed: tol parameter must be specified.") + + # Record data in closure so that we can persistently edit closure = {'previous_fields':0, 't0':0, 'dt':0, 'maxchange':0} def _stop(_sim): if _sim.fields.t == 0: From 2df927acd1993e9b0dd4ddecc76a20ae233aaf40 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Fri, 17 Sep 2021 18:07:45 -0700 Subject: [PATCH 2/5] fix --- doc/docs/Python_User_Interface.md | 8 ++++---- python/simulation.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/docs/Python_User_Interface.md b/doc/docs/Python_User_Interface.md index 3df312bfa..64b6d7e7d 100644 --- a/doc/docs/Python_User_Interface.md +++ b/doc/docs/Python_User_Interface.md @@ -2717,10 +2717,10 @@ def stop_when_dft_decayed(tol=None,
Return a `condition` function, suitable for passing to `Simulation.run` as the `until` -or `until_after_sources` parameter, that checks all of the `Simulation`'s dft objects -every `dt` timesteps, and stops the simulation once *all* the field components and frequencies -of *every* dft object have decayed by at least some tolerance `tol` (no default value). -The optimal `dt` is determined automatically based on the frequency content in the DFT monitors. +or `until_after_sources` parameter, that checks the `Simulation`'s dft objects every `dt` +timesteps, and stops the simulation once all the field components and frequencies of *every* +dft object have decayed by at least some tolerance `tol` (no default value). The optimal `dt` +is determined automatically based on the frequency content in the DFT monitors. There are two optional parameters: a minimum run time `minimum_run_time` (default: 0) or a maximum run time `maximum_run_time` (no default). diff --git a/python/simulation.py b/python/simulation.py index 203520681..777a194fc 100644 --- a/python/simulation.py +++ b/python/simulation.py @@ -4434,10 +4434,10 @@ def _stop(sim): def stop_when_dft_decayed(tol=None, minimum_run_time=0, maximum_run_time=None): """ Return a `condition` function, suitable for passing to `Simulation.run` as the `until` - or `until_after_sources` parameter, that checks all of the `Simulation`'s dft objects - every `dt` timesteps, and stops the simulation once *all* the field components and frequencies - of *every* dft object have decayed by at least some tolerance `tol` (no default value). - The optimal `dt` is determined automatically based on the frequency content in the DFT monitors. + or `until_after_sources` parameter, that checks the `Simulation`'s dft objects every `dt` + timesteps, and stops the simulation once all the field components and frequencies of *every* + dft object have decayed by at least some tolerance `tol` (no default value). The optimal `dt` + is determined automatically based on the frequency content in the DFT monitors. There are two optional parameters: a minimum run time `minimum_run_time` (default: 0) or a maximum run time `maximum_run_time` (no default). """ From 8226d3f82bdd0da709e3605956c2810b8cfbe558 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sat, 18 Sep 2021 02:19:27 +0000 Subject: [PATCH 3/5] replace TypeError with ValueError for required arguments --- doc/docs/Python_User_Interface.md | 12 ++++++------ python/simulation.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/docs/Python_User_Interface.md b/doc/docs/Python_User_Interface.md index 64b6d7e7d..6716b4a0a 100644 --- a/doc/docs/Python_User_Interface.md +++ b/doc/docs/Python_User_Interface.md @@ -2691,12 +2691,12 @@ def stop_when_fields_decayed(dt=None, c=None, pt=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 component `c` (e.g. `Ex`, etc.) +or `until_after_sources` parameter, that examines the component `c` (e.g. `meep.Ex`, etc.) at the point `pt` (a `Vector3`) and keeps running until its absolute value *squared* has decayed by at least `decay_by` from its maximum previous value. In particular, it keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value over that time period — in this way, it won't be fooled just because the field -happens to go through 0 at some instant. +happens to go through zero at some instant. 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 @@ -2719,8 +2719,8 @@ def stop_when_dft_decayed(tol=None, Return a `condition` function, suitable for passing to `Simulation.run` as the `until` or `until_after_sources` parameter, that checks the `Simulation`'s dft objects every `dt` timesteps, and stops the simulation once all the field components and frequencies of *every* -dft object have decayed by at least some tolerance `tol` (no default value). The optimal `dt` -is determined automatically based on the frequency content in the DFT monitors. +dft object have decayed by at least some tolerance `tol` (no default value). The time interval +`dt` is determined automatically based on the frequency content in the DFT monitors. There are two optional parameters: a minimum run time `minimum_run_time` (default: 0) or a maximum run time `maximum_run_time` (no default). @@ -7516,12 +7516,12 @@ def stop_when_fields_decayed(dt=None, c=None, pt=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 component `c` (e.g. `Ex`, etc.) +or `until_after_sources` parameter, that examines the component `c` (e.g. `meep.Ex`, etc.) at the point `pt` (a `Vector3`) and keeps running until its absolute value *squared* has decayed by at least `decay_by` from its maximum previous value. In particular, it keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value over that time period — in this way, it won't be fooled just because the field -happens to go through 0 at some instant. +happens to go through zero at some instant. 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 diff --git a/python/simulation.py b/python/simulation.py index 777a194fc..3560c4e50 100644 --- a/python/simulation.py +++ b/python/simulation.py @@ -4357,12 +4357,12 @@ def _to_appended(sim, todo): def stop_when_fields_decayed(dt=None, c=None, pt=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 component `c` (e.g. `Ex`, etc.) + or `until_after_sources` parameter, that examines the component `c` (e.g. `meep.Ex`, etc.) at the point `pt` (a `Vector3`) and keeps running until its absolute value *squared* has decayed by at least `decay_by` from its maximum previous value. In particular, it keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value over that time period — in this way, it won't be fooled just because the field - happens to go through 0 at some instant. + happens to go through zero at some instant. 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 @@ -4371,7 +4371,7 @@ def stop_when_fields_decayed(dt=None, c=None, pt=None, decay_by=None): slow group velocities and are absorbed poorly by [PML](Perfectly_Matched_Layer.md). """ if (dt is None) or (c is None) or (pt is None) or (decay_by is None): - raise TypeError("stop_when_fields_decayed: dt, c, pt, decay_by must all be specified.") + raise ValueError("dt, c, pt, and decay_by are all required.") closure = { 'max_abs': 0, @@ -4436,13 +4436,13 @@ def stop_when_dft_decayed(tol=None, minimum_run_time=0, maximum_run_time=None): Return a `condition` function, suitable for passing to `Simulation.run` as the `until` or `until_after_sources` parameter, that checks the `Simulation`'s dft objects every `dt` timesteps, and stops the simulation once all the field components and frequencies of *every* - dft object have decayed by at least some tolerance `tol` (no default value). The optimal `dt` - is determined automatically based on the frequency content in the DFT monitors. + dft object have decayed by at least some tolerance `tol` (no default value). The time interval + `dt` is determined automatically based on the frequency content in the DFT monitors. There are two optional parameters: a minimum run time `minimum_run_time` (default: 0) or a maximum run time `maximum_run_time` (no default). """ if tol is None: - raise TypeError("stop_when_dft_decayed: tol parameter must be specified.") + raise ValueError("tol is required.") # Record data in closure so that we can persistently edit closure = {'previous_fields':0, 't0':0, 'dt':0, 'maxchange':0} From bc6779da1d396d6527c05852c3eb783ca5ecd1bb Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sat, 18 Sep 2021 02:55:49 +0000 Subject: [PATCH 4/5] show DFT decay status in output when verbosity > 1 --- python/simulation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/simulation.py b/python/simulation.py index 3560c4e50..b3bec8df2 100644 --- a/python/simulation.py +++ b/python/simulation.py @@ -4462,11 +4462,11 @@ def _stop(_sim): if previous_fields == 0: closure['previous_fields'] = current_fields return False - + closure['previous_fields'] = current_fields closure['t0'] = _sim.fields.t - if mp.verbosity > 0: - fmt = "DFT decay(t = {0:1.1f}): {1:0.4e}" + if mp.verbosity > 1: + fmt = "DFT fields decay(t = {0:0.2f}): {1:0.4e}" print(fmt.format(_sim.meep_time(), np.real(change/closure['maxchange']))) return (change/closure['maxchange']) <= tol and _sim.round_time() >= minimum_run_time From 7ee74bf597ca2de4ec6a089b82658e30fd7605f3 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Tue, 21 Sep 2021 01:37:43 +0000 Subject: [PATCH 5/5] use default value for tol --- doc/docs/Python_User_Interface.md | 4 ++-- python/simulation.py | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/doc/docs/Python_User_Interface.md b/doc/docs/Python_User_Interface.md index 6716b4a0a..aeeaf28c4 100644 --- a/doc/docs/Python_User_Interface.md +++ b/doc/docs/Python_User_Interface.md @@ -2709,7 +2709,7 @@ slow group velocities and are absorbed poorly by [PML](Perfectly_Matched_Layer.m ```python -def stop_when_dft_decayed(tol=None, +def stop_when_dft_decayed(tol=1e-11, minimum_run_time=0, maximum_run_time=None): ``` @@ -2719,7 +2719,7 @@ def stop_when_dft_decayed(tol=None, Return a `condition` function, suitable for passing to `Simulation.run` as the `until` or `until_after_sources` parameter, that checks the `Simulation`'s dft objects every `dt` timesteps, and stops the simulation once all the field components and frequencies of *every* -dft object have decayed by at least some tolerance `tol` (no default value). The time interval +dft object have decayed by at least some tolerance `tol` (default is 1e-11). The time interval `dt` is determined automatically based on the frequency content in the DFT monitors. There are two optional parameters: a minimum run time `minimum_run_time` (default: 0) or a maximum run time `maximum_run_time` (no default). diff --git a/python/simulation.py b/python/simulation.py index b3bec8df2..568995705 100644 --- a/python/simulation.py +++ b/python/simulation.py @@ -4431,18 +4431,16 @@ def _stop(sim): return _stop -def stop_when_dft_decayed(tol=None, minimum_run_time=0, maximum_run_time=None): +def stop_when_dft_decayed(tol=1e-11, minimum_run_time=0, maximum_run_time=None): """ Return a `condition` function, suitable for passing to `Simulation.run` as the `until` or `until_after_sources` parameter, that checks the `Simulation`'s dft objects every `dt` timesteps, and stops the simulation once all the field components and frequencies of *every* - dft object have decayed by at least some tolerance `tol` (no default value). The time interval + dft object have decayed by at least some tolerance `tol` (default is 1e-11). The time interval `dt` is determined automatically based on the frequency content in the DFT monitors. There are two optional parameters: a minimum run time `minimum_run_time` (default: 0) or a maximum run time `maximum_run_time` (no default). """ - if tol is None: - raise ValueError("tol is required.") # Record data in closure so that we can persistently edit closure = {'previous_fields':0, 't0':0, 'dt':0, 'maxchange':0}