-
Notifications
You must be signed in to change notification settings - Fork 50
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
schema-backed postprocess option for invdes
#1828
Closed
+241
−11
Closed
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# defines postprocessing classes for `InverseDesign` objects. | ||
from __future__ import annotations | ||
|
||
import abc | ||
import typing | ||
|
||
import autograd.numpy as anp | ||
import pydantic.v1 as pd | ||
|
||
import tidy3d as td | ||
|
||
from .base import InvdesBaseModel | ||
|
||
PostProcessFnType = typing.Callable[[td.SimulationData], float] | ||
|
||
|
||
class AbstractPostProcessOperation(InvdesBaseModel, abc.ABC): | ||
"""Abstract base class defining components that make up postprocessing classes.""" | ||
|
||
@abc.abstractmethod | ||
def evaluate(self, sim_data: td.SimulationData) -> float: | ||
"""How to evaluate this operation on a ``SimulationData`` object.""" | ||
|
||
|
||
class CustomPostProcessOperation(AbstractPostProcessOperation): | ||
"""A postprocessing operation to subclass and implement ones own ``evalute`` method for.""" | ||
|
||
def evaluate(self, sim_data: td.SimulationData) -> float: | ||
"""How to evaluate this operation on a ``SimulationData`` object.""" | ||
raise NotImplementedError("Must define the 'self.evaluate(sim_data) -> float' method.") | ||
|
||
@classmethod | ||
def from_function(cls, fn: PostProcessFnType, **kwargs) -> CustomPostProcessOperation: | ||
"""Create a ``CustomPostProcessOperation`` from a function of ``SimulationData``.""" | ||
cls.evaluate = lambda self, sim_data: fn(sim_data) | ||
obj = cls(**kwargs) | ||
return obj | ||
|
||
|
||
class ElementaryPostProcessOperation(AbstractPostProcessOperation, abc.ABC): | ||
"""A postprocess operation that can work on its own.""" | ||
|
||
|
||
class ModePower(ElementaryPostProcessOperation): | ||
"""Grab the power from a ``ModeMonitor`` and apply an optional weight.""" | ||
|
||
monitor_name: str = pd.Field( | ||
..., | ||
title="Monitor Name", | ||
description="Name of the ``ModeMonitor`` corresponding to the ``ModeData`` " | ||
"that we want to compute power for.", | ||
) | ||
|
||
direction: td.components.types.Direction = pd.Field( | ||
None, | ||
title="Direction", | ||
description="If specified, selects a specific direction ``'-'`` or ``'+'`` from the " | ||
"``ModeData`` to include in power. Otherwise, sums over all directions.", | ||
) | ||
|
||
mode_index: pd.NonNegativeInt = pd.Field( | ||
None, | ||
title="Mode Index", | ||
description="If specified, selects a specific mode index from the ``ModeData`` " | ||
"to include in power. Otherwise, sums over all mode indices.", | ||
) | ||
|
||
f: float = pd.Field( | ||
None, | ||
title="Frequency", | ||
description="If specified, selects a specific frequency from the ``ModeData`` " | ||
"to include in power. Otherwise, sums over all frequencies.", | ||
) | ||
|
||
weight: float = pd.Field( | ||
1.0, | ||
title="Weight", | ||
description="Weight specifying the contribution of this power to the objective function. ", | ||
) | ||
|
||
@property | ||
def sel_kwargs(self) -> dict[str, typing.Any]: | ||
"""Selection kwargs corresponding to the fields.""" | ||
sel_kwargs_all = dict(direction=self.direction, mode_index=self.mode_index, f=self.f) | ||
return {key: sel for key, sel in sel_kwargs_all.items() if sel is not None} | ||
|
||
def evaluate(self, sim_data: td.SimulationData) -> float: | ||
"""Evaluate this instance when passed a simulation dataset.""" | ||
|
||
if self.monitor_name not in sim_data: | ||
raise KeyError(f"No data found for monitor with name '{self.monitor_name}'.") | ||
|
||
mnt_data = sim_data[self.monitor_name] | ||
tylerflex marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if not isinstance(mnt_data, td.ModeData): | ||
raise ValueError( | ||
"'ModePower' only works with 'ModeData' corresponding to 'ModeMonitor'. " | ||
f"Monitor name of '{self.monitor_name}' returned data of type {type(mnt_data)}." | ||
) | ||
|
||
amps = mnt_data.amps | ||
amp = amps.sel(**self.sel_kwargs) | ||
powers = abs(amp.values) ** 2 | ||
power = anp.sum(powers) | ||
return self.weight * power | ||
|
||
|
||
ElementaryPostProcessOperationType = typing.Union[ModePower] | ||
|
||
|
||
class CombinedPostProcessOperation(AbstractPostProcessOperation, abc.ABC): | ||
"""A postprocess operation that combines elementary operations.""" | ||
|
||
operations: tuple[ElementaryPostProcessOperationType, ...] = pd.Field( | ||
(), | ||
title="PostProcessing Operations", | ||
description="Set of objects specifying the operations combined in this operation.", | ||
) | ||
|
||
|
||
class Sum(CombinedPostProcessOperation): | ||
"""Sum of the evaluate outputs of elementary operation objects.""" | ||
|
||
def evaluate(self, sim_data: td.SimulationData) -> float: | ||
"""sum the evaluation of each operation.""" | ||
|
||
return sum(op.evaluate(sim_data) for op in self.operations) | ||
|
||
|
||
PostProcessOperationType = typing.Union[CustomPostProcessOperation, ModePower, Sum] |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering whether
terms
would be more intuitive instead ofoperations
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the classes are also called
Operations
so it kind of makes sense. But yea I wonder if there's an even better name for these?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
terms
sounds a bit strange to me.. it's more likeelementary_operations
but that's too verbose.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah don't know,
terms
only really makes sense in the context ofSum
probably. Maybe it's fine as-is..