|
44 | 44 | from .data.unstructured.tetrahedral import TetrahedralGridDataset
|
45 | 45 | from .data.unstructured.triangular import TriangularGridDataset
|
46 | 46 | from .data.utils import CustomSpatialDataType
|
47 |
| -from .geometry.base import Box, Geometry |
| 47 | +from .geometry.base import Box, ClipOperation, Geometry |
48 | 48 | from .geometry.mesh import TriangleMesh
|
49 | 49 | from .geometry.utils import flatten_groups, traverse_geometries
|
50 | 50 | from .geometry.utils_2d import get_bounds, get_thickened_geom, snap_coordinate_to_grid, subdivide
|
|
62 | 62 | Medium2D,
|
63 | 63 | MediumType,
|
64 | 64 | MediumType3D,
|
| 65 | + PECMedium, |
65 | 66 | )
|
66 | 67 | from .monitor import (
|
67 | 68 | AbstractFieldProjectionMonitor,
|
|
174 | 175 | # additional (safety) time step reduction factor for fixed angle simulations
|
175 | 176 | FIXED_ANGLE_DT_SAFETY_FACTOR = 0.9
|
176 | 177 |
|
| 178 | +# length and thickness of optional PEC frames around mode sources (in cells) |
| 179 | +MODE_PEC_FRAME_LENGTH = 2 |
| 180 | +MODE_PEC_FRAME_THICKNESS = 1e-3 |
| 181 | + |
177 | 182 |
|
178 | 183 | def validate_boundaries_for_zero_dims():
|
179 | 184 | """Error if absorbing boundaries, bloch boundaries, unmatching pec/pmc, or symmetry is used along a zero dimension."""
|
@@ -5209,3 +5214,70 @@ def from_scene(cls, scene: Scene, **kwargs) -> Simulation:
|
5209 | 5214 | )
|
5210 | 5215 |
|
5211 | 5216 | _boundaries_for_zero_dims = validate_boundaries_for_zero_dims()
|
| 5217 | + |
| 5218 | + def _make_pec_frame(self, mode_source) -> Structure: |
| 5219 | + """Make a pec frame around a mode source.""" |
| 5220 | + |
| 5221 | + coords = self.grid.boundaries.to_list |
| 5222 | + axis = mode_source.injection_axis |
| 5223 | + direction = mode_source.direction |
| 5224 | + |
| 5225 | + span_inds = np.array(self.grid.discretize_inds(mode_source)) |
| 5226 | + if direction == "+": |
| 5227 | + span_inds[axis][1] += MODE_PEC_FRAME_LENGTH - 1 |
| 5228 | + else: |
| 5229 | + span_inds[axis][0] -= MODE_PEC_FRAME_LENGTH - 1 |
| 5230 | + bounds_outer = [ |
| 5231 | + [ |
| 5232 | + (1 - MODE_PEC_FRAME_THICKNESS) * c[beg] |
| 5233 | + + MODE_PEC_FRAME_THICKNESS * c[max(0, beg - 1)], |
| 5234 | + (1 - MODE_PEC_FRAME_THICKNESS) * c[end] |
| 5235 | + + MODE_PEC_FRAME_THICKNESS * c[min(len(c) - 1, end + 1)], |
| 5236 | + ] |
| 5237 | + for c, (beg, end) in zip(coords, span_inds) |
| 5238 | + ] |
| 5239 | + bounds_inner = [ |
| 5240 | + [ |
| 5241 | + (1 - MODE_PEC_FRAME_THICKNESS) * c[beg] + MODE_PEC_FRAME_THICKNESS * c[beg + 1], |
| 5242 | + (1 - MODE_PEC_FRAME_THICKNESS) * c[end] + MODE_PEC_FRAME_THICKNESS * c[end - 1], |
| 5243 | + ] |
| 5244 | + for c, (beg, end) in zip(coords, span_inds) |
| 5245 | + ] |
| 5246 | + bounds_inner[axis] = [-inf, inf] |
| 5247 | + structure = Structure( |
| 5248 | + geometry=ClipOperation( |
| 5249 | + geometry_a=Box.from_bounds(*np.transpose(bounds_outer)), |
| 5250 | + geometry_b=Box.from_bounds(*np.transpose(bounds_inner)), |
| 5251 | + operation="difference", |
| 5252 | + ), |
| 5253 | + medium=PECMedium(), |
| 5254 | + ) |
| 5255 | + return structure |
| 5256 | + |
| 5257 | + @cached_property |
| 5258 | + def with_mode_source_pec_frames(self) -> Simulation: |
| 5259 | + """Return an instance with added pec frames around mode sources.""" |
| 5260 | + |
| 5261 | + pec_frames = [ |
| 5262 | + self._make_pec_frame(src) |
| 5263 | + for src in self.sources |
| 5264 | + if isinstance(src, ModeSource) and src.pec_frame |
| 5265 | + ] |
| 5266 | + |
| 5267 | + if len(pec_frames) == 0: |
| 5268 | + return self |
| 5269 | + |
| 5270 | + return self.updated_copy( |
| 5271 | + grid_spec=GridSpec.from_grid(self.grid), structures=list(self.structures) + pec_frames |
| 5272 | + ) |
| 5273 | + |
| 5274 | + def _validate_with_mode_source_pec_frames(self): |
| 5275 | + """Validate that after adding pec frames simulation setup is still valid.""" |
| 5276 | + |
| 5277 | + try: |
| 5278 | + _ = self.with_mode_source_pec_frames |
| 5279 | + except Exception: |
| 5280 | + log.error( |
| 5281 | + "Simulation fails after requested mode source PEC frames are added. " |
| 5282 | + "Please inspec '.with_mode_source_pec_frames'." |
| 5283 | + ) |
0 commit comments