Skip to content

Commit

Permalink
Documentation improvements
Browse files Browse the repository at this point in the history
Made final round of changes and checked against compiled docs
Will be ready for release once rebased
  • Loading branch information
m-bone committed Aug 26, 2024
1 parent d4b4402 commit 7a6f8eb
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 71 deletions.
Binary file added docs/_static/img/design.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 4 additions & 5 deletions docs/api/plugins/design.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ Design Space Exploration
:toctree: ../_autosummary/
:template: module.rst

tidy3d.plugins.design.Parameter
tidy3d.plugins.design.ParameterFloat
tidy3d.plugins.design.ParameterInt
tidy3d.plugins.design.ParameterAny
tidy3d.plugins.design.Method
tidy3d.plugins.design.MethodGrid
tidy3d.plugins.design.MethodMonteCarlo
tidy3d.plugins.design.MethodRandomCustom
tidy3d.plugins.design.MethodRandom
tidy3d.plugins.design.MethodBayOpt
tidy3d.plugins.design.MethodGenAlg
tidy3d.plugins.design.MethodParticleSwarm
tidy3d.plugins.design.DesignSpace
tidy3d.plugins.design.Results
tidy3d.plugins.design.Result
26 changes: 10 additions & 16 deletions tidy3d/plugins/design/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Parameter Sweep Plugin
# Design Plugin

## Basics

The parameter sweep plugin `tidy3d.plugins.design` is a wrapper designed to make it simple and convenient for `tidy3d` users to define their parameter scans.
The `Design` plugin `tidy3d.plugins.design` is a wrapper designed to make it simple and convenient for `Tidy3D` users to define parameter scans and optimizations.

In short, users define the dimensions of their design design, as well as the method they wish to explore the design space. These specifications are combined in a `DesignSpace` object.
In short, users define the dimensions of their design, as well as the method used to explore the design space. These specifications are combined in a `DesignSpace` object.

Then, the user passes a function that defines the input / output relationship they wish to explore. The function arguments correspond to the dimensions defined in the `DesignSpace` and the function outputs can be anything.
The user then passes a function that defines the input / output relationship they wish to explore. The function arguments correspond to the dimensions defined in the `DesignSpace` and the function outputs can be anything.

The result is stored as a `Result` object, which can be easily converted to a `pandas.DataFrame` for analysis, post processing, or visualization. The columns in this `DataFrame` correspond to the function inputs and outputs and each datapoint corresponds to a row in this `DataFrame`.

Expand All @@ -18,9 +18,9 @@ import tidy3d.plugins.design as tdd

## Function

The first step in using the parameter sweep is to write the design design as a function that we would like to explore. This function could ideally involve a `tidy3d` simulation, but actually does not have to.
The first step in using the `Design` plugin is to write the design as a function that can be explored. This function typically involves a `Tidy3D` simulation, but actually does not have to.

For a concrete example, say we are analyzing a system comprised of a set of `n` spheres, each with radius `r`. We could write a function to compute the transmission through this system as follows (with some pseudo-code used for brevity).
Say we are analyzing a system comprised of a set of `n` spheres, each with radius `r`. We could write a function to compute the transmission through this system as follows (with some pseudo-code used for brevity).

```py
def transmission(n: int, r: float) -> float:
Expand Down Expand Up @@ -48,11 +48,11 @@ def transmission_split(n: int, r: float) -> float:
return post(data=data)
```

As we'll see, putting it in this form will be useful although it is not necessary.
Putting it in this form is useful as it allows the `Design` plugin to automate parallelization through `Batch` objects, although it is not necessary.

## Parameters

Now, we could query our transmission function directly to construct a parameter scan, but it would be more convenient to simply **define** our parameter scan as a specification and have the `tidy3d` wrapper do the accounting for us.
Now, we could query our transmission function directly to construct a parameter scan, but it would be more convenient to simply **define** our parameter scan as a specification and have the `Tidy3D` wrapper do the accounting for us.

The first step is to define the design "parameters" (or dimensions), which also serve as inputs to our function defined earlier.

Expand All @@ -79,7 +79,7 @@ By defining our design parameters like this, we are mainly specifying what type,

## Method

Now that we've defined our parameters, we also need to define the procedure that we should use to query the design space we've defined. One approach is to randomly sample points within the design bounds, another is to perform a grid search to uniformly scan the bounds. There are also more complex methods, such as Bayesian Optimization, which are not implemented yet.
Now that we've defined our parameters, we also need to define the procedure that we should use to query the design space we've defined. One approach is to randomly sample points within the design bounds, another is to perform a grid search to uniformly scan the bounds. There are also more complex methods, such as Bayesian Optimization or genetic algorithms.

For this example, let's define a random sampling of the design parameters with 20 points.

Expand All @@ -95,15 +95,9 @@ With the design parameters and our method defined, we can combine everything int
design_space = tdd.DesignSpace(parameters=[param_n, param_r], method=method)
```

Note, we haven't told the `DesignSpace` anything about our function. For that, it has two methods `.run()` and `.run_batch()`, which accept our function.

`DesignSpace.run(f)` samples the design parameters according to the `method` and then evaluates each point one by one. Note that it has to be sequential because of the generality of this approach, in short `f` could be anything so we don't make any assumptions about whether it can be parallelized.

On the other hand, `DesignSpace.run_batch(f_pre, f_post)` accepts our pre and post processing functions and assumes that a simulation is run in between. Because of this, this method can safely construct a `web.Batch` under the hood and run the tasks in parallel, stitching together the final results.

## Results

The `DesignSpace.run()` and `DesignSpace.run_batch()` functions described before both return a `Result` object, which is basically a dataset containing the function inputs, outputs, source code, and any task ID information corresponding to each data point. Note that task ID can only be gathered if using `run_batch` because in the more general `run()` function, `tidy3d` can't know which tasks were involved in each data point.
The `DesignSpace.run()` function returns a `Result` object, which is basically a dataset containing the function inputs, outputs, source code, and any task ID information corresponding to each data point.

The `Results` can be converted to a `pandas.DataFrame` where each row is a separate data point and each column is either an input or output for a function. It also contains various methods for plotting and managing the data.

Expand Down
69 changes: 43 additions & 26 deletions tidy3d/plugins/design/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,31 @@

class DesignSpace(Tidy3dBaseModel):
"""Manages all exploration of a parameter space within specified parameters using a supplied search method.
The ``DesignSpace`` forms the basis of the ``Design`` plugin, and receives a ``Method`` and ``Parameter`` list that
define the scope of the design space and how it should be searched. ``DesignSpace.run()`` can then be called with
a function(s) to generate different solutions from parameters suggested by the ``Method``. The ``Method`` can either
sample the design space systematically or randomly, or can optimize for a given problem through an iterative search
and evaluate approach.
Schematic outline of how to use the ``Design`` plugin to explore a design space.
.. image:: ../../_static/img/design.png
:width: 50%
:align: left
The `Design <https://www.flexcompute.com/tidy3d/examples/notebooks/Design/>'_ notebook contains an overview of the
``Design`` plugin and is the best place to learn how to get started.
Notes
-----
Schematic outline of how to use the ``Design`` plugin to explore a design space.
.. image:: ../../../../_static/img/design.png
:width: 80%
:align: center
Detailed examples using the ``Design`` plugin can be found in the following notebooks:
`All-Dielectric Structural Colors <https://www.flexcompute.com/tidy3d/examples/notebooks/AllDielectricStructuralColor/>'_
`Bayesian Optimization of Y-Junction <https://www.flexcompute.com/tidy3d/examples/notebooks/BayesianOptimizationYJunction/>'_
`Genetic Algorithm Reflector <https://www.flexcompute.com/tidy3d/examples/notebooks/GeneticAlgorithmReflector/>'_
`Particle Swarm Optimizer PBS <https://www.flexcompute.com/tidy3d/examples/notebooks/ParticleSwarmOptimizedPBS/>'_
`Particle Swarm Optimizer Bullseye Cavity <https://www.flexcompute.com/tidy3d/examples/notebooks/BullseyeCavityPSO/>'_
The `Design <https://www.flexcompute.com/tidy3d/examples/notebooks/Design/>`_ notebook contains an overview of the
``Design`` plugin and is the best place to learn how to get started.
Detailed examples using the ``Design`` plugin can be found in the following notebooks:
* `All-Dielectric Structural Colors <https://www.flexcompute.com/tidy3d/examples/notebooks/AllDielectricStructuralColor/>`_
* `Bayesian Optimization of Y-Junction <https://www.flexcompute.com/tidy3d/examples/notebooks/BayesianOptimizationYJunction/>`_
* `Genetic Algorithm Reflector <https://www.flexcompute.com/tidy3d/examples/notebooks/GeneticAlgorithmReflector/>`_
* `Particle Swarm Optimizer PBS <https://www.flexcompute.com/tidy3d/examples/notebooks/ParticleSwarmOptimizedPBS/>`_
* `Particle Swarm Optimizer Bullseye Cavity <https://www.flexcompute.com/tidy3d/examples/notebooks/BullseyeCavityPSO/>`_
Example
-------
Expand Down Expand Up @@ -76,7 +80,8 @@ class DesignSpace(Tidy3dBaseModel):
task_name: str = pd.Field(
"",
title="Task Name",
description="Task name assigned to tasks along with a simulation counter in the form of {task_name}_{counter}. "
description="Task name assigned to tasks along with a simulation counter in the form of {task_name}_{sim_index}_{counter} where ``sim_index`` is "
"the index of the ``Simulation`` from the pre function output. "
"If the pre function outputs a dictionary the key will be included in the task name as {task_name}_{dict_key}_{counter}. "
"Only used when pre-post functions are supplied.",
)
Expand Down Expand Up @@ -139,7 +144,6 @@ def get_fn_source(function: Callable) -> str:

def run(self, fn: Callable, fn_post: Callable = None, verbose: bool = True) -> Result:
"""Explore a parameter space with a supplied method using the user supplied function.
Supplied functions are used to evaluate the design space and are called within the method.
For optimization methods these functions act as the fitness function. A single function can be
supplied which will contain the preprocessing, computation, and analysis of the desired problem.
Expand All @@ -156,17 +160,30 @@ def run(self, fn: Callable, fn_post: Callable = None, verbose: bool = True) -> R
parallel computation on the cloud. The original structure is then restored for output; all ``Simulation`` objects are replaced by ``SimulationData`` objects.
Example pre return formats and associated post inputs can be seen in the table below.
| fn_pre return | fn_post call |
|-------------------------------------------|---------------------------------------------------|
| 1.0 | fn_post(1.0) |
| [1,2,3] | fn_post(1,2,3) |
| {'a': 2, 'b': 'hi'} | fn_post(a=2, b='hi') |
| Simulation | fn_post(SimulationData) |
| Batch | fn_post(BatchData) |
| [Simulation, Simulation] | fn_post(SimulationData, SimulationData) |
| [Simulation, 1.0] | fn_post(SimulationData, 1.0) |
| [Simulation, Batch] | fn_post(SimulationData, BatchData) |
| {'a': Simulation, 'b': Batch, 'c': 2.0} | fn_post(a=SimulationData, b=BatchData, c=2.0) |
.. list-table:: Pre return formats and post input formats
:widths: 50 50
:header-rows: 1
* - fn_pre return
- fn_post call
* - 1.0
- fn_post(1.0)
* - [1,2,3]
- fn_post(1,2,3)
* - {'a': 2, 'b': 'hi'}
- fn_post(a=2, b='hi')
* - Simulation
- fn_post(SimulationData)
* - Batch
- fn_post(BatchData)
* - [Simulation, Simulation]
- fn_post(SimulationData, SimulationData)
* - [Simulation, 1.0]
- fn_post(SimulationData, 1.0)
* - [Simulation, Batch]
- fn_post(SimulationData, BatchData)
* - {'a': Simulation, 'b': Batch, 'c': 2.0}
- fn_post(a=SimulationData, b=BatchData, c=2.0)
The output of ``fn_post`` (or ``fn`` if only one function is supplied) must be a float
or a container where the first element is a ``float`` and second element is a ``list`` / ``dict`` e,g. [float {"aux_1": str}].
Expand Down
Loading

0 comments on commit 7a6f8eb

Please sign in to comment.