Coverage for klayout_pex/rcx25/c/device_capacitor_plates.py: 100%

21 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-02 23:32 +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# 

24from __future__ import annotations 

25 

26from dataclasses import dataclass, field 

27from typing import * 

28 

29import klayout.db as kdb 

30 

31from klayout_pex.klayout.lvsdb_extractor import DEVICE_CAPACITOR_PLATE_PROPERTY 

32from klayout_pex.rcx25.types import NetName 

33 

34Shape = Union[kdb.PolygonWithProperties, kdb.EdgeWithProperties] 

35 

36 

37@dataclass 

38class DeviceCapacitorPlates: 

39 """ 

40 The plates of the black-boxed capacitor devices, whose models have the capacitances between them 

41 (the shapes of KIND_DEVICE_CAPACITOR_PLATE, e.g. the fingers of a MOM cap), 

42 but not their capacitances to other nets (e.g. the substrate, a wire across), which are extracted. 

43 

44 NOTE: a pair of plates is of a device if its nets are the terminal nets of a device, 

45 and not e.g. a wire of another net across the device, which is on its plate layers too 

46 """ 

47 

48 # the nets of the terminals of each device 

49 terminal_net_pairs: Set[FrozenSet[NetName]] = field(default_factory=set) 

50 

51 @classmethod 

52 def from_circuit(cls, 

53 circuit: kdb.Circuit, 

54 device_class_names: Set[str]) -> DeviceCapacitorPlates: 

55 """ 

56 :param device_class_names: the device classes of the capacitors (e.g. the metal capacitors) 

57 """ 

58 terminal_net_pairs: Set[FrozenSet[NetName]] = set() 

59 for d in circuit.each_device(): 

60 if d.device_class().name not in device_class_names: 

61 continue 

62 net_names = sorted({net.expanded_name() 

63 for td in d.device_class().terminal_definitions() 

64 if (net := d.net_for_terminal(td.id())) is not None}) 

65 terminal_net_pairs.update(frozenset((n1, n2)) 

66 for idx, n1 in enumerate(net_names) for n2 in net_names[idx + 1:]) 

67 return DeviceCapacitorPlates(terminal_net_pairs=terminal_net_pairs) 

68 

69 def are_plates_of_a_device(self, shape1: Shape, net1: NetName, shape2: Shape, net2: NetName) -> bool: 

70 """ 

71 :return: whether the shapes are plates of a device between their nets, 

72 whose model has the capacitance between them 

73 """ 

74 return bool(shape1.property(DEVICE_CAPACITOR_PLATE_PROPERTY)) and \ 

75 bool(shape2.property(DEVICE_CAPACITOR_PLATE_PROPERTY)) and \ 

76 frozenset((net1, net2)) in self.terminal_net_pairs