Skip to content

Commit 73277db

Browse files
Delegate PEC check from MultiPhysicsMedium to its Optical Medium (#2431)
* fix: delegate is_pec check from MultiPhysicsMedium to its optical medium * set is_pec == False as a default for MultiPhysicsMedium * fix formatting issues * delegate all missing attributes of MultiPhysicsMedium to optical medium instance * generalize function to access inner media attributes * restrict delegation of missing MultiPhysicsMedium attributes * fix typo in error message * fix missing attributes for MultiPhysicsMedium * extend MultiPhysicsMedium test to verify attribute delegation * add proper docstring to MultiPhysicsMedium.__getattr__ method
1 parent cd3b0df commit 73277db

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

tests/test_components/test_scene.py

+17
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@ def test_plot_eps():
5353
plt.close()
5454

5555

56+
def test_plot_eps_multiphysics():
57+
s = td.Scene(
58+
structures=[
59+
td.Structure(
60+
geometry=td.Box(size=(1, 1, 1), center=(-1, 0.5, 0.5)),
61+
medium=td.MultiPhysicsMedium(
62+
optical=td.Medium(permittivity=3.9),
63+
charge=td.ChargeInsulatorMedium(permittivity=3.9),
64+
name="SiO2",
65+
),
66+
)
67+
]
68+
)
69+
assert s.structures[0].medium.name == "SiO2"
70+
s.plot_eps(x=0)
71+
72+
5673
def test_plot_eps_bounds():
5774
_ = SCENE_FULL.plot_eps(x=0, hlim=[-0.45, 0.45])
5875
plt.close()

tidy3d/components/material/multi_physics.py

+47
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,53 @@ class MultiPhysicsMedium(Tidy3dBaseModel):
9898
None, title="Charge properties", description="Specifies properties for Charge simulations."
9999
)
100100

101+
def __getattr__(self, name: str):
102+
"""
103+
Delegate attribute lookup to inner media or fail fast.
104+
105+
Parameters
106+
----------
107+
name : str
108+
The attribute that could not be found on the ``MultiPhysicsMedium`` itself.
109+
110+
Returns
111+
-------
112+
Any
113+
* The attribute value obtained from a delegated sub-medium when
114+
``name`` is listed in ``DELEGATED_ATTRIBUTES``.
115+
* ``None`` when ``name`` is explicitly ignored (e.g. ``"__deepcopy__"``).
116+
117+
Raises
118+
------
119+
ValueError
120+
If ``name`` is neither ignored nor in the delegation map, signalling that
121+
the caller may have intended to access ``optical``, ``heat``, or
122+
``charge`` directly.
123+
124+
Notes
125+
-----
126+
Only the attributes enumerated in the local ``DELEGATED_ATTRIBUTES`` dict are
127+
forwarded.
128+
Extend that mapping as additional cross-medium shim behaviour becomes
129+
necessary.
130+
"""
131+
IGNORED_ATTRIBUTES = ["__deepcopy__"]
132+
if name in IGNORED_ATTRIBUTES:
133+
return None
134+
135+
DELEGATED_ATTRIBUTES = {
136+
"is_pec": self.optical,
137+
"_eps_plot": self.optical,
138+
"viz_spec": self.optical,
139+
}
140+
141+
if name in DELEGATED_ATTRIBUTES:
142+
return getattr(DELEGATED_ATTRIBUTES[name], name)
143+
else:
144+
raise ValueError(
145+
f"MultiPhysicsMedium has no attribute called {name}. Did you mean to access the attribute of one of the optical, heat or charge media?"
146+
)
147+
101148
@property
102149
def heat_spec(self):
103150
if self.heat is not None:

0 commit comments

Comments
 (0)