Coverage for klayout_pex/pex25d/exporters.py: 69%

35 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-17 19:08 +0000

1# 

2# -------------------------------------------------------------------------------- 

3# SPDX-FileCopyrightText: 2024-2026 Martin Jan Köhler and Harald Pretl 

4# Johannes Kepler University, Institute for Integrated Circuits. 

5# 

6# This file is part of KPEX  

7# (see https://github.com/iic-jku/klayout-pex). 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21# SPDX-License-Identifier: GPL-3.0-or-later 

22# -------------------------------------------------------------------------------- 

23# 

24 

25""" 

26Generation of solver-native input files from a ``PEX25DScene``. 

27 

28The specification calls these solver *adapters*; this module is named after the 

29operation the CLI exposes, ``pex25d export``. 

30 

31Exporting is the one part of this package that is not pure format work: turning 

32a scene into a solver's input needs polygon booleans and meshing, so a backend 

33depends on a geometry library. Backends are therefore imported on use, and a 

34missing dependency is reported rather than surfacing as an ImportError from an 

35unexpected place. Reading, validating, converting and resolving stay 

36dependency-free. 

37""" 

38 

39from __future__ import annotations 

40 

41from dataclasses import dataclass 

42from enum import StrEnum 

43from typing import * 

44 

45 

46class SolverTarget(StrEnum): 

47 """Engines a PEX25D scene can be written out for.""" 

48 

49 FASTERCAP = 'fastercap' 

50 FASTCAP2 = 'fastcap2' 

51 

52 DEFAULT = 'fastercap' 

53 

54 

55class ExportError(RuntimeError): 

56 """The scene could not be written out for the requested target.""" 

57 

58 

59class ExporterUnavailable(ExportError): 

60 """The backend for a target is not importable in this installation.""" 

61 

62 

63@dataclass 

64class ExporterOptions: 

65 """Knobs the CLI exposes for solver input generation.""" 

66 

67 delaunay_amax: float = 0.0 

68 """Maximum triangle area; 0 leaves it to the mesher.""" 

69 

70 delaunay_b: float = 1.0 

71 """Minimum mesh angle as b = 2·sin(angle); 1.0 is 30 degrees.""" 

72 

73 field_margin_um: float = 8.0 

74 """ 

75 How far the laterally unbounded materials — the simple bands, the films that 

76 cover the field, the background, the ground plane — are drawn beyond the 

77 geometry. Ignored when the scene carries a DOMAIN_BOX, which says it 

78 outright. 

79 """ 

80 

81 write_stl: bool = False 

82 """Also dump the generated solids as STL, for looking at.""" 

83 

84 geometry_check: bool = False 

85 """Run the generator's own geometry validation before writing.""" 

86 

87 

88def export(scene: Any, 

89 target: SolverTarget, 

90 output_dir_path: str, 

91 prefix: str = '', 

92 options: Optional[ExporterOptions] = None) -> List[str]: 

93 """ 

94 Export ``scene`` as native input for ``target`` into ``output_dir_path``. 

95 

96 Does not run the engine. 

97 

98 :return: the paths written, most significant first — for FasterCap the 

99 ``.lst`` file, followed by the per-surface files it references. 

100 """ 

101 match target: 

102 case SolverTarget.FASTERCAP | SolverTarget.FASTCAP2: 

103 backend = load_fastercap_backend() 

104 case _: 

105 raise ExportError(f"No exporter for '{target.value}'") 

106 

107 return backend(scene=scene, target=target, output_dir_path=output_dir_path, 

108 prefix=prefix, options=options or ExporterOptions()) 

109 

110 

111def load_fastercap_backend() -> Callable[..., List[str]]: 

112 """ 

113 The FasterCap / FastCap2 backend, which needs KLayout. 

114 

115 Both engines read the same list-file format, so one backend serves them. 

116 """ 

117 try: 

118 from ..fastercap.pex25d_exporter import export_fastercap 

119 except ImportError as e: 

120 raise ExporterUnavailable( 

121 f"The FasterCap exporter needs KLayout, which is not importable here. " 

122 f"Everything else the pex25d tool does works without it.\n" 

123 f"Original error: {e}" 

124 ) from e 

125 return export_fastercap