diff --git a/CHANGELOG.md b/CHANGELOG.md index 392dd9c1be..cb2e8c25db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Mode solver plugin now supports 'EMESimulation'. - `TriangleMesh` class: automatic removal of zero-area faces, and functions `fill_holes` and `fix_winding` to attempt mesh repair. -- Automatic differentiation with `autograd` supports multiple frequencies through single, broadband adjoint simulation when the objective depends on a single port. +- Automatic differentiation with `autograd` supports multiple frequencies through single, broadband adjoint simulation when the objective function can be formulated as depending on a single dataset in the output ``SimulationData`` with frequency dependence only. ### Fixed - Error when loading a previously run `Batch` or `ComponentModeler` containing custom data. diff --git a/tidy3d/components/data/sim_data.py b/tidy3d/components/data/sim_data.py index 03c1c206d7..0ae8103e53 100644 --- a/tidy3d/components/data/sim_data.py +++ b/tidy3d/components/data/sim_data.py @@ -1057,25 +1057,22 @@ def process_adjoint_sources(self, adj_srcs: list[Source]) -> AdjointSourceInfo: # next, figure out which treatment / normalization to apply if num_unique_freqs == 1: - log.info("adjoint source creation: one unique frequency, no normalization") + log.info("Adjoint source creation: one unique frequency, no normalization.") return AdjointSourceInfo(sources=adj_srcs, post_norm=1.0, normalize_sim=True) - # return adj_srcs, 1.0, True if num_ports == 1 and len(adj_srcs) == num_unique_freqs: - log.info("adjoint source creation: one spatial port detected") + log.info("Adjoint source creation: one spatial port detected.") adj_srcs, post_norm = self.process_adjoint_sources_broadband(adj_srcs) return AdjointSourceInfo(sources=adj_srcs, post_norm=post_norm, normalize_sim=True) - # return adj_srcs, post_norm, True # if several spatial ports and several frequencies, try to fit - log.info("adjoint source creation: trying multifrequency fit.") + log.info("Adjoint source creation: trying multifrequency fit.") adj_srcs, post_norm = self.process_adjoint_sources_fit( adj_srcs=adj_srcs, spatial_to_src_times=spatial_to_src_times, json_to_sources=json_to_sources, ) return AdjointSourceInfo(sources=adj_srcs, post_norm=post_norm, normalize_sim=False) - # return adj_srcs, post_norm, False """ SIMPLE APPROACH """ diff --git a/tidy3d/components/source.py b/tidy3d/components/source.py index fbabdd7d98..5a7a245c3e 100644 --- a/tidy3d/components/source.py +++ b/tidy3d/components/source.py @@ -203,14 +203,21 @@ def end_time(self) -> float | None: @property def amp_complex(self) -> complex: - """grab the complex amplitude from a ``SourceTime``.""" - mag = self.amplitude + """Grab the complex amplitude from a ``GaussianPulse``.""" phase = np.exp(1j * self.phase) - return mag * phase + return self.amplitude * phase @classmethod def from_amp_complex(cls, amp: complex, **kwargs) -> GaussianPulse: - """set the complex amplitude of a ``SourceTime``.""" + """Set the complex amplitude of a ``GaussianPulse``. + + Parameters + ---------- + amp : complex + Complex-valued amplitude to set in the returned ``GaussianPulse``. + kwargs : dict + Keyword arguments passed to ``GaussianPulse()``, excluding ``amplitude`` & ``phase``. + """ amplitude = abs(amp) phase = np.angle(amp) return cls(amplitude=amplitude, phase=phase, **kwargs)