├── cds ├── __init__.py ├── test │ └── test_adexl.py └── adexl.py ├── setup.sh ├── README.md └── notebooks └── adexl class demo.ipynb /cds/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | export PYTHONPATH=$PYTHONPATH:`pwd` 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pycds 2 | ===== 3 | 4 | Python interface to Cadence Virtuoso data 5 | -------------------------------------------------------------------------------- /cds/test/test_adexl.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from cds.adexl import ADE_XL_Result 4 | 5 | def test_adexl(): 6 | r = ADE_XL_Result(os.path.join(os.path.dirname(__file__), 'data', 'adexl')) 7 | print r 8 | 9 | 10 | -------------------------------------------------------------------------------- /cds/adexl.py: -------------------------------------------------------------------------------- 1 | from lxml import etree 2 | import os 3 | import sqlite3 4 | import pandas.io.sql 5 | 6 | import util 7 | 8 | class ADE_XL_Result(object): 9 | def __init__(self, directory): 10 | self.directory = directory 11 | 12 | self.setupdb = self.xmldata() 13 | 14 | self._load_tests() 15 | self._load_history() 16 | 17 | def check(self): 18 | ## FIXME, check consistency 19 | return True 20 | 21 | def xmldata(self): 22 | """Return ADE-XL XML data etree""" 23 | datafile = os.path.join(self.directory, "data.sdb") 24 | return etree.parse(datafile) 25 | 26 | def expand_path(self, path): 27 | """Expand paths relative to result directory""" 28 | return path.replace('$AXL_SETUPDB_DIR', self.directory) 29 | 30 | def get_history_entry_names(self): 31 | return [he.name for he in self.history] 32 | 33 | def get_history_entry(self, name): 34 | for h_entry in self.history: 35 | if h_entry.name == name: 36 | return h_entry 37 | 38 | def _load_tests(self): 39 | self.tests = [ADE_XL_Test(elem) 40 | for elem in self.setupdb.findall('active/tests/test')] 41 | 42 | def _load_history(self): 43 | self.history = [ADE_XL_HistoryEntry(elem) 44 | for elem in self.setupdb.findall('history/historyentry')] 45 | 46 | class ADE_XL_Test(object): 47 | def __init__(self, elem): 48 | self.elem = elem 49 | 50 | self.name = elem.text.strip() 51 | 52 | self._load_tooloptions() 53 | self._load_outputs() 54 | 55 | def _load_outputs(self): 56 | self.outputs = [ADE_XL_TestOutput(elem.text.strip()) 57 | for elem in self.elem.findall('outputs/output')] 58 | 59 | def _load_tooloptions(self): 60 | ## Load tool options 61 | tooloptions = {} 62 | for tooloption in self.elem.findall('tooloptions/option'): 63 | value = tooloption.find('./value') 64 | tooloptions[tooloption.text.strip()] = value.text.strip() 65 | 66 | self.tooloptions = tooloptions 67 | 68 | def get_state_dir(self, result): 69 | return os.path.join(*([result.expand_path(self.tooloptions['path']), 70 | self.cellview[0], 71 | self.cellview[1], 72 | self.simulator, 73 | self.tooloptions['state'] 74 | ])) 75 | 76 | def get_state_file(self, filename, result): 77 | with open(os.path.join(self.get_state_dir(result), filename)) as f: 78 | return f.read() 79 | 80 | @property 81 | def cellview(self): 82 | return [self.tooloptions['lib'], 83 | self.tooloptions['cell'], 84 | self.tooloptions['view']] 85 | 86 | @property 87 | def simulator(self): 88 | return self.tooloptions['sim'] 89 | 90 | class ADE_XL_TestOutput(object): 91 | def __init__(self, name): 92 | self.name = name 93 | 94 | class ADE_XL_HistoryEntry(object): 95 | def __init__(self, elem): 96 | self.elem = elem 97 | 98 | self._load_history_entry() 99 | 100 | def _load_history_entry(self): 101 | self.name = self.elem.text.strip() 102 | self.simresults = self.elem.find('./simresults').text.strip() 103 | 104 | def get_result_db(self, result): 105 | if self.simresults: 106 | sqlitedbfile = result.expand_path(self.simresults) 107 | return ADE_XL_ResultDatabase(sqlitedbfile) 108 | 109 | class ADE_XL_ResultDatabase(object): 110 | def __init__(self, dbfile): 111 | self.conn = sqlite3.connect(dbfile) 112 | 113 | def get_results(self, **results): 114 | """Get selected results as pandas dataframe""" 115 | 116 | query = """SELECT 117 | test.name as testname, resultValue.pointID, 118 | result.name as resultname, resultValue.value 119 | FROM 120 | resultValue 121 | INNER JOIN 122 | result ON result.resultID = resultValue.resultID 123 | INNER JOIN 124 | point ON point.pointID = resultValue.pointID 125 | INNER JOIN 126 | corner ON corner.cornerID = point.cornerID 127 | INNER JOIN 128 | test ON test.testID = result.testID 129 | """ 130 | return pandas.io.sql.read_frame(query, self.conn).applymap(util.adexl_to_python) 131 | 132 | def get_point_corner_parameters(self, ): 133 | """Get all results as pandas dataframe""" 134 | 135 | query = """SELECT 136 | test.name as testname, resultValue.pointID, 137 | corner.name as cornername, 138 | result.name as resultname, resultValue.value 139 | FROM 140 | resultValue 141 | INNER JOIN 142 | result ON result.resultID = resultValue.resultID 143 | INNER JOIN 144 | point ON point.pointID = resultValue.pointID 145 | INNER JOIN 146 | corner ON corner.cornerID = point.cornerID 147 | INNER JOIN 148 | test ON test.testID = result.testID 149 | """ 150 | return pandas.io.sql.read_frame(query, self.conn).applymap(util.adexl_to_python) 151 | 152 | def get_result_names(self): 153 | query = """SELECT result.name 154 | FROM result""" 155 | return [row[0] for row in self.conn.execute(query).fetchall()] 156 | 157 | def get_parameter_names(self): 158 | query = """SELECT name 159 | FROM parameter""" 160 | return [row[0] for row in self.conn.execute(query).fetchall()] 161 | 162 | def get_results(self, *resultnames): 163 | ## If no parameters, select all columns 164 | if len(resultnames) == 0: 165 | resultnames = self.get_result_names() 166 | 167 | subqueries = ["""(SELECT value 168 | FROM resultValue 169 | INNER JOIN 170 | result ON result.resultID = resultValue.resultID 171 | INNER JOIN 172 | test ON test.testID = result.testID 173 | WHERE resultValue.pointID == point.pointID 174 | AND result.name = '%(resultname)s') 175 | AS '%(resultname)s'""" % {'resultname': resultname} 176 | for resultname in resultnames] 177 | select_columns = ", ".join(subqueries) 178 | 179 | quoted_result_names = ', '.join(["'%s'" % rn for rn in resultnames]) 180 | 181 | query = """SELECT 182 | point.pointID as pointID, 183 | %s 184 | FROM 185 | point 186 | """ % select_columns 187 | 188 | return pandas.io.sql.read_frame(query, self.conn).applymap(util.adexl_to_python) 189 | 190 | def get_parameter_values(self, *parameternames): 191 | ## If no parameters, select all columns 192 | if len(parameternames) == 0: 193 | parameternames = self.get_parameter_names() 194 | 195 | subqueries = ["""(SELECT value 196 | FROM parameterValue 197 | INNER JOIN 198 | parameter ON parameter.parameterID = parameterValue.parameterID 199 | WHERE parameterValue.pointID == point.pointID 200 | AND parameter.name = '%(parametername)s') 201 | AS '%(parametername)s'""" % {'parametername': parametername} 202 | for parametername in parameternames] 203 | select_columns = ", ".join(subqueries) 204 | 205 | query = """SELECT 206 | point.pointID as pointID, 207 | %s 208 | FROM 209 | point 210 | """ % select_columns 211 | 212 | return pandas.io.sql.read_frame(query, self.conn).applymap(util.adexl_to_python) 213 | 214 | 215 | def get_parameters(self, pointid): 216 | query = """SELECT 217 | parameter.name, parameterValue.value 218 | FROM 219 | parameterValue 220 | INNER JOIN 221 | parameter ON parameter.parameterID = parameterValue.parameterID 222 | WHERE 223 | parameterValue.pointID = %d""" % pointid 224 | return pandas.io.sql.read_frame(query, self.conn).applymap(util.adexl_to_python) 225 | 226 | 227 | if __name__ == '__main__': 228 | r = ADE_XL_Result(os.path.join(os.path.dirname(__file__), 'test', 'data', 'adexl')) 229 | 230 | test = r.tests[0] 231 | 232 | statedir = test.get_state_dir(r) 233 | 234 | history = r.history 235 | 236 | print "Tests:", [test.name for test in r.tests] 237 | print "History:", [he.name for he in r.history] 238 | 239 | resultdb = history[0].get_result_db(r) 240 | 241 | tables = resultdb.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall() 242 | 243 | print "Tables: %s" % tables 244 | 245 | query = """SELECT 246 | test.name, resultValue.pointID, result.name, resultValue.value 247 | FROM 248 | resultValue 249 | INNER JOIN 250 | result ON result.resultID = resultValue.resultID 251 | INNER JOIN 252 | test ON test.testID = result.testID 253 | """ 254 | 255 | for historyentry in r.history: 256 | print historyentry.get_parameters(1, r) 257 | print historyentry.get_all_results(r) 258 | 259 | -------------------------------------------------------------------------------- /notebooks/adexl class demo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "code", 12 | "collapsed": false, 13 | "input": [ 14 | "import cds.adexl as adexl\n", 15 | "\n", 16 | "datadir = \"/home/hjohansson/pycds/cds/test/data/adexl\"" 17 | ], 18 | "language": "python", 19 | "metadata": {}, 20 | "outputs": [], 21 | "prompt_number": 19 22 | }, 23 | { 24 | "cell_type": "code", 25 | "collapsed": false, 26 | "input": [ 27 | "adexl_result = adexl.ADE_XL_Result(datadir)" 28 | ], 29 | "language": "python", 30 | "metadata": {}, 31 | "outputs": [], 32 | "prompt_number": 20 33 | }, 34 | { 35 | "cell_type": "code", 36 | "collapsed": false, 37 | "input": [ 38 | "adexl_result.get_history_entry_names()" 39 | ], 40 | "language": "python", 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "metadata": {}, 45 | "output_type": "pyout", 46 | "prompt_number": 21, 47 | "text": [ 48 | "['Interactive.205',\n", 49 | " 'Interactive.206',\n", 50 | " 'Interactive.207',\n", 51 | " 'Interactive.208',\n", 52 | " 'Interactive.209',\n", 53 | " 'Interactive.210',\n", 54 | " 'Interactive.211',\n", 55 | " 'Interactive.212',\n", 56 | " 'Interactive.213',\n", 57 | " 'Interactive.214',\n", 58 | " 'Interactive.215',\n", 59 | " 'Interactive.216',\n", 60 | " 'Interactive.217',\n", 61 | " 'Interactive.218',\n", 62 | " 'Interactive.219']" 63 | ] 64 | } 65 | ], 66 | "prompt_number": 21 67 | }, 68 | { 69 | "cell_type": "code", 70 | "collapsed": false, 71 | "input": [ 72 | "h_entry = adexl_result.get_history_entry('Interactive.210')" 73 | ], 74 | "language": "python", 75 | "metadata": {}, 76 | "outputs": [], 77 | "prompt_number": 32 78 | }, 79 | { 80 | "cell_type": "code", 81 | "collapsed": false, 82 | "input": [ 83 | "h_entry.get_all_results(adexl_result)" 84 | ], 85 | "language": "python", 86 | "metadata": {}, 87 | "outputs": [ 88 | { 89 | "html": [ 90 | "
\n", 91 | "\n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | "
namepointIDnamevalue
0 psrr 1 PStoCM 20MHz -15.293499
1 psrr 1 PStoDM 20MHz-165.119020
2 psrr 1 PStoDM 40MHz-159.372130
3 psrr 1 PStoDM 10MHz-170.331518
4 psrr 1 PStoCM 40MHz -15.293499
5 psrr 1 PStoCM 10MHz -15.293499
\n", 146 | "
" 147 | ], 148 | "metadata": {}, 149 | "output_type": "pyout", 150 | "prompt_number": 33, 151 | "text": [ 152 | " name pointID name value\n", 153 | "0 psrr 1 PStoCM 20MHz -15.293499\n", 154 | "1 psrr 1 PStoDM 20MHz -165.119020\n", 155 | "2 psrr 1 PStoDM 40MHz -159.372130\n", 156 | "3 psrr 1 PStoDM 10MHz -170.331518\n", 157 | "4 psrr 1 PStoCM 40MHz -15.293499\n", 158 | "5 psrr 1 PStoCM 10MHz -15.293499" 159 | ] 160 | } 161 | ], 162 | "prompt_number": 33 163 | }, 164 | { 165 | "cell_type": "code", 166 | "collapsed": false, 167 | "input": [ 168 | "h_entry.get_parameters(1, adexl_result)" 169 | ], 170 | "language": "python", 171 | "metadata": {}, 172 | "outputs": [ 173 | { 174 | "html": [ 175 | "
\n", 176 | "\n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | "
namevalue
0 C 1p
1 Cload 100f
2 Ibias 25u
3 Rload 400k
4 Vcm 650m
5 Vcmdac 0.6
6 Vcmin 0.65
7 Vcmout 0.65
8 Vdd 1.35
9 amp 10m
10 amp1 10m
11 amp2 10m
12 bw 37
13 dac 0
14 fin 1M
15 fund 10M
16 fund1 32M
17 fund2 36M
18 gain 7
19 gain1 1
20 gain2 1
21 iac 0.005
22 idac 1u
23 idc 2.5m
24 iin 1u
25 iin_ac 0
26 iin_amp 0
27 iin_dc 0
28 rc_proc 1
\n", 332 | "
" 333 | ], 334 | "metadata": {}, 335 | "output_type": "pyout", 336 | "prompt_number": 35, 337 | "text": [ 338 | " name value\n", 339 | "0 C 1p\n", 340 | "1 Cload 100f\n", 341 | "2 Ibias 25u\n", 342 | "3 Rload 400k\n", 343 | "4 Vcm 650m\n", 344 | "5 Vcmdac 0.6\n", 345 | "6 Vcmin 0.65\n", 346 | "7 Vcmout 0.65\n", 347 | "8 Vdd 1.35\n", 348 | "9 amp 10m\n", 349 | "10 amp1 10m\n", 350 | "11 amp2 10m\n", 351 | "12 bw 37\n", 352 | "13 dac 0\n", 353 | "14 fin 1M\n", 354 | "15 fund 10M\n", 355 | "16 fund1 32M\n", 356 | "17 fund2 36M\n", 357 | "18 gain 7\n", 358 | "19 gain1 1\n", 359 | "20 gain2 1\n", 360 | "21 iac 0.005\n", 361 | "22 idac 1u\n", 362 | "23 idc 2.5m\n", 363 | "24 iin 1u\n", 364 | "25 iin_ac 0\n", 365 | "26 iin_amp 0\n", 366 | "27 iin_dc 0\n", 367 | "28 rc_proc 1" 368 | ] 369 | } 370 | ], 371 | "prompt_number": 35 372 | }, 373 | { 374 | "cell_type": "code", 375 | "collapsed": false, 376 | "input": [], 377 | "language": "python", 378 | "metadata": {}, 379 | "outputs": [] 380 | } 381 | ], 382 | "metadata": {} 383 | } 384 | ] 385 | } --------------------------------------------------------------------------------