66
77from functools import wraps
88from math import isclose
9- from typing import Literal , Optional , Union
9+ from typing import Literal , Optional , Union , get_args
1010
1111import numpy as np
1212import pydantic .v1 as pydantic
@@ -218,14 +218,17 @@ def _post_init_validators(self) -> None:
218218 mode_spec = self .mode_spec ,
219219 plane = self .plane ,
220220 sim_geom = self .simulation .geometry ,
221- msg_prefix = "Mode solver" ,
222221 )
223222 self ._warn_thick_pml (simulation = self .simulation , plane = self .plane , mode_spec = self .mode_spec )
224223 self ._validate_rotate_structures ()
225224
226225 @classmethod
227226 def _warn_thick_pml (
228- cls , simulation : Simulation , plane : Box , mode_spec : ModeSpec , warn_str : str = "'ModeSolver'"
227+ cls ,
228+ simulation : Simulation ,
229+ plane : Box ,
230+ mode_spec : ModeSpec ,
231+ msg_prefix : str = "'ModeSolver'" ,
229232 ):
230233 """Warn if the pml covers a significant portion of the mode plane."""
231234 coord_0 , coord_1 = cls ._plane_grid (
@@ -239,7 +242,7 @@ def _warn_thick_pml(
239242 for i in (0 , 1 ):
240243 if 2 * effective_num_pml [i ] > (WARN_THICK_PML_PERCENT / 100 ) * num_cells [i ]:
241244 log .warning (
242- f"{ warn_str } : "
245+ f"{ msg_prefix } : "
243246 f"The mode solver pml in tangential axis '{ i } ' "
244247 f"covers more than '{ WARN_THICK_PML_PERCENT } %' of the "
245248 "mode plane cells. Consider using a larger mode plane "
@@ -254,9 +257,7 @@ def _mode_plane(plane: Box, sim_geom: Box) -> Box:
254257 return Box .from_bounds (* mode_plane_bnds )
255258
256259 @classmethod
257- def _validate_mode_plane_radius (
258- cls , mode_spec : ModeSpec , plane : Box , sim_geom : Box , msg_prefix : str = ""
259- ):
260+ def _validate_mode_plane_radius (cls , mode_spec : ModeSpec , plane : Box , sim_geom : Box ):
260261 """Validate that the radius of a mode spec with a bend is not smaller than half the size of
261262 the plane along the radial direction."""
262263
@@ -271,21 +272,14 @@ def _validate_mode_plane_radius(
271272
272273 if np .abs (mode_spec .bend_radius ) < mode_plane .size [radial_ax ] / 2 :
273274 raise ValueError (
274- f" { msg_prefix } bend radius is smaller than half the mode plane size "
275+ "Mode solver bend radius is smaller than half the mode plane size "
275276 "along the radial axis, which can produce wrong results."
276277 )
277278
278279 def _validate_rotate_structures (self ) -> None :
279280 """Validate that structures can be rotated if angle_rotation is True."""
280- if not self .mode_spec .angle_rotation :
281- return
282- try :
281+ if np .abs (self .mode_spec .angle_theta ) > 0 and self .mode_spec .angle_rotation :
283282 _ = self ._rotate_structures
284- except Exception as e :
285- raise SetupError (
286- "Mode object defined with 'angle_rotation=True' but failed "
287- f"to create rotated structures: { e !s} "
288- ) from e
289283
290284 @cached_property
291285 def normal_axis (self ) -> Axis :
@@ -628,28 +622,41 @@ def _rotate_structures(self) -> list[Structure]:
628622 translate_coords = [0 , 0 , 0 ]
629623 translate_coords [idx_u ] = mnt_center [idx_u ]
630624 translate_coords [idx_v ] = mnt_center [idx_v ]
625+ translate_kwargs = dict (zip ("xyz" , translate_coords ))
626+ # Rotation arguments
627+ rotate_kwargs = {"angle" : theta , "axis" : self .bend_axis_3d }
631628
632- rotated_structures = []
633- for structure in Scene .intersecting_structures (self .plane , self .simulation .structures ):
634- if not isinstance (structure .medium , IsotropicUniformMediumType ):
635- raise NotImplementedError (
636- "Mode solver plane intersects an unsupported "
637- "medium. Only uniform isotropic media are supported for the plane rotation. "
638- )
629+ structs_in = Scene .intersecting_structures (self .plane , self .simulation .structures )
630+ return self ._make_rotated_structures (structs_in , translate_kwargs , rotate_kwargs )
631+
632+ @staticmethod
633+ def _make_rotated_structures (
634+ structures : list [Structure ], translate_kwargs : dict , rotate_kwargs : dict
635+ ):
636+ try :
637+ rotated_structures = []
638+ for structure in structures :
639+ if not isinstance (structure .medium , get_args (IsotropicUniformMediumType )):
640+ raise NotImplementedError (
641+ "Mode solver plane intersects an unsupported medium. "
642+ "Only uniform isotropic media are supported for the plane rotation."
643+ )
639644
640- # Rotate and apply translations
641- geometry = structure .geometry
642- geometry = (
643- geometry .translated (
644- x = - translate_coords [0 ], y = - translate_coords [1 ], z = - translate_coords [2 ]
645+ # Rotate and apply translations
646+ geometry = structure .geometry
647+ geometry = (
648+ geometry .translated (** {key : - val for key , val in translate_kwargs .items ()})
649+ .rotated (** rotate_kwargs )
650+ .translated (** translate_kwargs )
645651 )
646- .rotated (theta , axis = self .bend_axis_3d )
647- .translated (x = translate_coords [0 ], y = translate_coords [1 ], z = translate_coords [2 ])
648- )
649652
650- rotated_structures .append (structure .updated_copy (geometry = geometry ))
653+ rotated_structures .append (structure .updated_copy (geometry = geometry ))
651654
652- return rotated_structures
655+ return rotated_structures
656+ except Exception as e :
657+ raise SetupError (
658+ f"'angle_rotation' set to True but could not rotate structures: { e !s} "
659+ ) from e
653660
654661 @cached_property
655662 def rotated_bend_center (self ) -> list :
0 commit comments