diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ca77b1c9..9e61f8ff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Inaccuracy in transforming gradients from edge to `PolySlab.vertices`. - Bug in `run_async` where an adjoint simulation would sometimes be assigned to the wrong forward simulation. - Validate against nonlinearity or modulation in `FullyAnisotropicMedium.from_diagonal`. +- Add warning to complex-field nonlinearities, which may require more careful physical interpretation. ## [2.7.6] - 2024-10-30 diff --git a/tests/test_components/test_medium.py b/tests/test_components/test_medium.py index 2b54ad76b..1dffefde6 100644 --- a/tests/test_components/test_medium.py +++ b/tests/test_components/test_medium.py @@ -562,15 +562,15 @@ def test_nonlinear_medium(log_capture): ) # complex parameters - med = td.Medium( - nonlinear_spec=td.NonlinearSpec( - models=[ - td.KerrNonlinearity(n2=-1 + 1j, n0=1), - ], - num_iters=20, + with AssertLogLevel(log_capture, "WARNING", contains_str="preferred"): + med = td.Medium( + nonlinear_spec=td.NonlinearSpec( + models=[ + td.KerrNonlinearity(n2=-1 + 1j, n0=1), + ], + num_iters=20, + ) ) - ) - assert_log_level(log_capture, None) # warn about deprecated api med = td.Medium(nonlinear_spec=td.NonlinearSusceptibility(chi3=1.5)) @@ -621,10 +621,11 @@ def test_nonlinear_medium(log_capture): with pytest.raises(ValidationError): med = td.Medium(nonlinear_spec=td.NonlinearSpec(models=[td.KerrNonlinearity(n2=-1j, n0=1)])) - med = td.Medium( - nonlinear_spec=td.NonlinearSpec(models=[td.TwoPhotonAbsorption(beta=-1, n0=1)]), - allow_gain=True, - ) + with AssertLogLevel(log_capture, "WARNING", contains_str="phenomenological"): + med = td.Medium( + nonlinear_spec=td.NonlinearSpec(models=[td.TwoPhotonAbsorption(beta=-1, n0=1)]), + allow_gain=True, + ) # automatic detection of n0 and freq0 n0 = 2 diff --git a/tests/test_plugins/test_adjoint.py b/tests/test_plugins/test_adjoint.py index 8fd01fbb0..795412293 100644 --- a/tests/test_plugins/test_adjoint.py +++ b/tests/test_plugins/test_adjoint.py @@ -1858,7 +1858,7 @@ def test_nonlinear_warn(log_capture): ) # make the nonlinear objects to add to the JaxSimulation one by one - nl_model = td.KerrNonlinearity(n2=1) + nl_model = td.NonlinearSusceptibility(chi3=1) nl_medium = td.Medium(nonlinear_spec=td.NonlinearSpec(models=[nl_model])) struct_static_nl = struct_static.updated_copy(medium=nl_medium) input_struct_nl = JaxStructureStaticMedium(geometry=struct.geometry, medium=nl_medium) diff --git a/tidy3d/components/medium.py b/tidy3d/components/medium.py index 6f25ca46d..4f5e8d760 100644 --- a/tidy3d/components/medium.py +++ b/tidy3d/components/medium.py @@ -442,6 +442,14 @@ def _hardcode_medium_freqs( def _validate_medium(self, medium: AbstractMedium): """Check that the model is compatible with the medium.""" + log.warning( + "Found a medium with a 'TwoPhotonAbsorption' nonlinearity. " + "This uses a phenomenological model based on complex fields, " + "so care should be taken in interpreting the results. For more " + "information on the model, see the documentation at " + "'https://docs.flexcompute.com/projects/tidy3d/en/latest/api/_autosummary/tidy3d.TwoPhotonAbsorption.html' or the following reference: " + "'N. Suzuki, \"FDTD Analysis of Two-Photon Absorption and Free-Carrier Absorption in Si High-Index-Contrast Waveguides,\" J. Light. Technol. 25, 9 (2007).'." + ) # if n0 is specified, we can go ahead and validate passivity if self.n0 is not None: self._validate_medium_freqs(medium, []) @@ -481,7 +489,7 @@ class KerrNonlinearity(NonlinearModel): The fields in this equation are complex-valued, allowing a direct implementation of the Kerr nonlinearity. In contrast, the model :class:`.NonlinearSusceptibility` implements a chi3 nonlinear susceptibility using real-valued fields, giving rise to Kerr nonlinearity - as well as third-harmonic generation. The relationship between the parameters is given by + as well as third-harmonic generation and other effects. The relationship between the parameters is given by :math:`n_2 = \\frac{3}{4} \\frac{1}{\\varepsilon_0 c_0 n_0 \\operatorname{Re}(n_0)} \\chi_3`. The additional factor of :math:`\\frac{3}{4}` comes from the usage of complex-valued fields for the Kerr nonlinearity and real-valued fields for the nonlinear susceptibility. @@ -538,6 +546,13 @@ def _hardcode_medium_freqs( def _validate_medium(self, medium: AbstractMedium): """Check that the model is compatible with the medium.""" + log.warning( + "Found a medium with a 'KerrNonlinearity'. Usually, " + "'NonlinearSusceptibility' is preferred, as it captures " + "additional physical effects by acting on the underlying real fields. " + "The relation between the parameters is " + "'chi3 = (4/3) * eps_0 * c_0 * n0 * Re(n0) * n2'." + ) # if n0 is specified, we can go ahead and validate passivity if self.n0 is not None: self._validate_medium_freqs(medium, [])