Coverage for klayout_pex/fastercap/fastercap_runner.py: 70%

57 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-17 17:24 +0000

1# 

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

3# SPDX-FileCopyrightText: 2024 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/martinjankoehler/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# 

24import re 

25import subprocess 

26import time 

27from typing import * 

28 

29from ..log import ( 

30 info, 

31 # warning, 

32 rule, 

33 subproc, 

34) 

35from ..common.capacitance_matrix import CapacitanceMatrix 

36 

37 

38def run_fastercap(exe_path: str, 

39 lst_file_path: str, 

40 log_path: str, 

41 tolerance: float, 

42 d_coeff: float, 

43 mesh_refinement_value: float, 

44 ooc_condition: Optional[int], 

45 auto_preconditioner: bool, 

46 galerkin_scheme: bool, 

47 jacobi_preconditioner: bool): 

48 args = [ 

49 exe_path, 

50 '-b', # console mode, without GUI 

51 '-i', # Dump detailed time and memory information 

52 '-v', # Verbose output 

53 f"-a{tolerance}", # stop when relative error lower than threshold 

54 f"-d{d_coeff}", # Direct potential interaction coefficient to mesh refinement ratio 

55 f"-m{mesh_refinement_value}", # Mesh relative refinement value 

56 ] 

57 

58 if ooc_condition is not None: 

59 args += [f"-f{ooc_condition}"] 

60 

61 if auto_preconditioner: 

62 args += ['-ap'] 

63 

64 if galerkin_scheme: 

65 args += ['-g'] 

66 

67 if jacobi_preconditioner: 

68 args += ['-pj'] 

69 

70 args += [ 

71 lst_file_path 

72 ] 

73 info(f"Calling FasterCap") 

74 subproc(f"{' '.join(args)}, output file: {log_path}") 

75 

76 rule('FasterCap Output') 

77 start = time.time() 

78 

79 proc = subprocess.Popen(args, 

80 stdin=subprocess.DEVNULL, 

81 stdout=subprocess.PIPE, 

82 stderr=subprocess.STDOUT, 

83 universal_newlines=True, 

84 text=True) 

85 with open(log_path, 'w') as f: 

86 while True: 

87 line = proc.stdout.readline() 

88 if not line: 

89 break 

90 subproc(line[:-1]) # remove newline 

91 f.writelines([line]) 

92 proc.wait() 

93 

94 duration = time.time() - start 

95 

96 rule() 

97 

98 if proc.returncode == 0: 

99 info(f"FasterCap succeeded after {'%.4g' % duration}s") 

100 else: 

101 raise Exception(f"FasterCap failed with status code {proc.returncode} after {'%.4g' % duration}s, " 

102 f"see log file: {log_path}") 

103 

104 

105def fastercap_parse_capacitance_matrix(log_path: str) -> CapacitanceMatrix: 

106 with open(log_path, 'r') as f: 

107 rlines = f.readlines() 

108 rlines.reverse() 

109 

110 # multiple iterations possible, find the last matrix 

111 for idx, line in enumerate(rlines): 

112 if line.strip() == "Capacitance matrix is:": 

113 m = re.match(r'^Dimension (\d+) x (\d+)$', rlines[idx-1]) 

114 if not m: 

115 raise Exception(f"Could not parse capacitor matrix dimensions") 

116 dim = int(m.group(1)) 

117 conductor_names: List[str] = [] 

118 rows: List[List[float]] = [] 

119 for i in reversed(range(idx-1-dim, idx-1)): 

120 line = rlines[i].strip() 

121 cells = [cell.strip() for cell in line.split(' ')] 

122 cells = list(filter(lambda c: len(c) >= 1, cells)) 

123 conductor_names.append(cells[0]) 

124 row = [float(cell)/1e6 for cell in cells[1:]] 

125 rows.append(row) 

126 cm = CapacitanceMatrix(conductor_names=conductor_names, rows=rows) 

127 return cm 

128 

129 raise Exception(f"Could not extract capacitance matrix from FasterCap log file {log_path}")