Skip to content

Commit

Permalink
fix perturbation medium parameter propagation
Browse files Browse the repository at this point in the history
  • Loading branch information
dbochkov-flexcompute committed Jul 28, 2023
1 parent 3a69587 commit b448927
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 68 deletions.
1 change: 1 addition & 0 deletions test_local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pytest -ra tests/test_components/test_medium.py
pytest -ra tests/test_components/test_meshgenerate.py
pytest -ra tests/test_components/test_mode.py
pytest -ra tests/test_components/test_monitor.py
pytest -ra tests/test_components/test_parameter_perturbation.py
pytest -ra tests/test_components/test_field_projection.py
pytest -ra tests/test_components/test_sidewall.py
pytest -ra tests/test_components/test_simulation.py
Expand Down
47 changes: 41 additions & 6 deletions tests/test_components/test_medium.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,33 @@ def test_perturbation_medium():

pmed = td.PerturbationMedium(permittivity=3, permittivity_perturbation=pp_real)

_ = pmed.perturbed_copy()
_ = pmed.perturbed_copy(temperature, electron_density)
_ = pmed.perturbed_copy(temperature, electron_density, hole_density)
cmed = pmed.perturbed_copy()
# regular medium if no perturbations
assert isinstance(cmed, td.Medium)

cmed = pmed.perturbed_copy(temperature, electron_density)
cmed = pmed.perturbed_copy(temperature, electron_density, hole_density)

# correct propagation of parameters
assert cmed.name == pmed.name
assert cmed.frequency_range == pmed.frequency_range
assert cmed.subpixel == pmed.subpixel
assert cmed.allow_gain == pmed.allow_gain

# permittivity < 1
with pytest.raises(pydantic.ValidationError):
_ = pmed.perturbed_copy(2 * temperature)

# conductivity validators
pmed = td.PerturbationMedium(conductivity_perturbation=pp_real, subpixel=False)
cmed = pmed.perturbed_copy(0.9 * temperature) # positive conductivity
assert cmed.subpixel == False
with pytest.raises(pydantic.ValidationError):
_ = pmed.perturbed_copy(1.1 * temperature) # negative conductivity

# negative conductivity but allow gain
pmed = td.PerturbationMedium(conductivity_perturbation=pp_real, allow_gain=True)
_ = pmed.perturbed_copy(1.1 * temperature)

# complex perturbation
with pytest.raises(pydantic.ValidationError):
Expand All @@ -458,11 +482,22 @@ def test_perturbation_medium():
pmed = td.PerturbationPoleResidue(
poles=[(1j, 3), (2j, 4)],
poles_perturbation=[(None, pp_real), (pp_complex, None)],
subpixel=False,
allow_gain=True,
)

_ = pmed.perturbed_copy()
_ = pmed.perturbed_copy(temperature, None, hole_density)
_ = pmed.perturbed_copy(temperature, electron_density, hole_density)
cmed = pmed.perturbed_copy()
# regular medium if no perturbations
assert isinstance(cmed, td.PoleResidue)

cmed = pmed.perturbed_copy(temperature, None, hole_density)
cmed = pmed.perturbed_copy(temperature, electron_density, hole_density)

# correct propagation of parameters
assert cmed.name == pmed.name
assert cmed.frequency_range == pmed.frequency_range
assert cmed.subpixel == pmed.subpixel
assert cmed.allow_gain == pmed.allow_gain

# mismatch between base parameter and perturbations
with pytest.raises(pydantic.ValidationError):
Expand Down
78 changes: 43 additions & 35 deletions tidy3d/components/medium.py
Original file line number Diff line number Diff line change
Expand Up @@ -2934,6 +2934,16 @@ class CustomAnisotropicMediumInternal(CustomAnisotropicMedium):
class AbstractPerturbationMedium(ABC, Tidy3dBaseModel):
"""Abstract class for medium perturbation."""

subpixel: bool = pd.Field(
True,
title="Subpixel averaging",
description="This value will be transferred to the resulting custom medium. That is, "
"if ``True``, the subpixel averaging will be applied to the custom medium provided "
"the corresponding ``Simulation``'s field ``subpixel`` is set to ``True`` as well. "
"If the resulting medium is not a custom medium (no perturbations), this field does not "
"have an effect.",
)

@abstractmethod
def perturbed_copy(
self,
Expand Down Expand Up @@ -2969,16 +2979,16 @@ class PerturbationMedium(Medium, AbstractPerturbationMedium):
-------
>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation
>>> dielectric = PerturbationMedium(
>>> permittivity=4.0,
>>> permittivity_perturbation=ParameterPerturbation(
>>> heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),
>>> ),
>>> name='my_medium'
>>> )
... permittivity=4.0,
... permittivity_perturbation=ParameterPerturbation(
... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),
... ),
... name='my_medium',
... )
"""

permittivity_perturbation: Optional[ParameterPerturbation] = pd.Field(
...,
None,
title="Permittivity Perturbation",
description="List of heat and/or charge perturbations to permittivity.",
units=PERMITTIVITY,
Expand Down Expand Up @@ -3033,12 +3043,13 @@ def perturbed_copy(
Medium specification after application of heat and/or charge data.
"""

new_dict = self.dict(
exclude={"permittivity_perturbation", "conductivity_perturbation", "type"}
)

if all(x is None for x in [temperature, electron_density, hole_density]):
return Medium(
permittivity=self.permittivity,
conductivity=self.conductivity,
name=self.name,
)
new_dict.pop("subpixel")
return Medium.parse_obj(new_dict)

# pylint:disable=protected-access
permittivity_field = self.permittivity + ParameterPerturbation._zeros_like(
Expand All @@ -3056,12 +3067,10 @@ def perturbed_copy(
temperature, electron_density, hole_density
)

return CustomMedium(
permittivity=permittivity_field,
conductivity=conductivity_field,
name=self.name,
subpixel=True,
)
new_dict["permittivity"] = permittivity_field
new_dict["conductivity"] = conductivity_field

return CustomMedium.parse_obj(new_dict)


class PerturbationPoleResidue(PoleResidue, AbstractPerturbationMedium):
Expand All @@ -3080,13 +3089,13 @@ class PerturbationPoleResidue(PoleResidue, AbstractPerturbationMedium):
-------
>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation
>>> c0_perturbation = ParameterPerturbation(
>>> heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),
>>> )
>>> pole_res = PoleResidue(
>>> eps_inf=2.0,
>>> poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],
>>> poles_perturbation=[(None, c0_perturbation), (None, None)],
>>> )
... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),
... )
>>> pole_res = PerturbationPoleResidue(
... eps_inf=2.0,
... poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],
... poles_perturbation=[(None, c0_perturbation), (None, None)],
... )
"""

eps_inf_perturbation: Optional[ParameterPerturbation] = pd.Field(
Expand Down Expand Up @@ -3146,12 +3155,11 @@ def perturbed_copy(
Medium specification after application of heat and/or charge data.
"""

new_dict = self.dict(exclude={"eps_inf_perturbation", "poles_perturbation", "type"})

if all(x is None for x in [temperature, electron_density, hole_density]):
return PoleResidue(
eps_inf=self.eps_inf,
poles=self.poles,
name=self.name,
)
new_dict.pop("subpixel")
return PoleResidue.parse_obj(new_dict)

# pylint:disable=protected-access
zeros = ParameterPerturbation._zeros_like(temperature, electron_density, hole_density)
Expand All @@ -3172,15 +3180,15 @@ def perturbed_copy(
if c_perturb is not None:
c_field += c_perturb.apply_data(temperature, electron_density, hole_density)

return CustomPoleResidue(
eps_inf=eps_inf_field,
poles=poles_field,
name=self.name,
)
new_dict["eps_inf"] = eps_inf_field
new_dict["poles"] = poles_field

return CustomPoleResidue.parse_obj(new_dict)


# types of mediums that can be used in Simulation and Structures


MediumType3D = Union[
Medium,
AnisotropicMedium,
Expand Down
54 changes: 27 additions & 27 deletions tidy3d/components/parameter_perturbation.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,10 @@ class LinearHeatPerturbation(HeatPerturbation):
Example
-------
>>> heat_perturb = LinearHeatPerturbation(
>>> temperature_ref=300,
>>> coeff=0.0001,
>>> temperature_range=[200, 500],
>>> )
... temperature_ref=300,
... coeff=0.0001,
... temperature_range=[200, 500],
... )
"""

temperature_ref: pd.NonNegativeFloat = pd.Field(
Expand Down Expand Up @@ -269,8 +269,8 @@ class CustomHeatPerturbation(HeatPerturbation):
>>> from tidy3d import HeatDataArray
>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))
>>> heat_perturb = CustomHeatPerturbation(
>>> perturbation_values=perturbation_data
>>> )
... perturbation_values=perturbation_data
... )
"""

perturbation_values: HeatDataArray = pd.Field(
Expand Down Expand Up @@ -558,13 +558,13 @@ class LinearChargePerturbation(ChargePerturbation):
Example
-------
>>> charge_perturb = LinearChargePerturbation(
>>> electron_ref=0,
>>> electron_coeff=0.0001,
>>> electron_range=[0, 1e19],
>>> hole_ref=0,
>>> hole_coeff=0.0002,
>>> hole_range=[0, 2e19],
>>> )
... electron_ref=0,
... electron_coeff=0.0001,
... electron_range=[0, 1e19],
... hole_ref=0,
... hole_coeff=0.0002,
... hole_range=[0, 2e19],
... )
"""

electron_ref: pd.NonNegativeFloat = pd.Field(
Expand Down Expand Up @@ -676,12 +676,12 @@ class CustomChargePerturbation(ChargePerturbation):
-------
>>> from tidy3d import ChargeDataArray
>>> perturbation_data = ChargeDataArray(
>>> [[0.001, 0.002, 0.004], [0.003, 0.002, 0.001],
>>> coords=dict(n=[1e16, 1e17, 1e18], p=[2e15, 2e19]),
>>> )
... [[0.001, 0.002, 0.004], [0.003, 0.002, 0.001]],
... coords=dict(n=[2e15, 2e19], p=[1e16, 1e17, 1e18]),
... )
>>> charge_perturb = CustomChargePerturbation(
>>> perturbation_values=perturbation_data
>>> )
... perturbation_values=perturbation_data,
... )
"""

perturbation_values: ChargeDataArray = pd.Field(
Expand Down Expand Up @@ -812,16 +812,16 @@ class ParameterPerturbation(Tidy3dBaseModel):
>>>
>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))
>>> heat_perturb = CustomHeatPerturbation(
>>> perturbation_values=perturbation_data
>>> )
... perturbation_values=perturbation_data
... )
>>> charge_perturb = LinearChargePerturbation(
>>> electron_ref=0,
>>> electron_coeff=0.0001,
>>> electron_range=[0, 1e19],
>>> hole_ref=0,
>>> hole_coeff=0.0002,
>>> hole_range=[0, 2e19],
>>> )
... electron_ref=0,
... electron_coeff=0.0001,
... electron_range=[0, 1e19],
... hole_ref=0,
... hole_coeff=0.0002,
... hole_range=[0, 2e19],
... )
>>> param_perturb = ParameterPerturbation(heat=heat_perturb, charge=charge_perturb)
"""

Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ commands =
pytest -rA tests/test_components/test_meshgenerate.py
pytest -rA tests/test_components/test_mode.py
pytest -rA tests/test_components/test_monitor.py
pytest -rA tests/test_components/test_parameter_perturbation.py
pytest -rA tests/test_components/test_field_projection.py
pytest -rA tests/test_components/test_sidewall.py
pytest -rA tests/test_components/test_simulation.py
Expand Down

0 comments on commit b448927

Please sign in to comment.