Skip to content

Commit

Permalink
markdown documentation for stop_when_dft_decayed (NanoComp#1759)
Browse files Browse the repository at this point in the history
* documentation for stop_when_dft_decayed

* fix

* replace TypeError with ValueError for required arguments

* show DFT decay status in output when verbosity > 1

* use default value for tol
  • Loading branch information
oskooi authored and mawc2019 committed Nov 3, 2021
1 parent 4ca2cb5 commit eafa0f6
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 27 deletions.
37 changes: 28 additions & 9 deletions doc/docs/Python_User_Interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -2685,18 +2685,18 @@ In particular, a useful value for `until_after_sources` or `until` is often `sto
<a id="stop_when_fields_decayed"></a>

```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):
```

<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 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
keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value
over that time period &mdash; 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
Expand All @@ -2706,6 +2706,26 @@ slow group velocities and are absorbed poorly by [PML](Perfectly_Matched_Layer.m

</div>

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

```python
def stop_when_dft_decayed(tol=1e-11,
minimum_run_time=0,
maximum_run_time=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 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` (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).

</div>

<a id="stop_after_walltime"></a>

```python
Expand Down Expand Up @@ -2734,7 +2754,6 @@ follows the `run` function (e.g., outputting fields).

</div>


Finally, another run function, useful for computing ω(**k**) band diagrams, is available via these `Simulation` methods:


Expand Down Expand Up @@ -7506,18 +7525,18 @@ fr = mp.FluxRegion(volume=mp.GDSII_vol(fname, layer, zmin, zmax))
<a id="stop_when_fields_decayed"></a>

```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):
```

<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 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
keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value
over that time period &mdash; 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
Expand Down
2 changes: 1 addition & 1 deletion doc/docs/Python_User_Interface.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 @@
Expand Down
37 changes: 20 additions & 17 deletions python/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4354,22 +4354,25 @@ 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.)
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
keeps incrementing the run time by `dt` (in Meep units) and checks the maximum value
over that time period &mdash; 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
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 (c is None) or (pt is None) or (decay_by is None):
raise ValueError("dt, c, pt, and decay_by are all required.")

closure = {
'max_abs': 0,
'cur_max': 0,
Expand Down Expand Up @@ -4428,18 +4431,18 @@ 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=1e-11, 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 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` (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).
"""
# Record data in closure so that we can persitently edit

# 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:
Expand All @@ -4457,11 +4460,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

Expand Down

0 comments on commit eafa0f6

Please sign in to comment.