Coverage for tests/fastercap/fastercap_test.py: 79%
62 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-17 17:24 +0000
« 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#
24from __future__ import annotations
26import io
27import json
28import tempfile
30import allure
31import csv_diff
32import os
33import pytest
34from typing import *
36import klayout.db as kdb
37import klayout.lay as klay
39from klayout_pex.kpex_cli import KpexCLI
42CSVPath = str
43PNGPath = str
44parent_suite = "kpex/FasterCap Extraction Tests"
45tags = ("PEX", "FasterCap", "Maxwell")
48def _kpex_pdk_dir() -> str:
49 return os.path.realpath(os.path.join(__file__, '..', '..', '..',
50 'pdk', 'sky130A', 'libs.tech', 'kpex'))
53def _sky130a_testdata_dir() -> str:
54 return os.path.realpath(os.path.join(__file__, '..', '..', '..',
55 'testdata', 'designs', 'sky130A'))
58def _gds(*path_components) -> str:
59 return os.path.join(_sky130a_testdata_dir(), *path_components)
62def _save_layout_preview(gds_path: str,
63 output_png_path: str):
64 kdb.Technology.clear_technologies()
65 default_lyt_path = os.path.abspath(f"{_kpex_pdk_dir()}/sky130A.lyt")
66 tech = kdb.Technology.create_technology('sky130A')
67 tech.load(default_lyt_path)
69 lv = klay.LayoutView()
70 lv.load_layout(gds_path)
71 lv.max_hier()
72 lv.set_config('background-color', '#000000')
73 lv.set_config('bitmap-oversampling', '1')
74 lv.set_config('default-font-size', '4')
75 lv.set_config('default-text-size', '0.1')
76 lv.save_image_with_options(
77 output_png_path,
78 width=4096, height=2160
79 # ,
80 # linewidth=2,
81 # resolution=0.25 # 4x as large fonts
82 )
84def _extract_single_cell(*path_components) -> Tuple[CSVPath, PNGPath]:
85 gds_path = _gds(*path_components)
87 preview_png_path = tempfile.mktemp(prefix=f"layout_preview_", suffix=".png")
88 _save_layout_preview(gds_path, preview_png_path)
89 output_dir_path = os.path.realpath(os.path.join(__file__, '..', '..', '..', 'output_sky130A'))
90 cli = KpexCLI()
91 cli.main(['main',
92 '--pdk', 'sky130A',
93 '--gds', gds_path,
94 '--out_dir', output_dir_path,
95 '--fastercap', 'y'])
96 assert cli.fastercap_extracted_csv_path is not None
97 return cli.fastercap_extracted_csv_path, preview_png_path
100def assert_expected_matches_obtained(*path_components,
101 expected_csv_content: str):
102 csv, preview_png = _extract_single_cell(*path_components)
103 allure.attach.file(csv, name='pex_obtained.csv', attachment_type=allure.attachment_type.CSV)
104 allure.attach.file(preview_png, name='📸 layout_preview.png', attachment_type=allure.attachment_type.PNG)
105 expected_csv = csv_diff.load_csv(io.StringIO(expected_csv_content), key='Device')
106 with open(csv, 'r') as f:
107 obtained_csv = csv_diff.load_csv(f, key='Device')
108 diff = csv_diff.compare(expected_csv, obtained_csv, show_unchanged=False)
109 human_diff = csv_diff.human_text(
110 diff, current=obtained_csv, extras=(('Net1','{Net1}'),('Net2','{Net2}'))
111 )
112 allure.attach(expected_csv_content, name='pex_expected.csv', attachment_type=allure.attachment_type.CSV)
113 allure.attach(json.dumps(diff, sort_keys=True, indent=' ').encode("utf8"),
114 name='pex_diff.json', attachment_type=allure.attachment_type.JSON)
115 allure.attach(human_diff.encode("utf8"), name='‼️ pex_diff.txt', attachment_type=allure.attachment_type.TEXT)
116 # assert diff['added'] == []
117 # assert diff['removed'] == []
118 # assert diff['changed'] == []
119 # assert diff['columns_added'] == []
120 # assert diff['columns_removed'] == []
121 assert human_diff == '', 'Diff detected'
124@allure.parent_suite(parent_suite)
125@allure.tag(*tags)
126@pytest.mark.slow
127def test_single_plate_100um_x_100um_li1_over_substrate():
128 #_______________________________ NOTE: with halo=8µm __________________________________
129 # C0 PLATE VSUBS 0.38618p
130 assert_expected_matches_obtained(
131 'test_patterns', 'single_plate_100um_x_100um_li1_over_substrate.gds.gz',
132 expected_csv_content="""Device;Net1;Net2;Capacitance [fF]
133Cext_0_1;VSUBS;PLATE;386.18"""
134 )