diff --git a/CHANGELOG.md b/CHANGELOG.md index d89acf6cd..1696c50e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- Added `tidy3d.plugins.metrics` module for constructing and serializing simulation metrics like `ModeCoefficient` and `ModePower`. +- Added `tidy3d.plugins.expressions` module for constructing and serializing mathematical expressions and simulation metrics like `ModeAmps` and `ModePower`. ## [2.7.3] - 2024-09-12 diff --git a/tests/test_plugins/metrics/__init__.py b/tests/test_plugins/expressions/__init__.py similarity index 100% rename from tests/test_plugins/metrics/__init__.py rename to tests/test_plugins/expressions/__init__.py diff --git a/tests/test_plugins/metrics/test_functions.py b/tests/test_plugins/expressions/test_functions.py similarity index 86% rename from tests/test_plugins/metrics/test_functions.py rename to tests/test_plugins/expressions/test_functions.py index e998d85c0..c002ed7e5 100644 --- a/tests/test_plugins/metrics/test_functions.py +++ b/tests/test_plugins/expressions/test_functions.py @@ -1,7 +1,7 @@ import numpy as np import pytest -from tidy3d.plugins.metrics.functions import Cos, Exp, Log, Log10, Sin, Tan -from tidy3d.plugins.metrics.variables import Constant +from tidy3d.plugins.expressions.functions import Cos, Exp, Log, Log10, Sin, Tan +from tidy3d.plugins.expressions.variables import Constant FUNCTIONS = [ (Sin, np.sin), diff --git a/tests/test_plugins/metrics/test_operators.py b/tests/test_plugins/expressions/test_operators.py similarity index 96% rename from tests/test_plugins/metrics/test_operators.py rename to tests/test_plugins/expressions/test_operators.py index 3539bbd28..d794a928f 100644 --- a/tests/test_plugins/metrics/test_operators.py +++ b/tests/test_plugins/expressions/test_operators.py @@ -2,7 +2,7 @@ import numpy as np import pytest -from tidy3d.plugins.metrics.operators import ( +from tidy3d.plugins.expressions.operators import ( Abs, Add, Divide, diff --git a/tests/test_plugins/metrics/test_variables.py b/tests/test_plugins/expressions/test_variables.py similarity index 97% rename from tests/test_plugins/metrics/test_variables.py rename to tests/test_plugins/expressions/test_variables.py index 6f939da5f..0d4818c9a 100644 --- a/tests/test_plugins/metrics/test_variables.py +++ b/tests/test_plugins/expressions/test_variables.py @@ -1,6 +1,6 @@ import numpy as np import pytest -from tidy3d.plugins.metrics.variables import Constant, Variable +from tidy3d.plugins.expressions.variables import Constant, Variable @pytest.fixture(params=[1, 2.5, 1 + 2j, np.array([1, 2, 3])]) diff --git a/tidy3d/plugins/metrics/README.md b/tidy3d/plugins/expressions/README.md similarity index 55% rename from tidy3d/plugins/metrics/README.md rename to tidy3d/plugins/expressions/README.md index cc8388621..48e998bf7 100644 --- a/tidy3d/plugins/metrics/README.md +++ b/tidy3d/plugins/expressions/README.md @@ -1,26 +1,26 @@ -# Metrics module +# Expressions module -The `metrics` module provides a way to construct and serialize complex mathematical expressions involving simulation metrics in Tidy3D. +The `expressions` module provides a way to construct and serialize complex mathematical expressions involving simulation metrics in Tidy3D. It allows users to define objective functions for optimization tasks, for example in conjunction with the `invdes` plugin. This module is essential for creating expressions that can be easily saved, loaded, and passed between different components of a simulation workflow. ## Introduction -The `metrics` module is designed to facilitate the construction of serializable mathematical expressions involving simulation metrics like mode power, mode coefficients, field intensity, and more. +The `expressions` module is designed to facilitate the construction of serializable mathematical expressions involving simulation metrics like mode power, mode coefficients, field intensity, and more. These expressions can be combined using standard arithmetic operators. This functionality is important when defining objective functions for optimization routines, especially in inverse design tasks where the objective functions may need to be transmitted or stored. -## Usage - ### Creating metrics -To start using the `metrics` module, you can create expressions using predefined metric classes such as `ModeCoefficient` and `ModePower`. +To start using the `expressions` module, you can create metrics using predefined metric classes such as `ModeAmp` and `ModePower`. + +Metrics are a special instance of a `Variable`, which itself is a subclass of `Expression`, that take a `SimulationData` as input and are intended to return a single scalar. ```python -from tidy3d.plugins.metrics import ModeCoefficient, ModePower +from tidy3d.plugins.expressions import ModeAmp, ModePower -# Create a ModeCoefficient metric -mode_coeff = ModeCoefficient(monitor_name="monitor1", freqs=[1.0]) +# Create a ModeAmp metric +mode_coeff = ModeAmp(monitor_name="monitor1", freqs=[1.0]) # Create a ModePower metric mode_power = ModePower(monitor_name="monitor2", freqs=[1.0]) @@ -29,6 +29,7 @@ mode_power = ModePower(monitor_name="monitor2", freqs=[1.0]) ### Combining metrics with operators Metrics can be combined using standard arithmetic operators like `+`, `-`, `*`, `/`, `**`, and functions like `abs()`. +Together, they will form an `Expression`. ```python # Define an objective function using metrics @@ -37,15 +38,15 @@ f = abs(mode_coeff) - mode_power / 2 ### Functions -The `metrics` module also provides a set of mathematical functions that can be used to create more complex expressions. +The `expressions` module also provides a set of mathematical functions that can be used to create more complex expressions. ```python -from tidy3d.plugins.metrics import Sin, Cos +from tidy3d.plugins.expressions import Sin, Cos f = Sin(mode_coeff) + Cos(mode_power) ``` -### Evaluating metrics +### Evaluating expressions Once you have a metric, you can evaluate it using simulation data. @@ -57,30 +58,66 @@ result = f.evaluate(data) result = f(data) ``` -### Serializing and deserializing metrics +### Serializing and deserializing expressions -Metrics can be serialized to a file using the `to_file` method and deserialized using the `from_file` class method. +Expressions can be serialized to a file using the `to_file` method and deserialized using the `from_file` class method. ```python # Serialize the metric to a file f.to_file("metric_expression.hdf5") # Deserialize the metric from a file -from tidy3d.plugins.metrics import Expression +from tidy3d.plugins.expressions import Expression loaded_expr = Expression.from_file("metric_expression.hdf5") ``` +## Supported features + +### Operators and functions + +The `expressions` module supports various operators and functions to build complex expressions: + +| Type | Name | Description | Class Name | +|------------|------------|--------------------------------------------------|------------------| +| Operator | `+` | Addition | `Add` | +| Operator | `-` | Subtraction | `Subtract` | +| Operator | `*` | Multiplication | `Multiply` | +| Operator | `/` | Division | `Divide` | +| Operator | `**` | Power | `Power` | +| Operator | `//` | Floor Division | `FloorDivide` | +| Operator | `%` | Modulus | `Modulus` | +| Operator | `@` | Matrix Multiplication | `MatMul` | +| Operator | `abs` | Absolute Value | `Abs` | +| Function | `Sin` | Sine function | `Sin` | +| Function | `Cos` | Cosine function | `Cos` | +| Function | `Tan` | Tangent function | `Tan` | +| Function | `Exp` | Exponential function | `Exp` | +| Function | `Log` | Natural logarithm function | `Log` | +| Function | `Log10` | Base-10 logarithm function | `Log10` | + +### Variables and metrics + +The module provides predefined metrics and variables for constructing expressions. +Metrics represent specific simulation data, while variables act as placeholders. + +| Type | Name | Description | +|------------|------------|--------------------------------------------------| +| Metric | `ModeAmp` | Metric for calculating the mode coefficient | +| Metric | `ModePower`| Metric for calculating the mode power | +| Variable | `Constant` | Fixed value in expressions | +| Variable | `Variable` | Placeholder for values in expressions | + ## Examples -### `ModeCoefficient` and `ModePower` +### `ModeAmp` and `ModePower` -In this example, we create metrics using only `ModeCoefficient` and `ModePower` and combine them to define an objective function. +In this example, we create metrics using only `ModeAmp` and `ModePower` and combine them to define an objective function. ```python -from tidy3d.plugins.metrics import ModeCoefficient, ModePower +from tidy3d.plugins.expressions import ModeAmp, ModePower # Create metrics -mode_coeff = ModeCoefficient(monitor_name="monitor1", freqs=[1.0]) +mode_coeff = ModeAmp(monitor_name="monitor1", freqs=[1.0]) mode_power = ModePower(monitor_name="monitor2", freqs=[1.0]) # Define an objective function using metrics @@ -93,7 +130,7 @@ print(f) **Expected output:** ```text -(abs(ModeCoefficient("monitor1")) - (ModePower("monitor2") / 2)) +(abs(ModeAmp("monitor1")) - (ModePower("monitor2") / 2)) ``` **Evaluating the expression:** @@ -108,16 +145,16 @@ print(result) ### Using variables -The `metrics` module provides `Variable` and `Constant` classes to represent placeholders and fixed values in your expressions. +The `expressions` module provides `Variable` and `Constant` classes to represent placeholders and fixed values in your expressions. Variables can be used to parameterize expressions, allowing you to supply values at evaluation time. -Note that a `Metric` such as `ModeCoefficient` is a subclass of `Variable`, so it can be used in the same way. +Note that a `Metric` such as `ModeAmp` is a subclass of `Variable`, so it can be used in the same way. #### Unnamed variables (positional arguments) If you create a `Variable` without a name, it expects its value to be provided as a single positional argument during evaluation. ```python -from tidy3d.plugins.metrics import Variable +from tidy3d.plugins.expressions import Variable # Create an unnamed variable x = Variable() @@ -136,7 +173,7 @@ print(result) # Outputs: 126 If you create a `Variable` with a name, it expects its value to be provided as a keyword argument during evaluation. ```python -from tidy3d.plugins.metrics import Variable +from tidy3d.plugins.expressions import Variable # Create named variables x = Variable(name="x") @@ -166,13 +203,13 @@ print(result) # Outputs: 25 #### A `Metric` is a `Variable` -A `Metric` such as `ModeCoefficient` is a subclass of `Variable`, so all the rules for `Variable` apply to `Metric` as well. +A `Metric` such as `ModeAmp` is a subclass of `Variable`, so all the rules for `Variable` apply to `Metric` as well. -from tidy3d.plugins.metrics import ModeCoefficient, ModePower +from tidy3d.plugins.expressions import ModeAmp, ModePower ```python # Define two named metrics -mode_coeff1 = ModeCoefficient(name="mode_coeff1", monitor_name="monitor1", freqs=[1.0]) +mode_coeff1 = ModeAmp(name="mode_coeff1", monitor_name="monitor1", freqs=[1.0]) mode_power1 = ModePower(name="mode_power1", monitor_name="monitor2", freqs=[1.0]) # Create an expression using the metrics @@ -195,7 +232,7 @@ You should assign names to the variables and provide their values as keyword arg ## Developer notes -### Extending metrics +### Extending expressions To implement new metrics, follow these steps: @@ -204,7 +241,7 @@ To implement new metrics, follow these steps: Create a new class that inherits from `Metric` and implement the required methods. ```python - from tidy3d.plugins.metrics import Metric + from tidy3d.plugins.expressions.metrics import Metric class CustomMetric(Metric): monitor_name: str @@ -225,14 +262,14 @@ To implement new metrics, follow these steps: ### Extending operators -To extend the `metrics` module with additional operators: +To extend the `expressions` module with additional operators: 1. **Create a new operator class:** Subclass `UnaryOperator` or `BinaryOperator` depending on the operator's arity. ```python - from tidy3d.plugins.metrics import BinaryOperator + from tidy3d.plugins.expressions.operators import BinaryOperator class CustomOperator(BinaryOperator): _symbol = "??" # Replace with the operator symbol @@ -262,4 +299,4 @@ To extend the `metrics` module with additional operators: 4. **Register the operator (if necessary):** - Ensure the new operator is recognized by the serialization mechanism. If your operator introduces a new type, update any type maps or registries used in the `metrics` module. + Ensure the new operator is recognized by the serialization mechanism. If your operator introduces a new type, update any type maps or registries used in the `expressions` module. diff --git a/tidy3d/plugins/metrics/__init__.py b/tidy3d/plugins/expressions/__init__.py similarity index 94% rename from tidy3d/plugins/metrics/__init__.py rename to tidy3d/plugins/expressions/__init__.py index 37f78a0ef..00da637eb 100644 --- a/tidy3d/plugins/metrics/__init__.py +++ b/tidy3d/plugins/expressions/__init__.py @@ -1,13 +1,13 @@ from .base import Expression from .functions import Cos, Exp, Log, Log10, Sin, Tan -from .metrics import ModeCoefficient, ModePower +from .metrics import ModeAmp, ModePower from .variables import Constant, Variable __all__ = [ "Expression", "Constant", "Variable", - "ModeCoefficient", + "ModeAmp", "ModePower", "Sin", "Cos", diff --git a/tidy3d/plugins/metrics/base.py b/tidy3d/plugins/expressions/base.py similarity index 100% rename from tidy3d/plugins/metrics/base.py rename to tidy3d/plugins/expressions/base.py diff --git a/tidy3d/plugins/metrics/functions.py b/tidy3d/plugins/expressions/functions.py similarity index 100% rename from tidy3d/plugins/metrics/functions.py rename to tidy3d/plugins/expressions/functions.py diff --git a/tidy3d/plugins/metrics/metrics.py b/tidy3d/plugins/expressions/metrics.py similarity index 95% rename from tidy3d/plugins/metrics/metrics.py rename to tidy3d/plugins/expressions/metrics.py index 2b16d5add..5d0d6109a 100644 --- a/tidy3d/plugins/metrics/metrics.py +++ b/tidy3d/plugins/expressions/metrics.py @@ -23,7 +23,7 @@ def __repr__(self) -> str: return f'{self.type}("{self.monitor_name}")' -class ModeCoefficient(Metric): +class ModeAmp(Metric): """ Metric for calculating the mode coefficient from a ModeMonitor. @@ -41,7 +41,7 @@ class ModeCoefficient(Metric): Examples -------- >>> monitor = ModeMonitor(name="monitor1", freqs=[1.0]) - >>> mode_coeff = ModeCoefficient.from_mode_monitor(monitor) + >>> mode_coeff = ModeAmp.from_mode_monitor(monitor) >>> data = SimulationData() # Assume this is a valid SimulationData object >>> result = mode_coeff.evaluate(data) """ @@ -69,7 +69,7 @@ def evaluate(self, *args: Any, **kwargs: Any) -> NumberType: return anp.squeeze(amps.values.tolist()) -class ModePower(ModeCoefficient): +class ModePower(ModeAmp): """ Metric for calculating the mode power from a ModeMonitor. diff --git a/tidy3d/plugins/metrics/operators.py b/tidy3d/plugins/expressions/operators.py similarity index 100% rename from tidy3d/plugins/metrics/operators.py rename to tidy3d/plugins/expressions/operators.py diff --git a/tidy3d/plugins/metrics/types.py b/tidy3d/plugins/expressions/types.py similarity index 94% rename from tidy3d/plugins/metrics/types.py rename to tidy3d/plugins/expressions/types.py index 659392163..34bee4906 100644 --- a/tidy3d/plugins/metrics/types.py +++ b/tidy3d/plugins/expressions/types.py @@ -6,7 +6,7 @@ if TYPE_CHECKING: from .functions import Cos, Exp, Log, Log10, Sin, Tan - from .metrics import ModeCoefficient, ModePower + from .metrics import ModeAmp, ModePower from .operators import ( Abs, Add, @@ -55,7 +55,7 @@ Union[ "Constant", "Variable", - "ModeCoefficient", + "ModeAmp", "ModePower", ], Field(discriminator=TYPE_TAG_STR), diff --git a/tidy3d/plugins/metrics/variables.py b/tidy3d/plugins/expressions/variables.py similarity index 100% rename from tidy3d/plugins/metrics/variables.py rename to tidy3d/plugins/expressions/variables.py