From 725b5f97a3c38bc94b5cc7538a0d108d2b97df15 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Fri, 14 Oct 2022 20:13:47 -0700 Subject: [PATCH 1/3] Add support for load_minus_flux to objective functions of adjoint solver --- python/adjoint/objective.py | 28 +++++++++++++++++++++++++++- python/tests/test_adjoint_solver.py | 24 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/python/adjoint/objective.py b/python/adjoint/objective.py index 6a9a4fb65..cdf1a46f7 100644 --- a/python/adjoint/objective.py +++ b/python/adjoint/objective.py @@ -4,7 +4,7 @@ from typing import Callable, List, Optional import numpy as np -from meep.simulation import py_v3_to_vec +from meep.simulation import py_v3_to_vec, FluxData, NearToFarData import meep as mp @@ -158,6 +158,11 @@ class EigenmodeCoefficient(ObjectiveQuantity): kpoint_func_overlap_idx: the index of the mode coefficient to return when specifying `kpoint_func`. When specified, this overrides the effect of `forward` and should have a value of either 0 or 1. + norm_dft_fields: the DFT fields obtained using `get_flux_data` from a + previous normalization run. This is subtracted from the DFT fields + of this mode monitor in order to improve the accuracy of the + reflectance calculation (i.e., the $S_{11}$ scattering parameter). + Default is None. """ def __init__( @@ -169,6 +174,7 @@ def __init__( kpoint_func: Optional[Callable] = None, kpoint_func_overlap_idx: Optional[int] = 0, decimation_factor: Optional[int] = 0, + norm_dft_fields: Optional[FluxData] = None, **kwargs ): """ @@ -189,6 +195,7 @@ def __init__( self._monitor = None self._cscale = None self.decimation_factor = decimation_factor + self.norm_dft_fields = norm_dft_fields def register_monitors(self, frequencies): self._frequencies = np.asarray(frequencies) @@ -198,6 +205,11 @@ def register_monitors(self, frequencies): yee_grid=True, decimation_factor=self.decimation_factor, ) + if self.norm_dft_fields is not None: + self.sim.load_minus_flux_data( + self._monitor, + self.norm_dft_fields, + ) return self._monitor def place_adjoint_source(self, dJ): @@ -279,6 +291,7 @@ def __init__( component: List[int], yee_grid: Optional[bool] = False, decimation_factor: Optional[int] = 0, + norm_dft_fields: Optional[FluxData] = None, ): """ """ super().__init__(sim) @@ -286,6 +299,7 @@ def __init__( self.component = component self.yee_grid = yee_grid self.decimation_factor = decimation_factor + self.norm_dft_fields = norm_dft_fields def register_monitors(self, frequencies): self._frequencies = np.asarray(frequencies) @@ -296,6 +310,11 @@ def register_monitors(self, frequencies): yee_grid=self.yee_grid, decimation_factor=self.decimation_factor, ) + if self.norm_dft_fields is not None: + self.sim.load_minus_flux_data( + self._monitor, + self.norm_dft_fields, + ) return self._monitor def place_adjoint_source(self, dJ): @@ -372,6 +391,7 @@ def __init__( Near2FarRegions: List[mp.Near2FarRegion], far_pts: List[mp.Vector3], decimation_factor: Optional[int] = 0, + norm_near_fields: Optional[NearToFarData] = None, ): """ """ super().__init__(sim) @@ -379,6 +399,7 @@ def __init__( self.far_pts = far_pts # list of far pts self._nfar_pts = len(far_pts) self.decimation_factor = decimation_factor + self.norm_near_fields = norm_near_fields def register_monitors(self, frequencies): self._frequencies = np.asarray(frequencies) @@ -387,6 +408,11 @@ def register_monitors(self, frequencies): *self.Near2FarRegions, decimation_factor=self.decimation_factor, ) + if norm_near_fields is not None: + self.sim.load_minus_near2far_data( + self._monitor, + self.norm_near_fields, + ) return self._monitor def place_adjoint_source(self, dJ): diff --git a/python/tests/test_adjoint_solver.py b/python/tests/test_adjoint_solver.py index 4b64f5fab..c3d73bbf3 100644 --- a/python/tests/test_adjoint_solver.py +++ b/python/tests/test_adjoint_solver.py @@ -137,6 +137,29 @@ def adjoint_solver( if mon_type.name == "EIGENMODE": if len(frequencies) == 1: + if mat2 is None: + # compute the incident fields of the source + # in just the straight waveguide + ref_sim = mp.Simulation( + resolution=self.resolution, + cell_size=self.cell_size, + boundary_layers=self.pml_xy, + sources=self.mode_source, + geometry=self.waveguide_geometry, + ) + dft_mon = ref_sim.add_mode_monitor( + frequencies, + mp.ModeRegion( + center=mp.Vector3(-0.5 * self.sxy + self.dpml), + size=mp.Vector3(0, self.sxy - 2 * self.dpml, 0), + ), + yee_grid=True, + ) + ref_sim.run(until_after_sources=20) + norm_dft_fields = ref_sim.get_flux_data(dft_mon) + else: + norm_dft_fields = None + obj_list = [ mpa.EigenmodeCoefficient( sim, @@ -147,6 +170,7 @@ def adjoint_solver( 1, forward=False, eig_parity=self.eig_parity, + norm_dft_fields=norm_dft_fields, ), mpa.EigenmodeCoefficient( sim, From af1fb531b1296370c5115a5497e0e04af3f19c8b Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Fri, 14 Oct 2022 21:01:13 -0700 Subject: [PATCH 2/3] bug fix in Near2FarFields class --- python/adjoint/objective.py | 2 +- python/tests/test_adjoint_solver.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/python/adjoint/objective.py b/python/adjoint/objective.py index cdf1a46f7..e1e015de8 100644 --- a/python/adjoint/objective.py +++ b/python/adjoint/objective.py @@ -408,7 +408,7 @@ def register_monitors(self, frequencies): *self.Near2FarRegions, decimation_factor=self.decimation_factor, ) - if norm_near_fields is not None: + if self.norm_near_fields is not None: self.sim.load_minus_near2far_data( self._monitor, self.norm_near_fields, diff --git a/python/tests/test_adjoint_solver.py b/python/tests/test_adjoint_solver.py index c3d73bbf3..d2893c49f 100644 --- a/python/tests/test_adjoint_solver.py +++ b/python/tests/test_adjoint_solver.py @@ -138,8 +138,9 @@ def adjoint_solver( if mon_type.name == "EIGENMODE": if len(frequencies) == 1: if mat2 is None: - # compute the incident fields of the source - # in just the straight waveguide + # compute the incident fields of the mode source + # in just the straight waveguide for normalization + # of the reflectance (S11) measurement ref_sim = mp.Simulation( resolution=self.resolution, cell_size=self.cell_size, From 009562499bbcb263a72bc0aa560ab51eca24105e Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Tue, 18 Oct 2022 16:47:11 +0000 Subject: [PATCH 3/3] rename norm_dft_fields to subtracted_dft_fields --- python/adjoint/objective.py | 22 +++++++++++----------- python/tests/test_adjoint_solver.py | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/python/adjoint/objective.py b/python/adjoint/objective.py index e1e015de8..ef6998b86 100644 --- a/python/adjoint/objective.py +++ b/python/adjoint/objective.py @@ -158,10 +158,10 @@ class EigenmodeCoefficient(ObjectiveQuantity): kpoint_func_overlap_idx: the index of the mode coefficient to return when specifying `kpoint_func`. When specified, this overrides the effect of `forward` and should have a value of either 0 or 1. - norm_dft_fields: the DFT fields obtained using `get_flux_data` from a - previous normalization run. This is subtracted from the DFT fields + subtracted_dft_fields: the DFT fields obtained using `get_flux_data` from + a previous normalization run. This is subtracted from the DFT fields of this mode monitor in order to improve the accuracy of the - reflectance calculation (i.e., the $S_{11}$ scattering parameter). + reflectance measurement (i.e., the $S_{11}$ scattering parameter). Default is None. """ @@ -174,7 +174,7 @@ def __init__( kpoint_func: Optional[Callable] = None, kpoint_func_overlap_idx: Optional[int] = 0, decimation_factor: Optional[int] = 0, - norm_dft_fields: Optional[FluxData] = None, + subtracted_dft_fields: Optional[FluxData] = None, **kwargs ): """ @@ -195,7 +195,7 @@ def __init__( self._monitor = None self._cscale = None self.decimation_factor = decimation_factor - self.norm_dft_fields = norm_dft_fields + self.subtracted_dft_fields = subtracted_dft_fields def register_monitors(self, frequencies): self._frequencies = np.asarray(frequencies) @@ -205,10 +205,10 @@ def register_monitors(self, frequencies): yee_grid=True, decimation_factor=self.decimation_factor, ) - if self.norm_dft_fields is not None: + if self.subtracted_dft_fields is not None: self.sim.load_minus_flux_data( self._monitor, - self.norm_dft_fields, + self.subtracted_dft_fields, ) return self._monitor @@ -291,7 +291,7 @@ def __init__( component: List[int], yee_grid: Optional[bool] = False, decimation_factor: Optional[int] = 0, - norm_dft_fields: Optional[FluxData] = None, + subtracted_dft_fields: Optional[FluxData] = None, ): """ """ super().__init__(sim) @@ -299,7 +299,7 @@ def __init__( self.component = component self.yee_grid = yee_grid self.decimation_factor = decimation_factor - self.norm_dft_fields = norm_dft_fields + self.subtracted_dft_fields = subtracted_dft_fields def register_monitors(self, frequencies): self._frequencies = np.asarray(frequencies) @@ -310,10 +310,10 @@ def register_monitors(self, frequencies): yee_grid=self.yee_grid, decimation_factor=self.decimation_factor, ) - if self.norm_dft_fields is not None: + if self.subtracted_dft_fields is not None: self.sim.load_minus_flux_data( self._monitor, - self.norm_dft_fields, + self.subtracted_dft_fields, ) return self._monitor diff --git a/python/tests/test_adjoint_solver.py b/python/tests/test_adjoint_solver.py index d2893c49f..03c0839fe 100644 --- a/python/tests/test_adjoint_solver.py +++ b/python/tests/test_adjoint_solver.py @@ -138,9 +138,9 @@ def adjoint_solver( if mon_type.name == "EIGENMODE": if len(frequencies) == 1: if mat2 is None: - # compute the incident fields of the mode source - # in just the straight waveguide for normalization - # of the reflectance (S11) measurement + # Compute the incident fields of the mode source + # in the straight waveguide for use as normalization + # of the reflectance (S11) measurement. ref_sim = mp.Simulation( resolution=self.resolution, cell_size=self.cell_size, @@ -157,9 +157,9 @@ def adjoint_solver( yee_grid=True, ) ref_sim.run(until_after_sources=20) - norm_dft_fields = ref_sim.get_flux_data(dft_mon) + subtracted_dft_fields = ref_sim.get_flux_data(dft_mon) else: - norm_dft_fields = None + subtracted_dft_fields = None obj_list = [ mpa.EigenmodeCoefficient( @@ -171,7 +171,7 @@ def adjoint_solver( 1, forward=False, eig_parity=self.eig_parity, - norm_dft_fields=norm_dft_fields, + subtracted_dft_fields=subtracted_dft_fields, ), mpa.EigenmodeCoefficient( sim,