@@ -799,16 +799,16 @@ def test_mode_plane_analyzer_mode_bounds(mode_size, symmetry):
799799 y = td .Boundary (plus = td .PECBoundary (), minus = td .PECBoundary ()),
800800 z = td .Boundary (plus = td .PECBoundary (), minus = td .PECBoundary ()),
801801 )
802- impedance_specs = (td .AutoImpedanceSpec (),) * 4
802+ impedance_specs = (td .AutoImpedanceSpec (),)
803803 mode_spec = td .MicrowaveModeSpec (
804- num_modes = 4 ,
804+ num_modes = 1 ,
805805 target_neff = 1.8 ,
806806 impedance_specs = impedance_specs ,
807807 )
808808
809809 metal_box = td .Structure (
810810 geometry = td .Box .from_bounds (
811- rmin = (0.5 * mm , 0.5 * mm , 0.5 * mm ), rmax = (1 * mm - 1 * dl , 0.5 * mm , 0.5 * mm )
811+ rmin = (- 1 * dl , - 1 * dl , - 0.5 * mm ), rmax = (2 * dl , 2 * dl , 0.5 * mm )
812812 ),
813813 medium = td .PEC ,
814814 )
@@ -830,7 +830,7 @@ def test_mode_plane_analyzer_mode_bounds(mode_size, symmetry):
830830 simulation = sim ,
831831 plane = mode_plane ,
832832 mode_spec = mode_spec ,
833- colocate = True ,
833+ colocate = False ,
834834 freqs = [freq0 ],
835835 )
836836 mode_solver_boundaries = mms ._solver_grid .boundaries .to_list
@@ -1828,3 +1828,105 @@ def test_validate_conductor_voltage_configurations():
18281828 ]
18291829 with pytest .raises (ValueError , match = "Duplicate voltage configuration" ):
18301830 analyzer ._validate_conductor_voltage_configurations (error_polarity_reversed )
1831+
1832+
1833+ def test_terminal_spec_valid_inputs ():
1834+ """Test TerminalSpec validation with valid inputs for plus_terminals and minus_terminals."""
1835+ # Test Case 1.1: Coordinate2D tuples (single coordinate)
1836+ spec = td .TerminalSpec (plus_terminals = ((1.0 , 0.5 ),), minus_terminals = ((- 1.0 , 0.5 ),))
1837+ assert spec is not None
1838+ assert len (spec .plus_terminals ) == 1
1839+ assert spec .plus_terminals [0 ] == (1.0 , 0.5 )
1840+
1841+ # Test Case 1.2: Multiple Coordinate2D tuples
1842+ spec = td .TerminalSpec (plus_terminals = ((1.0 , 0.5 ), (2.0 , 0.5 )), minus_terminals = ())
1843+ assert len (spec .plus_terminals ) == 2
1844+
1845+ # Test Case 1.3: String identifiers
1846+ spec = td .TerminalSpec (
1847+ plus_terminals = ("conductor_1" , "conductor_2" ), minus_terminals = ("ground" ,)
1848+ )
1849+ assert spec .plus_terminals [0 ] == "conductor_1"
1850+ assert spec .minus_terminals [0 ] == "ground"
1851+
1852+ # Test Case 1.4: ArrayFloat2D with 2 points (linestring)
1853+ spec = td .TerminalSpec (plus_terminals = (np .array ([[0.0 , 0.0 ], [1.0 , 1.0 ]]),), minus_terminals = ())
1854+ assert isinstance (spec .plus_terminals [0 ], np .ndarray )
1855+ assert spec .plus_terminals [0 ].shape == (2 , 2 )
1856+
1857+ # Test Case 1.5: ArrayFloat2D with 3+ points (polygon)
1858+ spec = td .TerminalSpec (
1859+ plus_terminals = (np .array ([[0 , 0 ], [1 , 0 ], [1 , 1 ], [0 , 1 ]]),), minus_terminals = ()
1860+ )
1861+ assert isinstance (spec .plus_terminals [0 ], np .ndarray )
1862+ assert spec .plus_terminals [0 ].shape == (4 , 2 )
1863+
1864+ # Test Case 1.6: Lists converted to numpy by ArrayFloat2D
1865+ spec = td .TerminalSpec (plus_terminals = ([[0.0 , 0.0 ], [1.0 , 1.0 ]],), minus_terminals = ())
1866+ # List should be converted to numpy array
1867+ assert isinstance (spec .plus_terminals [0 ], np .ndarray )
1868+ assert spec .plus_terminals [0 ].shape == (2 , 2 )
1869+
1870+ # Test Case 1.7: Mixed types in same spec
1871+ spec = td .TerminalSpec (
1872+ plus_terminals = (
1873+ (1.0 , 0.5 ), # Coordinate2D
1874+ "conductor_2" , # str
1875+ np .array ([[0 , 0 ], [1 , 1 ]]), # ArrayFloat2D
1876+ ),
1877+ minus_terminals = (),
1878+ )
1879+ assert isinstance (spec .plus_terminals [0 ], tuple )
1880+ assert isinstance (spec .plus_terminals [1 ], str )
1881+ assert isinstance (spec .plus_terminals [2 ], np .ndarray )
1882+
1883+ # Test Case 1.8: Empty minus_terminals (valid for common mode)
1884+ spec = td .TerminalSpec (plus_terminals = ((1.0 , 0.5 ),), minus_terminals = ())
1885+ assert len (spec .minus_terminals ) == 0
1886+
1887+ # Test Case 1.9: Exactly 3 points (minimum for polygon - triangle)
1888+ spec = td .TerminalSpec (
1889+ plus_terminals = (np .array ([[0 , 0 ], [1 , 0 ], [0.5 , 1 ]]),), minus_terminals = ()
1890+ )
1891+ assert spec .plus_terminals [0 ].shape == (3 , 2 )
1892+
1893+ # Test Case 1.10: Exactly 2 points
1894+ spec = td .TerminalSpec (plus_terminals = (np .array ([[0.0 , 0.0 ], [1.0 , 0.0 ]]),), minus_terminals = ())
1895+ assert spec .plus_terminals [0 ].shape == (2 , 2 )
1896+
1897+ # Test Case 1.11: 1 point but using ArrayLike
1898+ spec = td .TerminalSpec (plus_terminals = (np .array ([[1.0 , 0.0 ]]),), minus_terminals = ())
1899+ assert spec .plus_terminals [0 ].shape == (1 , 2 )
1900+
1901+
1902+ def test_terminal_spec_invalid_inputs ():
1903+ """Test TerminalSpec validation rejects invalid inputs."""
1904+ # Test Case 2.1: Invalid array shape (not Nx2)
1905+ with pytest .raises (pd .ValidationError ):
1906+ td .TerminalSpec (
1907+ plus_terminals = (np .array ([[0 , 0 , 0 ], [1 , 1 , 1 ]]),), # 3 columns instead of 2
1908+ minus_terminals = (),
1909+ )
1910+
1911+ # Test Case 2.2: Invalid polygon (self-intersecting bowtie)
1912+ with pytest .raises (pd .ValidationError , match = "valid polygon" ):
1913+ td .TerminalSpec (
1914+ plus_terminals = (
1915+ np .array ([[0 , 0 ], [1 , 1 ], [1 , 0 ], [0 , 1 ]]),
1916+ ), # Figure-8 self-intersection
1917+ minus_terminals = (),
1918+ )
1919+
1920+ # Test Case 2.3: 1D array instead of 2D
1921+ with pytest .raises (pd .ValidationError ):
1922+ td .TerminalSpec (
1923+ plus_terminals = (np .array ([0 , 1 , 2 ]),), # 1D array
1924+ minus_terminals = (),
1925+ )
1926+
1927+ # Test Case 2.4: Wrong coordinate tuple length (3 elements instead of 2)
1928+ with pytest .raises (pd .ValidationError ):
1929+ td .TerminalSpec (
1930+ plus_terminals = ((1.0 , 0.5 , 2.0 ),), # 3 elements
1931+ minus_terminals = (),
1932+ )
0 commit comments