1919from tidy3d .components .grid .grid import Coords , Grid
2020from tidy3d .components .medium import Medium , MediumType
2121from tidy3d .components .monitor import (
22+ AstigmaticGaussianOverlapMonitor ,
2223 AuxFieldTimeMonitor ,
2324 DiffractionMonitor ,
2425 DirectivityMonitor ,
3031 FieldTimeMonitor ,
3132 FluxMonitor ,
3233 FluxTimeMonitor ,
34+ GaussianOverlapMonitor ,
3335 MediumMonitor ,
3436 ModeMonitor ,
3537 ModeSolverMonitor ,
@@ -1596,7 +1598,58 @@ class MediumData(MediumDataset, AbstractFieldData):
15961598 )
15971599
15981600
1599- class ModeData (ModeSolverDataset , ElectromagneticFieldData ):
1601+ class AbstractOverlapData (ElectromagneticFieldData ):
1602+ amps : ModeAmpsDataArray = pd .Field (
1603+ ...,
1604+ title = "Amplitudes" ,
1605+ description = "Complex-valued amplitudes of the overlap decomposition." ,
1606+ )
1607+
1608+ def normalize (self , source_spectrum_fn ) -> AbstractOverlapData :
1609+ """Return copy of self after normalization is applied using source spectrum function."""
1610+ if self .amps is None :
1611+ return self .copy ()
1612+ source_freq_amps = source_spectrum_fn (self .amps .f )[None , :, None ]
1613+ new_amps = (self .amps / source_freq_amps ).astype (self .amps .dtype )
1614+ return self .copy (update = {"amps" : new_amps })
1615+
1616+ @property
1617+ def time_reversed_copy (self ) -> FieldData :
1618+ """Make a copy of the data with direction-reversed fields. In lossy or gyrotropic systems,
1619+ the time-reversed fields will not be the same as the backward-propagating modes."""
1620+
1621+ # Time reversal
1622+ new_data = {}
1623+ for comp , field in self .field_components .items ():
1624+ if comp [0 ] == "H" :
1625+ new_data [comp ] = - np .conj (field )
1626+ else :
1627+ new_data [comp ] = np .conj (field )
1628+
1629+ # switch direction in the monitor
1630+ mnt = self .monitor
1631+ new_dir = "+" if mnt .store_fields_direction == "-" else "-"
1632+ update_dict = {"store_fields_direction" : new_dir }
1633+ if hasattr (mnt , "direction" ):
1634+ update_dict ["direction" ] = new_dir
1635+ new_data ["monitor" ] = mnt .updated_copy (** update_dict )
1636+ return self .copy (update = new_data )
1637+
1638+
1639+ class FieldOverlapData (AbstractOverlapData ):
1640+ monitor : Union [GaussianOverlapMonitor , AstigmaticGaussianOverlapMonitor ] = pd .Field (
1641+ ..., title = "Monitor" , description = "Monitor associated with the data."
1642+ )
1643+
1644+ def _make_adjoint_sources (
1645+ self , dataset_names : list [str ], fwidth : float
1646+ ) -> list [Union [CustomCurrentSource , PointDipole ]]:
1647+ """Converts a :class:`.FieldData` to a list of adjoint current or point sources."""
1648+
1649+ raise NotImplementedError ("Could not formulate adjoint source for overlap monitor output." )
1650+
1651+
1652+ class ModeData (ModeSolverDataset , AbstractOverlapData ):
16001653 """
16011654 Data associated with a :class:`.ModeMonitor`: modal amplitudes, propagation indices and mode profiles.
16021655
@@ -1636,11 +1689,7 @@ class ModeData(ModeSolverDataset, ElectromagneticFieldData):
16361689 """
16371690
16381691 monitor : ModeMonitor = pd .Field (
1639- ..., title = "Monitor" , description = "Mode monitor associated with the data."
1640- )
1641-
1642- amps : ModeAmpsDataArray = pd .Field (
1643- ..., title = "Amplitudes" , description = "Complex-valued amplitudes associated with the mode."
1692+ ..., title = "Monitor" , description = "Monitor associated with the data."
16441693 )
16451694
16461695 eps_spec : list [EpsSpecType ] = pd .Field (
@@ -1662,12 +1711,6 @@ def eps_spec_match_mode_spec(cls, val, values):
16621711 )
16631712 return val
16641713
1665- def normalize (self , source_spectrum_fn ) -> ModeData :
1666- """Return copy of self after normalization is applied using source spectrum function."""
1667- source_freq_amps = source_spectrum_fn (self .amps .f )[None , :, None ]
1668- new_amps = (self .amps / source_freq_amps ).astype (self .amps .dtype )
1669- return self .copy (update = {"amps" : new_amps })
1670-
16711714 def overlap_sort (
16721715 self ,
16731716 track_freq : TrackFreq ,
@@ -1965,25 +2008,6 @@ def _group_index_post_process(self, frequency_step: float) -> ModeData:
19652008
19662009 return self .copy (update = update_dict )
19672010
1968- @property
1969- def time_reversed_copy (self ) -> FieldData :
1970- """Make a copy of the data with direction-reversed fields. In lossy or gyrotropic systems,
1971- the time-reversed fields will not be the same as the backward-propagating modes."""
1972-
1973- # Time reversal
1974- new_data = {}
1975- for comp , field in self .field_components .items ():
1976- if comp [0 ] == "H" :
1977- new_data [comp ] = - np .conj (field )
1978- else :
1979- new_data [comp ] = np .conj (field )
1980-
1981- # switch direction in the monitor
1982- mnt = self .monitor
1983- new_dir = "+" if mnt .store_fields_direction == "-" else "-"
1984- new_data ["monitor" ] = mnt .updated_copy (store_fields_direction = new_dir )
1985- return self .copy (update = new_data )
1986-
19872011 def _colocated_propagation_axes_field (self , field_name : Literal ["E" , "H" ]) -> DataArray :
19882012 """Collect a field DataArray containing all 3 field components and rotate from frame
19892013 with normal axis along z to frame with propagation axis along z.
@@ -2262,29 +2286,6 @@ class ModeSolverData(ModeData):
22622286 None , title = "Amplitudes" , description = "Unused for ModeSolverData."
22632287 )
22642288
2265- def normalize (self , source_spectrum_fn : Callable [[float ], complex ]) -> ModeSolverData :
2266- """Return copy of self after normalization is applied using source spectrum function."""
2267- return self .copy ()
2268-
2269- @property
2270- def time_reversed_copy (self ) -> FieldData :
2271- """Make a copy of the data with direction-reversed fields. In lossy or gyrotropic systems,
2272- the time-reversed fields will not be the same as the backward-propagating modes."""
2273-
2274- # Time reversal
2275- new_data = {}
2276- for comp , field in self .field_components .items ():
2277- if comp [0 ] == "H" :
2278- new_data [comp ] = - np .conj (field )
2279- else :
2280- new_data [comp ] = np .conj (field )
2281-
2282- # switch direction in the monitor
2283- mnt = self .monitor
2284- new_dir = "+" if mnt .store_fields_direction == "-" else "-"
2285- new_data ["monitor" ] = mnt .updated_copy (direction = new_dir , store_fields_direction = new_dir )
2286- return self .copy (update = new_data )
2287-
22882289 def _check_fields_stored (self , components : list [str ]):
22892290 """Check that all requested field components are stored in the data."""
22902291 missing_comps = [comp for comp in components if comp not in self .field_components .keys ()]
0 commit comments